mirror of
				https://github.com/saitohirga/WSJT-X.git
				synced 2025-10-31 04:50:34 -04:00 
			
		
		
		
	
		
			
	
	
		
			279 lines
		
	
	
		
			9.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			279 lines
		
	
	
		
			9.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|  | // distribution_construction.cpp
 | ||
|  | 
 | ||
|  | // Copyright Paul A. Bristow 2007, 2010, 2012.
 | ||
|  | 
 | ||
|  | // Use, modification and distribution are subject to the
 | ||
|  | // Boost Software License, Version 1.0.
 | ||
|  | // (See accompanying file LICENSE_1_0.txt
 | ||
|  | // or copy at http://www.boost.org/LICENSE_1_0.txt)
 | ||
|  | 
 | ||
|  | // Caution: this file contains Quickbook markup as well as code
 | ||
|  | // and comments, don't change any of the special comment markups!
 | ||
|  | 
 | ||
|  | #ifdef _MSC_VER
 | ||
|  | #  pragma warning (disable : 4996) // disable -D_SCL_SECURE_NO_WARNINGS C++ 'Checked Iterators'
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #include <iostream>
 | ||
|  | #include <exception>
 | ||
|  | 
 | ||
|  | //[distribution_construction_1
 | ||
|  | 
 | ||
|  | /*`
 | ||
|  | The structure of distributions is rather different from some other statistical libraries, | ||
|  | for example, those written in less object-oriented language like FORTRAN and C: | ||
|  | these provide a few arguments to each free function. | ||
|  | 
 | ||
|  | Boost.Math library provides each distribution as a template C++ class. | ||
|  | A distribution is constructed with a few arguments, and then | ||
|  | member and non-member functions are used to find values of the | ||
|  | distribution, often a function of a random variate. | ||
|  | 
 | ||
|  | For this demonstration, first we need some includes to access the | ||
|  | negative binomial distribution (and the binomial, beta and gamma distributions too). | ||
|  | 
 | ||
|  | To demonstrate the use with a high precision User-defined floating-point type | ||
|  | `cpp_dec_float` we also need an include from Boost.Multiprecision. | ||
|  | */ | ||
|  | 
 | ||
|  | #include <boost/math/distributions/negative_binomial.hpp> // for negative_binomial_distribution
 | ||
|  |   using boost::math::negative_binomial_distribution; // default type is double.
 | ||
|  |   using boost::math::negative_binomial; // typedef provides default type is double.
 | ||
|  | #include <boost/math/distributions/binomial.hpp> // for binomial_distribution.
 | ||
|  | #include <boost/math/distributions/beta.hpp> // for beta_distribution.
 | ||
|  | #include <boost/math/distributions/gamma.hpp> // for gamma_distribution.
 | ||
|  | #include <boost/math/distributions/normal.hpp> // for normal_distribution.
 | ||
|  | 
 | ||
|  | #include <boost/multiprecision/cpp_dec_float.hpp> // for cpp_dec_float_100
 | ||
|  | /*`
 | ||
|  | Several examples of constructing distributions follow: | ||
|  | */ | ||
|  | //] [/distribution_construction_1 end of Quickbook in C++ markup]
 | ||
|  | 
 | ||
