binomial_coinflip_example.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. // Copyright Paul A. 2007, 2010
  2. // Copyright John Maddock 2006
  3. // Use, modification and distribution are subject to the
  4. // Boost Software License, Version 1.0.
  5. // (See accompanying file LICENSE_1_0.txt
  6. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. // Simple example of computing probabilities and quantiles for
  8. // a Bernoulli random variable representing the flipping of a coin.
  9. // http://mathworld.wolfram.com/CoinTossing.html
  10. // http://en.wikipedia.org/wiki/Bernoulli_trial
  11. // Weisstein, Eric W. "Dice." From MathWorld--A Wolfram Web Resource.
  12. // http://mathworld.wolfram.com/Dice.html
  13. // http://en.wikipedia.org/wiki/Bernoulli_distribution
  14. // http://mathworld.wolfram.com/BernoulliDistribution.html
  15. //
  16. // An idealized coin consists of a circular disk of zero thickness which,
  17. // when thrown in the air and allowed to fall, will rest with either side face up
  18. // ("heads" H or "tails" T) with equal probability. A coin is therefore a two-sided die.
  19. // Despite slight differences between the sides and nonzero thickness of actual coins,
  20. // the distribution of their tosses makes a good approximation to a p==1/2 Bernoulli distribution.
  21. //[binomial_coinflip_example1
  22. /*`An example of a [@http://en.wikipedia.org/wiki/Bernoulli_process Bernoulli process]
  23. is coin flipping.
  24. A variable in such a sequence may be called a Bernoulli variable.
  25. This example shows using the Binomial distribution to predict the probability
  26. of heads and tails when throwing a coin.
  27. The number of correct answers (say heads),
  28. X, is distributed as a binomial random variable
  29. with binomial distribution parameters number of trials (flips) n = 10 and probability (success_fraction) of getting a head p = 0.5 (a 'fair' coin).
  30. (Our coin is assumed fair, but we could easily change the success_fraction parameter p
  31. from 0.5 to some other value to simulate an unfair coin,
  32. say 0.6 for one with chewing gum on the tail,
  33. so it is more likely to fall tails down and heads up).
  34. First we need some includes and using statements to be able to use the binomial distribution, some std input and output, and get started:
  35. */
  36. #include <boost/math/distributions/binomial.hpp>
  37. using boost::math::binomial;
  38. #include <iostream>
  39. using std::cout; using std::endl; using std::left;
  40. #include <iomanip>
  41. using std::setw;
  42. int main()
  43. {
  44. cout << "Using Binomial distribution to predict how many heads and tails." << endl;
  45. try
  46. {
  47. /*`
  48. See note [link coinflip_eg_catch with the catch block]
  49. about why a try and catch block is always a good idea.
  50. First, construct a binomial distribution with parameters success_fraction
  51. 1/2, and how many flips.
  52. */
  53. const double success_fraction = 0.5; // = 50% = 1/2 for a 'fair' coin.
  54. int flips = 10;
  55. binomial flip(flips, success_fraction);
  56. cout.precision(4);
  57. /*`
  58. Then some examples of using Binomial moments (and echoing the parameters).
  59. */
  60. cout << "From " << flips << " one can expect to get on average "
  61. << mean(flip) << " heads (or tails)." << endl;
  62. cout << "Mode is " << mode(flip) << endl;
  63. cout << "Standard deviation is " << standard_deviation(flip) << endl;
  64. cout << "So about 2/3 will lie within 1 standard deviation and get between "
  65. << ceil(mean(flip) - standard_deviation(flip)) << " and "
  66. << floor(mean(flip) + standard_deviation(flip)) << " correct." << endl;
  67. cout << "Skewness is " << skewness(flip) << endl;
  68. // Skewness of binomial distributions is only zero (symmetrical)
  69. // if success_fraction is exactly one half,
  70. // for example, when flipping 'fair' coins.
  71. cout << "Skewness if success_fraction is " << flip.success_fraction()
  72. << " is " << skewness(flip) << endl << endl; // Expect zero for a 'fair' coin.
  73. /*`
  74. Now we show a variety of predictions on the probability of heads:
  75. */
  76. cout << "For " << flip.trials() << " coin flips: " << endl;
  77. cout << "Probability of getting no heads is " << pdf(flip, 0) << endl;
  78. cout << "Probability of getting at least one head is " << 1. - pdf(flip, 0) << endl;
  79. /*`
  80. When we want to calculate the probability for a range or values we can sum the PDF's:
  81. */
  82. cout << "Probability of getting 0 or 1 heads is "
  83. << pdf(flip, 0) + pdf(flip, 1) << endl; // sum of exactly == probabilities
  84. /*`
  85. Or we can use the cdf.
  86. */
  87. cout << "Probability of getting 0 or 1 (<= 1) heads is " << cdf(flip, 1) << endl;
  88. cout << "Probability of getting 9 or 10 heads is " << pdf(flip, 9) + pdf(flip, 10) << endl;
  89. /*`
  90. Note that using
  91. */
  92. cout << "Probability of getting 9 or 10 heads is " << 1. - cdf(flip, 8) << endl;
  93. /*`
  94. is less accurate than using the complement
  95. */
  96. cout << "Probability of getting 9 or 10 heads is " << cdf(complement(flip, 8)) << endl;
  97. /*`
  98. Since the subtraction may involve
  99. [@http://docs.sun.com/source/806-3568/ncg_goldberg.html cancellation error],
  100. where as `cdf(complement(flip, 8))`
  101. does not use such a subtraction internally, and so does not exhibit the problem.
  102. To get the probability for a range of heads, we can either add the pdfs for each number of heads
  103. */
  104. cout << "Probability of between 4 and 6 heads (4 or 5 or 6) is "
  105. // P(X == 4) + P(X == 5) + P(X == 6)
  106. << pdf(flip, 4) + pdf(flip, 5) + pdf(flip, 6) << endl;
  107. /*`
  108. But this is probably less efficient than using the cdf
  109. */
  110. cout << "Probability of between 4 and 6 heads (4 or 5 or 6) is "
  111. // P(X <= 6) - P(X <= 3) == P(X < 4)
  112. << cdf(flip, 6) - cdf(flip, 3) << endl;
  113. /*`
  114. Certainly for a bigger range like, 3 to 7
  115. */
  116. cout << "Probability of between 3 and 7 heads (3, 4, 5, 6 or 7) is "
  117. // P(X <= 7) - P(X <= 2) == P(X < 3)
  118. << cdf(flip, 7) - cdf(flip, 2) << endl;
  119. cout << endl;
  120. /*`
  121. Finally, print two tables of probability for the /exactly/ and /at least/ a number of heads.
  122. */
  123. // Print a table of probability for the exactly a number of heads.
  124. cout << "Probability of getting exactly (==) heads" << endl;
  125. for (int successes = 0; successes <= flips; successes++)
  126. { // Say success means getting a head (or equally success means getting a tail).
  127. double probability = pdf(flip, successes);
  128. cout << left << setw(2) << successes << " " << setw(10)
  129. << probability << " or 1 in " << 1. / probability
  130. << ", or " << probability * 100. << "%" << endl;
  131. } // for i
  132. cout << endl;
  133. // Tabulate the probability of getting between zero heads and 0 upto 10 heads.
  134. cout << "Probability of getting upto (<=) heads" << endl;
  135. for (int successes = 0; successes <= flips; successes++)
  136. { // Say success means getting a head
  137. // (equally success could mean getting a tail).
  138. double probability = cdf(flip, successes); // P(X <= heads)
  139. cout << setw(2) << successes << " " << setw(10) << left
  140. << probability << " or 1 in " << 1. / probability << ", or "
  141. << probability * 100. << "%"<< endl;
  142. } // for i
  143. /*`
  144. The last (0 to 10 heads) must, of course, be 100% probability.
  145. */
  146. double probability = 0.3;
  147. double q = quantile(flip, probability);
  148. std::cout << "Quantile (flip, " << probability << ") = " << q << std::endl; // Quantile (flip, 0.3) = 3
  149. probability = 0.6;
  150. q = quantile(flip, probability);
  151. std::cout << "Quantile (flip, " << probability << ") = " << q << std::endl; // Quantile (flip, 0.6) = 5
  152. }
  153. catch(const std::exception& e)
  154. {
  155. //
  156. /*`
  157. [#coinflip_eg_catch]
  158. It is always essential to include try & catch blocks because
  159. default policies are to throw exceptions on arguments that
  160. are out of domain or cause errors like numeric-overflow.
  161. Lacking try & catch blocks, the program will abort, whereas the
  162. message below from the thrown exception will give some helpful
  163. clues as to the cause of the problem.
  164. */
  165. std::cout <<
  166. "\n""Message from thrown exception was:\n " << e.what() << std::endl;
  167. }
  168. //] [binomial_coinflip_example1]
  169. return 0;
  170. } // int main()
  171. // Output:
  172. //[binomial_coinflip_example_output
  173. /*`
  174. [pre
  175. Using Binomial distribution to predict how many heads and tails.
  176. From 10 one can expect to get on average 5 heads (or tails).
  177. Mode is 5
  178. Standard deviation is 1.581
  179. So about 2/3 will lie within 1 standard deviation and get between 4 and 6 correct.
  180. Skewness is 0
  181. Skewness if success_fraction is 0.5 is 0
  182. For 10 coin flips:
  183. Probability of getting no heads is 0.0009766
  184. Probability of getting at least one head is 0.999
  185. Probability of getting 0 or 1 heads is 0.01074
  186. Probability of getting 0 or 1 (<= 1) heads is 0.01074
  187. Probability of getting 9 or 10 heads is 0.01074
  188. Probability of getting 9 or 10 heads is 0.01074
  189. Probability of getting 9 or 10 heads is 0.01074
  190. Probability of between 4 and 6 heads (4 or 5 or 6) is 0.6562
  191. Probability of between 4 and 6 heads (4 or 5 or 6) is 0.6563
  192. Probability of between 3 and 7 heads (3, 4, 5, 6 or 7) is 0.8906
  193. Probability of getting exactly (==) heads
  194. 0 0.0009766 or 1 in 1024, or 0.09766%
  195. 1 0.009766 or 1 in 102.4, or 0.9766%
  196. 2 0.04395 or 1 in 22.76, or 4.395%
  197. 3 0.1172 or 1 in 8.533, or 11.72%
  198. 4 0.2051 or 1 in 4.876, or 20.51%
  199. 5 0.2461 or 1 in 4.063, or 24.61%
  200. 6 0.2051 or 1 in 4.876, or 20.51%
  201. 7 0.1172 or 1 in 8.533, or 11.72%
  202. 8 0.04395 or 1 in 22.76, or 4.395%
  203. 9 0.009766 or 1 in 102.4, or 0.9766%
  204. 10 0.0009766 or 1 in 1024, or 0.09766%
  205. Probability of getting upto (<=) heads
  206. 0 0.0009766 or 1 in 1024, or 0.09766%
  207. 1 0.01074 or 1 in 93.09, or 1.074%
  208. 2 0.05469 or 1 in 18.29, or 5.469%
  209. 3 0.1719 or 1 in 5.818, or 17.19%
  210. 4 0.377 or 1 in 2.653, or 37.7%
  211. 5 0.623 or 1 in 1.605, or 62.3%
  212. 6 0.8281 or 1 in 1.208, or 82.81%
  213. 7 0.9453 or 1 in 1.058, or 94.53%
  214. 8 0.9893 or 1 in 1.011, or 98.93%
  215. 9 0.999 or 1 in 1.001, or 99.9%
  216. 10 1 or 1 in 1, or 100%
  217. ]
  218. */
  219. //][/binomial_coinflip_example_output]