test_factorials.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. // Copyright John Maddock 2006.
  2. // Use, modification and distribution are subject to the
  3. // Boost Software License, Version 1.0. (See accompanying file
  4. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifdef _MSC_VER
  6. # pragma warning(disable: 4127) // conditional expression is constant.
  7. # pragma warning(disable: 4245) // int/unsigned int conversion
  8. #endif
  9. // Return infinities not exceptions:
  10. #define BOOST_MATH_OVERFLOW_ERROR_POLICY ignore_error
  11. #include <boost/cstdfloat.hpp>
  12. #define BOOST_TEST_MAIN
  13. #include <boost/test/unit_test.hpp>
  14. #include <boost/test/tools/floating_point_comparison.hpp>
  15. #include <boost/math/special_functions/factorials.hpp>
  16. #include <boost/math/special_functions/gamma.hpp>
  17. #include <boost/math/tools/stats.hpp>
  18. #include <boost/math/tools/test.hpp>
  19. #include <iostream>
  20. using std::cout;
  21. using std::endl;
  22. template <class T>
  23. T naive_falling_factorial(T x, unsigned n)
  24. {
  25. if(n == 0)
  26. return 1;
  27. T result = x;
  28. while(--n)
  29. {
  30. x -= 1;
  31. result *= x;
  32. }
  33. return result;
  34. }
  35. template <class T>
  36. void test_spots(T)
  37. {
  38. //
  39. // Basic sanity checks.
  40. //
  41. T tolerance = boost::math::tools::epsilon<T>() * 100 * 2; // 2 eps as a percent.
  42. BOOST_CHECK_CLOSE(
  43. ::boost::math::factorial<T>(0),
  44. static_cast<T>(1), tolerance);
  45. BOOST_CHECK_CLOSE(
  46. ::boost::math::factorial<T>(1),
  47. static_cast<T>(1), tolerance);
  48. BOOST_CHECK_CLOSE(
  49. ::boost::math::factorial<T>(10),
  50. static_cast<T>(3628800L), tolerance);
  51. BOOST_CHECK_CLOSE(
  52. ::boost::math::unchecked_factorial<T>(0),
  53. static_cast<T>(1), tolerance);
  54. BOOST_CHECK_CLOSE(
  55. ::boost::math::unchecked_factorial<T>(1),
  56. static_cast<T>(1), tolerance);
  57. BOOST_CHECK_CLOSE(
  58. ::boost::math::unchecked_factorial<T>(10),
  59. static_cast<T>(3628800L), tolerance);
  60. //
  61. // Try some double factorials:
  62. //
  63. BOOST_CHECK_CLOSE(
  64. ::boost::math::double_factorial<T>(0),
  65. static_cast<T>(1), tolerance);
  66. BOOST_CHECK_CLOSE(
  67. ::boost::math::double_factorial<T>(1),
  68. static_cast<T>(1), tolerance);
  69. BOOST_CHECK_CLOSE(
  70. ::boost::math::double_factorial<T>(2),
  71. static_cast<T>(2), tolerance);
  72. BOOST_CHECK_CLOSE(
  73. ::boost::math::double_factorial<T>(5),
  74. static_cast<T>(15), tolerance);
  75. BOOST_CHECK_CLOSE(
  76. ::boost::math::double_factorial<T>(10),
  77. static_cast<T>(3840), tolerance);
  78. BOOST_CHECK_CLOSE(
  79. ::boost::math::double_factorial<T>(19),
  80. static_cast<T>(6.547290750e8Q), tolerance);
  81. BOOST_CHECK_CLOSE(
  82. ::boost::math::double_factorial<T>(24),
  83. static_cast<T>(1.961990553600000e12Q), tolerance);
  84. BOOST_CHECK_CLOSE(
  85. ::boost::math::double_factorial<T>(33),
  86. static_cast<T>(6.33265987076285062500000e18Q), tolerance);
  87. BOOST_CHECK_CLOSE(
  88. ::boost::math::double_factorial<T>(42),
  89. static_cast<T>(1.0714547155728479551488000000e26Q), tolerance);
  90. BOOST_CHECK_CLOSE(
  91. ::boost::math::double_factorial<T>(47),
  92. static_cast<T>(1.19256819277443412353990764062500000e30Q), tolerance);
  93. if((std::numeric_limits<T>::has_infinity) && (std::numeric_limits<T>::max_exponent <= 1024))
  94. {
  95. BOOST_CHECK_EQUAL(
  96. ::boost::math::double_factorial<T>(320),
  97. std::numeric_limits<T>::infinity());
  98. BOOST_CHECK_EQUAL(
  99. ::boost::math::double_factorial<T>(301),
  100. std::numeric_limits<T>::infinity());
  101. }
  102. //
  103. // Rising factorials:
  104. //
  105. tolerance = boost::math::tools::epsilon<T>() * 100 * 20; // 20 eps as a percent.
  106. if(std::numeric_limits<T>::is_specialized == 0)
  107. tolerance *= 5; // higher error rates without Lanczos support
  108. BOOST_CHECK_CLOSE(
  109. ::boost::math::rising_factorial(static_cast<T>(3), 4),
  110. static_cast<T>(360), tolerance);
  111. BOOST_CHECK_CLOSE(
  112. ::boost::math::rising_factorial(static_cast<T>(7), -4),
  113. static_cast<T>(0.00277777777777777777777777777777777777777777777777777777777778Q), tolerance);
  114. BOOST_CHECK_CLOSE(
  115. ::boost::math::rising_factorial(static_cast<T>(120.5f), 8),
  116. static_cast<T>(5.58187566784927180664062500e16Q), tolerance);
  117. BOOST_CHECK_CLOSE(
  118. ::boost::math::rising_factorial(static_cast<T>(120.5f), -4),
  119. static_cast<T>(5.15881498170104646868208445266116850161120996179812063177241e-9Q), tolerance);
  120. BOOST_CHECK_CLOSE(
  121. ::boost::math::rising_factorial(static_cast<T>(5000.25f), 8),
  122. static_cast<T>(3.92974581976666067544013393509103775024414062500000e29Q), tolerance);
  123. BOOST_CHECK_CLOSE(
  124. ::boost::math::rising_factorial(static_cast<T>(5000.25f), -7),
  125. static_cast<T>(1.28674092710208810281923019294164707555099052561945725535047e-26Q), tolerance);
  126. BOOST_CHECK_CLOSE(
  127. ::boost::math::rising_factorial(static_cast<T>(30.25), 21),
  128. static_cast<T>(3.93286957998925490693364184100209193343633629069699964020401e33Q), tolerance * 2);
  129. BOOST_CHECK_CLOSE(
  130. ::boost::math::rising_factorial(static_cast<T>(30.25), -21),
  131. static_cast<T>(3.35010902064291983728782493133164809108646650368560147505884e-27Q), tolerance);
  132. BOOST_CHECK_CLOSE(
  133. ::boost::math::rising_factorial(static_cast<T>(-30.25), 21),
  134. static_cast<T>(-9.76168312768123676601980433377916854311706629232503473758698e26Q), tolerance * 2);
  135. BOOST_CHECK_CLOSE(
  136. ::boost::math::rising_factorial(static_cast<T>(-30.25), -21),
  137. static_cast<T>(-1.50079704000923674318934280259377728203516775215430875839823e-34Q), 2 * tolerance);
  138. BOOST_CHECK_CLOSE(
  139. ::boost::math::rising_factorial(static_cast<T>(-30.25), 5),
  140. static_cast<T>(-1.78799177197265625000000e7Q), tolerance);
  141. BOOST_CHECK_CLOSE(
  142. ::boost::math::rising_factorial(static_cast<T>(-30.25), -5),
  143. static_cast<T>(-2.47177487004482195012362027432181137141899692171397467859150e-8Q), tolerance);
  144. BOOST_CHECK_CLOSE(
  145. ::boost::math::rising_factorial(static_cast<T>(-30.25), 6),
  146. static_cast<T>(4.5146792242309570312500000e8Q), tolerance);
  147. BOOST_CHECK_CLOSE(
  148. ::boost::math::rising_factorial(static_cast<T>(-30.25), -6),
  149. static_cast<T>(6.81868929667537089689274558433603136943171564610751635473516e-10Q), tolerance);
  150. BOOST_CHECK_CLOSE(
  151. ::boost::math::rising_factorial(static_cast<T>(-3), 6),
  152. static_cast<T>(0), tolerance);
  153. BOOST_CHECK_CLOSE(
  154. ::boost::math::rising_factorial(static_cast<T>(-3.25), 6),
  155. static_cast<T>(2.99926757812500Q), tolerance);
  156. BOOST_CHECK_CLOSE(
  157. ::boost::math::rising_factorial(static_cast<T>(-5.25), 6),
  158. static_cast<T>(50.987548828125000000000000Q), tolerance);
  159. BOOST_CHECK_CLOSE(
  160. ::boost::math::rising_factorial(static_cast<T>(-5.25), 13),
  161. static_cast<T>(127230.91046623885631561279296875000Q), tolerance);
  162. BOOST_CHECK_CLOSE(
  163. ::boost::math::rising_factorial(static_cast<T>(-3.25), -6),
  164. static_cast<T>(0.0000129609865918182348202632178291407500332449622510474437452125Q), tolerance);
  165. BOOST_CHECK_CLOSE(
  166. ::boost::math::rising_factorial(static_cast<T>(-5.25), -6),
  167. static_cast<T>(2.50789821857946332294524052303699065683926911849535903362649e-6Q), tolerance);
  168. BOOST_CHECK_CLOSE(
  169. ::boost::math::rising_factorial(static_cast<T>(-5.25), -13),
  170. static_cast<T>(-1.38984989447269128946284683518361786049649013886981662962096e-14Q), tolerance);
  171. //
  172. // Falling factorials:
  173. //
  174. BOOST_CHECK_CLOSE(
  175. ::boost::math::falling_factorial(static_cast<T>(30.25), 0),
  176. static_cast<T>(naive_falling_factorial(30.25Q, 0)),
  177. tolerance);
  178. BOOST_CHECK_CLOSE(
  179. ::boost::math::falling_factorial(static_cast<T>(30.25), 1),
  180. static_cast<T>(naive_falling_factorial(30.25Q, 1)),
  181. tolerance);
  182. BOOST_CHECK_CLOSE(
  183. ::boost::math::falling_factorial(static_cast<T>(30.25), 2),
  184. static_cast<T>(naive_falling_factorial(30.25Q, 2)),
  185. tolerance);
  186. BOOST_CHECK_CLOSE(
  187. ::boost::math::falling_factorial(static_cast<T>(30.25), 5),
  188. static_cast<T>(naive_falling_factorial(30.25Q, 5)),
  189. tolerance);
  190. BOOST_CHECK_CLOSE(
  191. ::boost::math::falling_factorial(static_cast<T>(30.25), 22),
  192. static_cast<T>(naive_falling_factorial(30.25Q, 22)),
  193. tolerance);
  194. BOOST_CHECK_CLOSE(
  195. ::boost::math::falling_factorial(static_cast<T>(100.5), 6),
  196. static_cast<T>(naive_falling_factorial(100.5Q, 6)),
  197. tolerance);
  198. BOOST_CHECK_CLOSE(
  199. ::boost::math::falling_factorial(static_cast<T>(30.75), 30),
  200. static_cast<T>(naive_falling_factorial(30.75Q, 30)),
  201. tolerance * 3);
  202. if(boost::math::policies::digits<T, boost::math::policies::policy<> >() > 50)
  203. {
  204. BOOST_CHECK_CLOSE(
  205. ::boost::math::falling_factorial(static_cast<T>(-30.75Q), 30),
  206. static_cast<T>(naive_falling_factorial(-30.75Q, 30)),
  207. tolerance * 3);
  208. BOOST_CHECK_CLOSE(
  209. ::boost::math::falling_factorial(static_cast<T>(-30.75Q), 27),
  210. static_cast<T>(naive_falling_factorial(-30.75Q, 27)),
  211. tolerance * 3);
  212. }
  213. BOOST_CHECK_CLOSE(
  214. ::boost::math::falling_factorial(static_cast<T>(-12.0), 6),
  215. static_cast<T>(naive_falling_factorial(-12.0Q, 6)),
  216. tolerance);
  217. BOOST_CHECK_CLOSE(
  218. ::boost::math::falling_factorial(static_cast<T>(-12), 5),
  219. static_cast<T>(naive_falling_factorial(-12.0Q, 5)),
  220. tolerance);
  221. BOOST_CHECK_CLOSE(
  222. ::boost::math::falling_factorial(static_cast<T>(-3.0), 6),
  223. static_cast<T>(naive_falling_factorial(-3.0Q, 6)),
  224. tolerance);
  225. BOOST_CHECK_CLOSE(
  226. ::boost::math::falling_factorial(static_cast<T>(-3), 5),
  227. static_cast<T>(naive_falling_factorial(-3.0Q, 5)),
  228. tolerance);
  229. BOOST_CHECK_CLOSE(
  230. ::boost::math::falling_factorial(static_cast<T>(3.0), 6),
  231. static_cast<T>(naive_falling_factorial(3.0Q, 6)),
  232. tolerance);
  233. BOOST_CHECK_CLOSE(
  234. ::boost::math::falling_factorial(static_cast<T>(3), 5),
  235. static_cast<T>(naive_falling_factorial(3.0Q, 5)),
  236. tolerance);
  237. BOOST_CHECK_CLOSE(
  238. ::boost::math::falling_factorial(static_cast<T>(3.25), 4),
  239. static_cast<T>(naive_falling_factorial(3.25Q, 4)),
  240. tolerance);
  241. BOOST_CHECK_CLOSE(
  242. ::boost::math::falling_factorial(static_cast<T>(3.25), 5),
  243. static_cast<T>(naive_falling_factorial(3.25Q, 5)),
  244. tolerance);
  245. BOOST_CHECK_CLOSE(
  246. ::boost::math::falling_factorial(static_cast<T>(3.25), 6),
  247. static_cast<T>(naive_falling_factorial(3.25Q, 6)),
  248. tolerance);
  249. BOOST_CHECK_CLOSE(
  250. ::boost::math::falling_factorial(static_cast<T>(3.25), 7),
  251. static_cast<T>(naive_falling_factorial(3.25Q, 7)),
  252. tolerance);
  253. BOOST_CHECK_CLOSE(
  254. ::boost::math::falling_factorial(static_cast<T>(8.25), 12),
  255. static_cast<T>(naive_falling_factorial(8.25Q, 12)),
  256. tolerance);
  257. tolerance = boost::math::tools::epsilon<T>() * 100 * 20; // 20 eps as a percent.
  258. unsigned i = boost::math::max_factorial<T>::value;
  259. if((boost::is_floating_point<T>::value) && (sizeof(T) <= sizeof(double)))
  260. {
  261. // Without Lanczos support, tgamma isn't accurate enough for this test:
  262. BOOST_CHECK_CLOSE(
  263. ::boost::math::unchecked_factorial<T>(i),
  264. boost::math::tgamma(static_cast<T>(i+1)), tolerance);
  265. }
  266. i += 10;
  267. while(boost::math::lgamma(static_cast<T>(i+1)) < boost::math::tools::log_max_value<T>())
  268. {
  269. BOOST_CHECK_CLOSE(
  270. ::boost::math::factorial<T>(i),
  271. boost::math::tgamma(static_cast<T>(i+1)), tolerance);
  272. i += 10;
  273. }
  274. } // template <class T> void test_spots(T)
  275. BOOST_AUTO_TEST_CASE( test_main )
  276. {
  277. BOOST_MATH_CONTROL_FP;
  278. test_spots(0.0Q);
  279. cout << "max factorial for __float128" << boost::math::max_factorial<boost::floatmax_t>::value << endl;
  280. }