|  | int main() | ||
|  | { | ||
|  |   try | ||
|  |   { | ||
|  | //[distribution_construction_2
 | ||
|  | /*`
 | ||
|  | First, a negative binomial distribution with 8 successes | ||
|  | and a success fraction 0.25, 25% or 1 in 4, is constructed like this: | ||
|  | */ | ||
|  |   boost::math::negative_binomial_distribution<double> mydist0(8., 0.25); | ||
|  |   /*`
 | ||
|  |   But this is inconveniently long, so we might be tempted to write | ||
|  |   */ | ||
|  |   using namespace boost::math; | ||
|  |   /*`
 | ||
|  |   but this might risk ambiguity with names in `std random` so | ||
|  |   [*much] better is explicit `using boost::math::` statements, for example: | ||
|  |   */ | ||
|  |   using boost::math::negative_binomial_distribution; | ||
|  |   /*`
 | ||
|  |   and we can still reduce typing. | ||
|  | 
 | ||
|  |   Since the vast majority of applications use will be using `double` precision, | ||
|  |   the template argument to the distribution (`RealType`) defaults | ||
|  |   to type `double`, so we can also write: | ||
|  |   */ | ||
|  | 
 | ||
|  |   negative_binomial_distribution<> mydist9(8., 0.25); // Uses default `RealType = double`.
 | ||
|  | 
 | ||
|  |   /*`
 | ||
|  |   But the name `negative_binomial_distribution` is still inconveniently long, | ||
|  |   so, for most distributions, a convenience `typedef` is provided, for example: | ||
|  | 
 | ||
|  |      typedef negative_binomial_distribution<double> negative_binomial; // Reserved name of type double.
 | ||
|  | 
 | ||
|  |   [caution | ||
|  |   This convenience typedef is [*not provided] if a clash would occur | ||
|  |   with the name of a function: currently only `beta` and `gamma` | ||
|  |   fall into this category. | ||
|  |   ] | ||
|  | 
 | ||
|  |   So, after a using statement, | ||
|  |   */ | ||
|  | 
 | ||
|  |   using boost::math::negative_binomial; | ||
|  | 
 | ||
|  |   /*`
 | ||
|  |   we have a convenient typedef to `negative_binomial_distribution<double>`: | ||
|  |   */ | ||
|  |   negative_binomial mydist(8., 0.25); | ||
|  | 
 | ||
|  |   /*`
 | ||
|  |   Some more examples using the convenience typedef: | ||
|  |   */ | ||
|  |   negative_binomial mydist10(5., 0.4); // Both arguments double.
 | ||
|  |   /*`
 | ||
|  |   And automatic conversion takes place, so you can use integers and floats: | ||
|  |   */ | ||
|  |   negative_binomial mydist11(5, 0.4); // Using provided typedef double, int and double arguments.
 | ||
|  |   /*`
 | ||
|  |   This is probably the most common usage. | ||
|  |   */ | ||
|  |   negative_binomial mydist12(5., 0.4F); // Double and float arguments.
 | ||
|  |   negative_binomial mydist13(5, 1); // Both arguments integer.
 | ||
|  | 
 | ||
|  |   /*`
 | ||
|  |   Similarly for most other distributions like the binomial. | ||
|  |   */ | ||
|  |   binomial mybinomial(1, 0.5); // is more concise than
 | ||
|  |   binomial_distribution<> mybinomd1(1, 0.5); | ||
|  | 
 | ||
|  |   /*`
 | ||
|  |   For cases when the typdef distribution name would clash with a math special function | ||
|  |   (currently only beta and gamma) | ||
|  |   the typedef is deliberately not provided, and the longer version of the name | ||
|  |   must be used.  For example do not use: | ||
|  | 
 | ||
|  |      using boost::math::beta; | ||
|  |      beta mybetad0(1, 0.5); // Error beta is a math FUNCTION!
 | ||
|  | 
 | ||
|  |   Which produces the error messages: | ||
|  | 
 | ||
|  |   [pre | ||
|  |   error C2146: syntax error : missing ';' before identifier 'mybetad0' | ||
|  |   warning C4551: function call missing argument list | ||
|  |   error C3861: 'mybetad0': identifier not found | ||
|  |   ] | ||
|  | 
 | ||
|  |   Instead you should use: | ||
|  |   */ | ||
|  |   using boost::math::beta_distribution; | ||
|  |   beta_distribution<> mybetad1(1, 0.5); | ||
|  |   /*`
 | ||
|  |   or for the gamma distribution: | ||
|  |   */ | ||
|  |   gamma_distribution<> mygammad1(1, 0.5); | ||
|  | 
 | ||
|  |   /*`
 | ||
|  |   We can, of course, still provide the type explicitly thus: | ||
|  |   */ | ||
|  | 
 | ||
|  |   // Explicit double precision:  both arguments are double:
 | ||
|  |   negative_binomial_distribution<double>        mydist1(8., 0.25); | ||
|  | 
 | ||
|  |   // Explicit float precision, double arguments are truncated to float:
 | ||
|  |   negative_binomial_distribution<float>         mydist2(8., 0.25); | ||
|  | 
 | ||
|  |   // Explicit float precision, integer & double arguments converted to float:
 | ||
|  |   negative_binomial_distribution<float>         mydist3(8, 0.25); | ||
|  | 
 | ||
|  |   // Explicit float precision, float arguments, so no conversion:
 | ||
|  |   negative_binomial_distribution<float>         mydist4(8.F, 0.25F); | ||
|  | 
 | ||
|  |   // Explicit float precision, integer arguments promoted to float.
 | ||
|  |   negative_binomial_distribution<float>         mydist5(8, 1); | ||
|  | 
 | ||
|  |   // Explicit double precision:
 | ||
|  |   negative_binomial_distribution<double>        mydist6(8., 0.25); | ||
|  | 
 | ||
|  |   // Explicit long double precision:
 | ||
|  |   negative_binomial_distribution<long double>   mydist7(8., 0.25); | ||
|  | 
 | ||
|  |   /*`
 | ||
|  |   And you can use your own RealType, | ||
|  |   for example, `boost::math::cpp_dec_float_50` (an arbitrary 50 decimal digits precision type), | ||
|  |   then we can write: | ||
|  |   */ | ||
|  |   using namespace boost::multiprecision; | ||
|  | 
 | ||
|  |   negative_binomial_distribution<cpp_dec_float_50>  mydist8(8, 0.25); | ||
|  |   // `integer` arguments are promoted to your RealType exactly, but
 | ||
|  |   // `double` argument are converted to RealType,
 | ||
|  |   // possibly losing precision, so don't write:
 | ||
|  | 
 | ||
|  |   negative_binomial_distribution<cpp_dec_float_50>  mydist20(8, 0.23456789012345678901234567890); | ||
|  |  // to avoid truncation of second parameter to `0.2345678901234567`.
 | ||
|  | 
 | ||
|  |   negative_binomial_distribution<cpp_dec_float_50>  mydist21(8, cpp_dec_float_50("0.23456789012345678901234567890") ); | ||
|  | 
 | ||
|  |   // Ensure that all potentially significant digits are shown.
 | ||
|  |   std::cout.precision(std::numeric_limits<cpp_dec_float_50>::digits10); | ||
|  |   cpp_dec_float_50 x("1.23456789012345678901234567890"); | ||
|  |   std::cout << pdf(mydist8, x) << std::endl; | ||
|  | /*` showing  0.00012630010495970320103876754721976419438231705359935
 | ||
|  | 
 | ||
|  | [warning When using multiprecision, it is all too easy to get accidental truncation!] | ||
|  | 
 | ||
|  | For example, if you write | ||
|  | */ | ||
|  |   std::cout << pdf(mydist8, 1.23456789012345678901234567890) << std::endl; | ||
|  | /*`
 | ||
|  | showing  0.00012630010495970318465064569310967179576805651692929, | ||
|  | which is wrong at about the 17th decimal digit! | ||
|  | 
 | ||
|  | This is because the value provided is truncated to a `double`, effectively | ||
|  |   `double x = 1.23456789012345678901234567890;` | ||
|  | 
 | ||
|  | Then the now `double x` is passed to function `pdf`, | ||
|  | and this truncated `double` value is finally promoted to `cpp_dec_float_50`. | ||
|  | 
 | ||
|  | Another way of quietly getting the wrong answer is to write: | ||
|  | */ | ||
|  |   std::cout << pdf(mydist8, cpp_dec_float_50(1.23456789012345678901234567890)) << std::endl; | ||
|  | /*`
 | ||
|  | A correct way from a multi-digit string value is | ||
|  | */ | ||
|  |   std::cout << pdf(mydist8, cpp_dec_float_50("1.23456789012345678901234567890")) << std::endl; | ||
|  | /*`
 | ||
|  | 
 | ||
|  | [tip Getting about 17 decimal digits followed by many zeros is often a sign of accidental truncation.] | ||
|  | */ | ||
|  | 
 | ||
|  | /*`
 | ||
|  | [h4 Default arguments to distribution constructors.] | ||
|  | 
 | ||
|  | Note that default constructor arguments are only provided for some distributions. | ||
|  | So if you wrongly assume a default argument, you will get an error message, for example: | ||
|  | 
 | ||
|  |    negative_binomial_distribution<> mydist8; | ||
|  | 
 | ||
|  | [pre error C2512 no appropriate default constructor available.] | ||
|  | 
 | ||
|  | No default constructors are provided for the `negative binomial` distribution, | ||
|  | because it is difficult to chose any sensible default values for this distribution. | ||
|  | 
 | ||
|  | For other distributions, like the normal distribution, | ||
|  | it is obviously very useful to provide 'standard' | ||
|  | defaults for the mean (zero) and standard deviation (unity) thus: | ||
|  | 
 | ||
|  |     normal_distribution(RealType mean = 0, RealType sd = 1); | ||
|  | 
 | ||
|  | So in this case we can write: | ||
|  | */ | ||
|  |   using boost::math::normal; | ||
|  | 
 | ||
|  |   normal norm1;       // Standard normal distribution.
 | ||
|  |   normal norm2(2);    // Mean = 2, std deviation = 1.
 | ||
|  |   normal norm3(2, 3); // Mean = 2, std deviation = 3.
 | ||
|  | 
 | ||
|  |   } | ||
|  |   catch(std::exception &ex) | ||
|  |   { | ||
|  |     std::cout << ex.what() << std::endl; | ||
|  |   } | ||
|  | 
 | ||
|  |   return 0; | ||
|  | }  // int main()
 | ||
|  | 
 | ||
|  | /*`There is no useful output from this demonstration program, of course. */ | ||
|  | 
 | ||
|  | //] [/end of distribution_construction_2]
 | ||
|  | 
 | ||
|  | /*
 | ||
|  | //[distribution_construction_output
 | ||
|  | 
 | ||
|  |   0.00012630010495970320103876754721976419438231705359935 | ||
|  |   0.00012630010495970318465064569310967179576805651692929 | ||
|  |   0.00012630010495970318465064569310967179576805651692929 | ||
|  |   0.00012630010495970320103876754721976419438231705359935 | ||
|  | 
 | ||
|  | //] [/distribution_construction_output]
 | ||
|  | 
 | ||
|  | */ | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 |