test_factorials.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  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. #include <pch.hpp>
  6. #ifdef _MSC_VER
  7. # pragma warning(disable: 4127) // conditional expression is constant.
  8. # pragma warning(disable: 4245) // int/unsigned int conversion
  9. #endif
  10. // Return infinities not exceptions:
  11. #define BOOST_MATH_OVERFLOW_ERROR_POLICY ignore_error
  12. #include <boost/math/concepts/real_concept.hpp>
  13. #define BOOST_TEST_MAIN
  14. #include <boost/test/unit_test.hpp>
  15. #include <boost/test/tools/floating_point_comparison.hpp>
  16. #include <boost/math/special_functions/factorials.hpp>
  17. #include <boost/math/special_functions/gamma.hpp>
  18. #include <boost/math/tools/stats.hpp>
  19. #include <boost/math/tools/test.hpp>
  20. #include <iostream>
  21. #include <iomanip>
  22. using std::cout;
  23. using std::endl;
  24. template <class T>
  25. T naive_falling_factorial(T x, unsigned n)
  26. {
  27. if(n == 0)
  28. return 1;
  29. T result = x;
  30. while(--n)
  31. {
  32. x -= 1;
  33. result *= x;
  34. }
  35. return result;
  36. }
  37. template <class T>
  38. void test_spots(T)
  39. {
  40. //
  41. // Basic sanity checks.
  42. //
  43. T tolerance = boost::math::tools::epsilon<T>() * 100 * 2; // 2 eps as a percent.
  44. BOOST_CHECK_CLOSE(
  45. ::boost::math::factorial<T>(0),
  46. static_cast<T>(1), tolerance);
  47. BOOST_CHECK_CLOSE(
  48. ::boost::math::factorial<T>(1),
  49. static_cast<T>(1), tolerance);
  50. BOOST_CHECK_CLOSE(
  51. ::boost::math::factorial<T>(10),
  52. static_cast<T>(3628800L), tolerance);
  53. BOOST_CHECK_CLOSE(
  54. ::boost::math::unchecked_factorial<T>(0),
  55. static_cast<T>(1), tolerance);
  56. BOOST_CHECK_CLOSE(
  57. ::boost::math::unchecked_factorial<T>(1),
  58. static_cast<T>(1), tolerance);
  59. BOOST_CHECK_CLOSE(
  60. ::boost::math::unchecked_factorial<T>(10),
  61. static_cast<T>(3628800L), tolerance);
  62. //
  63. // Try some double factorials:
  64. //
  65. BOOST_CHECK_CLOSE(
  66. ::boost::math::double_factorial<T>(0),
  67. static_cast<T>(1), tolerance);
  68. BOOST_CHECK_CLOSE(
  69. ::boost::math::double_factorial<T>(1),
  70. static_cast<T>(1), tolerance);
  71. BOOST_CHECK_CLOSE(
  72. ::boost::math::double_factorial<T>(2),
  73. static_cast<T>(2), tolerance);
  74. BOOST_CHECK_CLOSE(
  75. ::boost::math::double_factorial<T>(5),
  76. static_cast<T>(15), tolerance);
  77. BOOST_CHECK_CLOSE(
  78. ::boost::math::double_factorial<T>(10),
  79. static_cast<T>(3840), tolerance);
  80. BOOST_CHECK_CLOSE(
  81. ::boost::math::double_factorial<T>(19),
  82. static_cast<T>(6.547290750e8L), tolerance);
  83. BOOST_CHECK_CLOSE(
  84. ::boost::math::double_factorial<T>(24),
  85. static_cast<T>(1.961990553600000e12L), tolerance);
  86. BOOST_CHECK_CLOSE(
  87. ::boost::math::double_factorial<T>(33),
  88. static_cast<T>(6.33265987076285062500000e18L), tolerance);
  89. BOOST_CHECK_CLOSE(
  90. ::boost::math::double_factorial<T>(42),
  91. static_cast<T>(1.0714547155728479551488000000e26L), tolerance);
  92. BOOST_CHECK_CLOSE(
  93. ::boost::math::double_factorial<T>(47),
  94. static_cast<T>(1.19256819277443412353990764062500000e30L), tolerance);
  95. if((std::numeric_limits<T>::has_infinity) && (std::numeric_limits<T>::max_exponent <= 1024))
  96. {
  97. BOOST_CHECK_EQUAL(
  98. ::boost::math::double_factorial<T>(320),
  99. std::numeric_limits<T>::infinity());
  100. BOOST_CHECK_EQUAL(
  101. ::boost::math::double_factorial<T>(301),
  102. std::numeric_limits<T>::infinity());
  103. }
  104. //
  105. // Rising factorials:
  106. //
  107. tolerance = boost::math::tools::epsilon<T>() * 100 * 20; // 20 eps as a percent.
  108. if(std::numeric_limits<T>::is_specialized == 0)
  109. tolerance *= 5; // higher error rates without Lanczos support
  110. BOOST_CHECK_CLOSE(
  111. ::boost::math::rising_factorial(static_cast<T>(3), 4),
  112. static_cast<T>(360), tolerance);
  113. BOOST_CHECK_CLOSE(
  114. ::boost::math::rising_factorial(static_cast<T>(7), -4),
  115. static_cast<T>(0.00277777777777777777777777777777777777777777777777777777777778L), tolerance);
  116. BOOST_CHECK_CLOSE(
  117. ::boost::math::rising_factorial(static_cast<T>(120.5f), 8),
  118. static_cast<T>(5.58187566784927180664062500e16L), tolerance);
  119. BOOST_CHECK_CLOSE(
  120. ::boost::math::rising_factorial(static_cast<T>(120.5f), -4),
  121. static_cast<T>(5.15881498170104646868208445266116850161120996179812063177241e-9L), tolerance);
  122. BOOST_CHECK_CLOSE(
  123. ::boost::math::rising_factorial(static_cast<T>(5000.25f), 8),
  124. static_cast<T>(3.92974581976666067544013393509103775024414062500000e29L), tolerance);
  125. BOOST_CHECK_CLOSE(
  126. ::boost::math::rising_factorial(static_cast<T>(5000.25f), -7),
  127. static_cast<T>(1.28674092710208810281923019294164707555099052561945725535047e-26L), tolerance);
  128. BOOST_CHECK_CLOSE(
  129. ::boost::math::rising_factorial(static_cast<T>(30.25), 21),
  130. static_cast<T>(3.93286957998925490693364184100209193343633629069699964020401e33L), tolerance * 2);
  131. BOOST_CHECK_CLOSE(
  132. ::boost::math::rising_factorial(static_cast<T>(30.25), -21),
  133. static_cast<T>(3.35010902064291983728782493133164809108646650368560147505884e-27L), tolerance);
  134. BOOST_CHECK_CLOSE(
  135. ::boost::math::rising_factorial(static_cast<T>(-30.25), 21),
  136. static_cast<T>(-9.76168312768123676601980433377916854311706629232503473758698e26L), tolerance * 2);
  137. BOOST_CHECK_CLOSE(
  138. ::boost::math::rising_factorial(static_cast<T>(-30.25), -21),
  139. static_cast<T>(-1.50079704000923674318934280259377728203516775215430875839823e-34L), 2 * tolerance);
  140. BOOST_CHECK_CLOSE(
  141. ::boost::math::rising_factorial(static_cast<T>(-30.25), 5),
  142. static_cast<T>(-1.78799177197265625000000e7L), tolerance);
  143. BOOST_CHECK_CLOSE(
  144. ::boost::math::rising_factorial(static_cast<T>(-30.25), -5),
  145. static_cast<T>(-2.47177487004482195012362027432181137141899692171397467859150e-8L), tolerance);
  146. BOOST_CHECK_CLOSE(
  147. ::boost::math::rising_factorial(static_cast<T>(-30.25), 6),
  148. static_cast<T>(4.5146792242309570312500000e8L), tolerance);
  149. BOOST_CHECK_CLOSE(
  150. ::boost::math::rising_factorial(static_cast<T>(-30.25), -6),
  151. static_cast<T>(6.81868929667537089689274558433603136943171564610751635473516e-10L), tolerance);
  152. BOOST_CHECK_CLOSE(
  153. ::boost::math::rising_factorial(static_cast<T>(-3), 6),
  154. static_cast<T>(0), tolerance);
  155. BOOST_CHECK_CLOSE(
  156. ::boost::math::rising_factorial(static_cast<T>(-3.25), 6),
  157. static_cast<T>(2.99926757812500L), tolerance);
  158. BOOST_CHECK_CLOSE(
  159. ::boost::math::rising_factorial(static_cast<T>(-5.25), 6),
  160. static_cast<T>(50.987548828125000000000000L), tolerance);
  161. BOOST_CHECK_CLOSE(
  162. ::boost::math::rising_factorial(static_cast<T>(-5.25), 13),
  163. static_cast<T>(127230.91046623885631561279296875000L), tolerance);
  164. BOOST_CHECK_CLOSE(
  165. ::boost::math::rising_factorial(static_cast<T>(-3.25), -6),
  166. static_cast<T>(0.0000129609865918182348202632178291407500332449622510474437452125L), tolerance);
  167. BOOST_CHECK_CLOSE(
  168. ::boost::math::rising_factorial(static_cast<T>(-5.25), -6),
  169. static_cast<T>(2.50789821857946332294524052303699065683926911849535903362649e-6L), tolerance);
  170. BOOST_CHECK_CLOSE(
  171. ::boost::math::rising_factorial(static_cast<T>(-5.25), -13),
  172. static_cast<T>(-1.38984989447269128946284683518361786049649013886981662962096e-14L), tolerance);
  173. //
  174. // More cases reported as bugs by Rocco Romeo:
  175. //
  176. BOOST_CHECK_EQUAL(::boost::math::rising_factorial(static_cast<T>(0), 1), static_cast<T>(0));
  177. BOOST_CHECK_EQUAL(::boost::math::rising_factorial(static_cast<T>(0), -1), static_cast<T>(-1));
  178. BOOST_CHECK_CLOSE(::boost::math::rising_factorial(static_cast<T>(0.5f), -1), static_cast<T>(-2), tolerance);
  179. BOOST_CHECK_CLOSE(::boost::math::rising_factorial(static_cast<T>(40.5), -41), static_cast<T>(-2.75643016796662963097096639854040835565778207128865739e-47L), tolerance);
  180. BOOST_CHECK_EQUAL(::boost::math::rising_factorial(static_cast<T>(-2), 3), static_cast<T>(0));
  181. BOOST_CHECK_EQUAL(::boost::math::rising_factorial(static_cast<T>(-2), 2), static_cast<T>(2));
  182. BOOST_CHECK_EQUAL(::boost::math::rising_factorial(static_cast<T>(-4), 3), static_cast<T>(-24));
  183. BOOST_CHECK_CLOSE(::boost::math::rising_factorial(static_cast<T>(-4), -3), static_cast<T>(-0.00476190476190476190476190476190476190476190476190476190476L), tolerance);
  184. if(ldexp(T(1), -150) != 0)
  185. {
  186. BOOST_CHECK_CLOSE(::boost::math::rising_factorial(ldexp(T(1), -150), 0), static_cast<T>(1), tolerance);
  187. BOOST_CHECK_CLOSE(::boost::math::rising_factorial(ldexp(T(1), -150), -1), static_cast<T>(-1.00000000000000000000000000000000000000000000070064923216241L), tolerance);
  188. BOOST_CHECK_CLOSE(::boost::math::rising_factorial(ldexp(T(1), -150), -2), static_cast<T>(0.500000000000000000000000000000000000000000000525486924121806L), tolerance);
  189. BOOST_CHECK_CLOSE(::boost::math::rising_factorial(ldexp(T(1), -150), -25), static_cast<T>(-6.44695028438447339619485321920468720529890442766578870603544e-26L), 15 * tolerance);
  190. if(std::numeric_limits<T>::min_exponent10 < -50)
  191. {
  192. BOOST_CHECK_CLOSE(::boost::math::rising_factorial(ldexp(T(1), -150), -40), static_cast<T>(1.22561743912838584942353998493975692372556196815242899727910e-48L), tolerance);
  193. }
  194. }
  195. //
  196. // Falling factorials:
  197. //
  198. BOOST_CHECK_CLOSE(
  199. ::boost::math::falling_factorial(static_cast<T>(30.25), 0),
  200. static_cast<T>(naive_falling_factorial(30.25L, 0)),
  201. tolerance);
  202. BOOST_CHECK_CLOSE(
  203. ::boost::math::falling_factorial(static_cast<T>(30.25), 1),
  204. static_cast<T>(naive_falling_factorial(30.25L, 1)),
  205. tolerance);
  206. BOOST_CHECK_CLOSE(
  207. ::boost::math::falling_factorial(static_cast<T>(30.25), 2),
  208. static_cast<T>(naive_falling_factorial(30.25L, 2)),
  209. tolerance);
  210. BOOST_CHECK_CLOSE(
  211. ::boost::math::falling_factorial(static_cast<T>(30.25), 5),
  212. static_cast<T>(naive_falling_factorial(30.25L, 5)),
  213. tolerance);
  214. BOOST_CHECK_CLOSE(
  215. ::boost::math::falling_factorial(static_cast<T>(30.25), 22),
  216. static_cast<T>(naive_falling_factorial(30.25L, 22)),
  217. tolerance);
  218. BOOST_CHECK_CLOSE(
  219. ::boost::math::falling_factorial(static_cast<T>(100.5), 6),
  220. static_cast<T>(naive_falling_factorial(100.5L, 6)),
  221. tolerance);
  222. BOOST_CHECK_CLOSE(
  223. ::boost::math::falling_factorial(static_cast<T>(30.75), 30),
  224. static_cast<T>(naive_falling_factorial(30.75L, 30)),
  225. tolerance * 3);
  226. if(boost::math::policies::digits<T, boost::math::policies::policy<> >() > 50)
  227. {
  228. BOOST_CHECK_CLOSE(
  229. ::boost::math::falling_factorial(static_cast<T>(-30.75L), 30),
  230. static_cast<T>(naive_falling_factorial(-30.75L, 30)),
  231. tolerance * 3);
  232. BOOST_CHECK_CLOSE(
  233. ::boost::math::falling_factorial(static_cast<T>(-30.75L), 27),
  234. static_cast<T>(naive_falling_factorial(-30.75L, 27)),
  235. tolerance * 3);
  236. }
  237. BOOST_CHECK_CLOSE(
  238. ::boost::math::falling_factorial(static_cast<T>(-12.0), 6),
  239. static_cast<T>(naive_falling_factorial(-12.0L, 6)),
  240. tolerance);
  241. BOOST_CHECK_CLOSE(
  242. ::boost::math::falling_factorial(static_cast<T>(-12), 5),
  243. static_cast<T>(naive_falling_factorial(-12.0L, 5)),
  244. tolerance);
  245. BOOST_CHECK_CLOSE(
  246. ::boost::math::falling_factorial(static_cast<T>(-3.0), 6),
  247. static_cast<T>(naive_falling_factorial(-3.0L, 6)),
  248. tolerance);
  249. BOOST_CHECK_CLOSE(
  250. ::boost::math::falling_factorial(static_cast<T>(-3), 5),
  251. static_cast<T>(naive_falling_factorial(-3.0L, 5)),
  252. tolerance);
  253. BOOST_CHECK_CLOSE(
  254. ::boost::math::falling_factorial(static_cast<T>(3.0), 6),
  255. static_cast<T>(naive_falling_factorial(3.0L, 6)),
  256. tolerance);
  257. BOOST_CHECK_CLOSE(
  258. ::boost::math::falling_factorial(static_cast<T>(3), 5),
  259. static_cast<T>(naive_falling_factorial(3.0L, 5)),
  260. tolerance);
  261. BOOST_CHECK_CLOSE(
  262. ::boost::math::falling_factorial(static_cast<T>(3.25), 4),
  263. static_cast<T>(naive_falling_factorial(3.25L, 4)),
  264. tolerance);
  265. BOOST_CHECK_CLOSE(
  266. ::boost::math::falling_factorial(static_cast<T>(3.25), 5),
  267. static_cast<T>(naive_falling_factorial(3.25L, 5)),
  268. tolerance);
  269. BOOST_CHECK_CLOSE(
  270. ::boost::math::falling_factorial(static_cast<T>(3.25), 6),
  271. static_cast<T>(naive_falling_factorial(3.25L, 6)),
  272. tolerance);
  273. BOOST_CHECK_CLOSE(
  274. ::boost::math::falling_factorial(static_cast<T>(3.25), 7),
  275. static_cast<T>(naive_falling_factorial(3.25L, 7)),
  276. tolerance);
  277. BOOST_CHECK_CLOSE(
  278. ::boost::math::falling_factorial(static_cast<T>(8.25), 12),
  279. static_cast<T>(naive_falling_factorial(8.25L, 12)),
  280. tolerance);
  281. //
  282. // More cases reported as bugs by Rocco Romeo:
  283. //
  284. BOOST_CHECK_EQUAL(::boost::math::falling_factorial(static_cast<T>(0), 1), static_cast<T>(0));
  285. BOOST_CHECK_CLOSE(::boost::math::falling_factorial(static_cast<T>(-2), 3), static_cast<T>(-24), tolerance);
  286. BOOST_CHECK_CLOSE(::boost::math::falling_factorial(static_cast<T>(-2), 2), static_cast<T>(6), tolerance);
  287. BOOST_CHECK_CLOSE(::boost::math::falling_factorial(static_cast<T>(-4), 3), static_cast<T>(-120), tolerance);
  288. if(ldexp(static_cast<T>(1), -100) != 0)
  289. {
  290. BOOST_CHECK_CLOSE(::boost::math::falling_factorial(ldexp(static_cast<T>(1), -100), 1), static_cast<T>(7.888609052210118054117285652827862296732064351090230047e-31L), tolerance);
  291. BOOST_CHECK_CLOSE(::boost::math::falling_factorial(ldexp(static_cast<T>(1), -100), 2), static_cast<T>(-7.88860905221011805411728565282163928145420320938308598e-31L), tolerance);
  292. BOOST_CHECK_CLOSE(::boost::math::falling_factorial(ldexp(static_cast<T>(1), -100), 3), static_cast<T>(1.577721810442023610823457130563705554763054527705902790e-30L), tolerance);
  293. BOOST_CHECK_CLOSE(::boost::math::falling_factorial(ldexp(static_cast<T>(1), -100), 35), static_cast<T>(2.32897613101315187323300837924676081371219290005311315885e8L), 35 * tolerance);
  294. }
  295. if((ldexp(static_cast<T>(1), -300) != 0) && (std::numeric_limits<T>::max_exponent10 > 290))
  296. {
  297. BOOST_CHECK_CLOSE(::boost::math::falling_factorial(ldexp(static_cast<T>(1), -300), 20), static_cast<T>(-5.97167167502482975928590631196751639118233432208390100e-74L), tolerance);
  298. BOOST_CHECK_CLOSE(::boost::math::falling_factorial(ldexp(static_cast<T>(1), -300), 200), static_cast<T>(-1.93579759151806711025267355739174942986011285920860098569075e282L), 10 * tolerance);
  299. }
  300. tolerance = boost::math::tools::epsilon<T>() * 100 * 20; // 20 eps as a percent.
  301. unsigned i = boost::math::max_factorial<T>::value;
  302. if((boost::is_floating_point<T>::value) && (sizeof(T) <= sizeof(double)))
  303. {
  304. // Without Lanczos support, tgamma isn't accurate enough for this test:
  305. BOOST_CHECK_CLOSE(
  306. ::boost::math::unchecked_factorial<T>(i),
  307. boost::math::tgamma(static_cast<T>(i+1)), tolerance);
  308. }
  309. i += 10;
  310. while(boost::math::lgamma(static_cast<T>(i+1)) < boost::math::tools::log_max_value<T>())
  311. {
  312. BOOST_CHECK_CLOSE(
  313. ::boost::math::factorial<T>(i),
  314. boost::math::tgamma(static_cast<T>(i+1)), tolerance);
  315. i += 10;
  316. }
  317. } // template <class T> void test_spots(T)
  318. BOOST_AUTO_TEST_CASE( test_main )
  319. {
  320. BOOST_MATH_CONTROL_FP;
  321. test_spots(0.0F);
  322. test_spots(0.0);
  323. #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
  324. test_spots(0.0L);
  325. #ifndef BOOST_MATH_NO_REAL_CONCEPT_TESTS
  326. test_spots(boost::math::concepts::real_concept(0.));
  327. #endif
  328. #else
  329. std::cout << "<note>The long double tests have been disabled on this platform "
  330. "either because the long double overloads of the usual math functions are "
  331. "not available at all, or because they are too inaccurate for these tests "
  332. "to pass.</note>" << std::endl;
  333. #endif
  334. if (std::numeric_limits<double>::digits == std::numeric_limits<long double>::digits)
  335. {
  336. cout << "Types double and long double have the same number of floating-point significand bits ("
  337. << std::numeric_limits<long double>::digits << ") on this platform." << endl;
  338. }
  339. if (std::numeric_limits<float>::digits == std::numeric_limits<double>::digits)
  340. {
  341. cout << "Types float and double have the same number of floating-point significand bits ("
  342. << std::numeric_limits<double>::digits << ") on this platform." << endl;
  343. }
  344. using boost::math::max_factorial;
  345. cout << "max factorial for float " << max_factorial<float>::value << endl;
  346. cout << "max factorial for double " << max_factorial<double>::value << endl;
  347. cout << "max factorial for long double " << max_factorial<long double>::value << endl;
  348. cout << "max factorial for real_concept " << max_factorial<boost::math::concepts::real_concept>::value << endl;
  349. }
  350. /*
  351. Output is:
  352. Running 1 test case...
  353. Types double and long double have the same number of floating-point significand bits (53) on this platform.
  354. max factorial for float 34
  355. max factorial for double 170
  356. max factorial for long double 170
  357. max factorial for real_concept 100
  358. *** No errors detected
  359. */