// Copyright John Maddock 2006. // 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) #include #ifdef _MSC_VER # pragma warning(disable: 4127) // conditional expression is constant. # pragma warning(disable: 4245) // int/unsigned int conversion #endif // Return infinities not exceptions: #define BOOST_MATH_OVERFLOW_ERROR_POLICY ignore_error #include #define BOOST_TEST_MAIN #include #include #include #include #include #include #include #include using std::cout; using std::endl; template T naive_falling_factorial(T x, unsigned n) { if(n == 0) return 1; T result = x; while(--n) { x -= 1; result *= x; } return result; } template void test_spots(T) { // // Basic sanity checks. // T tolerance = boost::math::tools::epsilon() * 100 * 2; // 2 eps as a percent. BOOST_CHECK_CLOSE( ::boost::math::factorial(0), static_cast(1), tolerance); BOOST_CHECK_CLOSE( ::boost::math::factorial(1), static_cast(1), tolerance); BOOST_CHECK_CLOSE( ::boost::math::factorial(10), static_cast(3628800L), tolerance); BOOST_CHECK_CLOSE( ::boost::math::unchecked_factorial(0), static_cast(1), tolerance); BOOST_CHECK_CLOSE( ::boost::math::unchecked_factorial(1), static_cast(1), tolerance); BOOST_CHECK_CLOSE( ::boost::math::unchecked_factorial(10), static_cast(3628800L), tolerance); // // Try some double factorials: // BOOST_CHECK_CLOSE( ::boost::math::double_factorial(0), static_cast(1), tolerance); BOOST_CHECK_CLOSE( ::boost::math::double_factorial(1), static_cast(1), tolerance); BOOST_CHECK_CLOSE( ::boost::math::double_factorial(2), static_cast(2), tolerance); BOOST_CHECK_CLOSE( ::boost::math::double_factorial(5), static_cast(15), tolerance); BOOST_CHECK_CLOSE( ::boost::math::double_factorial(10), static_cast(3840), tolerance); BOOST_CHECK_CLOSE( ::boost::math::double_factorial(19), static_cast(6.547290750e8L), tolerance); BOOST_CHECK_CLOSE( ::boost::math::double_factorial(24), static_cast(1.961990553600000e12L), tolerance); BOOST_CHECK_CLOSE( ::boost::math::double_factorial(33), static_cast(6.33265987076285062500000e18L), tolerance); BOOST_CHECK_CLOSE( ::boost::math::double_factorial(42), static_cast(1.0714547155728479551488000000e26L), tolerance); BOOST_CHECK_CLOSE( ::boost::math::double_factorial(47), static_cast(1.19256819277443412353990764062500000e30L), tolerance); if((std::numeric_limits::has_infinity) && (std::numeric_limits::max_exponent <= 1024)) { BOOST_CHECK_EQUAL( ::boost::math::double_factorial(320), std::numeric_limits::infinity()); BOOST_CHECK_EQUAL( ::boost::math::double_factorial(301), std::numeric_limits::infinity()); } // // Rising factorials: // tolerance = boost::math::tools::epsilon() * 100 * 20; // 20 eps as a percent. if(std::numeric_limits::is_specialized == 0) tolerance *= 5; // higher error rates without Lanczos support BOOST_CHECK_CLOSE( ::boost::math::rising_factorial(static_cast(3), 4), static_cast(360), tolerance); BOOST_CHECK_CLOSE( ::boost::math::rising_factorial(static_cast(7), -4), static_cast(0.00277777777777777777777777777777777777777777777777777777777778L), tolerance); BOOST_CHECK_CLOSE( ::boost::math::rising_factorial(static_cast(120.5f), 8), static_cast(5.58187566784927180664062500e16L), tolerance); BOOST_CHECK_CLOSE( ::boost::math::rising_factorial(static_cast(120.5f), -4), static_cast(5.15881498170104646868208445266116850161120996179812063177241e-9L), tolerance); BOOST_CHECK_CLOSE( ::boost::math::rising_factorial(static_cast(5000.25f), 8), static_cast(3.92974581976666067544013393509103775024414062500000e29L), tolerance); BOOST_CHECK_CLOSE( ::boost::math::rising_factorial(static_cast(5000.25f), -7), static_cast(1.28674092710208810281923019294164707555099052561945725535047e-26L), tolerance); BOOST_CHECK_CLOSE( ::boost::math::rising_factorial(static_cast(30.25), 21), static_cast(3.93286957998925490693364184100209193343633629069699964020401e33L), tolerance * 2); BOOST_CHECK_CLOSE( ::boost::math::rising_factorial(static_cast(30.25), -21), static_cast(3.35010902064291983728782493133164809108646650368560147505884e-27L), tolerance); BOOST_CHECK_CLOSE( ::boost::math::rising_factorial(static_cast(-30.25), 21), static_cast(-9.76168312768123676601980433377916854311706629232503473758698e26L), tolerance * 2); BOOST_CHECK_CLOSE( ::boost::math::rising_factorial(static_cast(-30.25), -21), static_cast(-1.50079704000923674318934280259377728203516775215430875839823e-34L), 2 * tolerance); BOOST_CHECK_CLOSE( ::boost::math::rising_factorial(static_cast(-30.25), 5), static_cast(-1.78799177197265625000000e7L), tolerance); BOOST_CHECK_CLOSE( ::boost::math::rising_factorial(static_cast(-30.25), -5), static_cast(-2.47177487004482195012362027432181137141899692171397467859150e-8L), tolerance); BOOST_CHECK_CLOSE( ::boost::math::rising_factorial(static_cast(-30.25), 6), static_cast(4.5146792242309570312500000e8L), tolerance); BOOST_CHECK_CLOSE( ::boost::math::rising_factorial(static_cast(-30.25), -6), static_cast(6.81868929667537089689274558433603136943171564610751635473516e-10L), tolerance); BOOST_CHECK_CLOSE( ::boost::math::rising_factorial(static_cast(-3), 6), static_cast(0), tolerance); BOOST_CHECK_CLOSE( ::boost::math::rising_factorial(static_cast(-3.25), 6), static_cast(2.99926757812500L), tolerance); BOOST_CHECK_CLOSE( ::boost::math::rising_factorial(static_cast(-5.25), 6), static_cast(50.987548828125000000000000L), tolerance); BOOST_CHECK_CLOSE( ::boost::math::rising_factorial(static_cast(-5.25), 13), static_cast(127230.91046623885631561279296875000L), tolerance); BOOST_CHECK_CLOSE( ::boost::math::rising_factorial(static_cast(-3.25), -6), static_cast(0.0000129609865918182348202632178291407500332449622510474437452125L), tolerance); BOOST_CHECK_CLOSE( ::boost::math::rising_factorial(static_cast(-5.25), -6), static_cast(2.50789821857946332294524052303699065683926911849535903362649e-6L), tolerance); BOOST_CHECK_CLOSE( ::boost::math::rising_factorial(static_cast(-5.25), -13), static_cast(-1.38984989447269128946284683518361786049649013886981662962096e-14L), tolerance); // // More cases reported as bugs by Rocco Romeo: // BOOST_CHECK_EQUAL(::boost::math::rising_factorial(static_cast(0), 1), static_cast(0)); BOOST_CHECK_EQUAL(::boost::math::rising_factorial(static_cast(0), -1), static_cast(-1)); BOOST_CHECK_CLOSE(::boost::math::rising_factorial(static_cast(0.5f), -1), static_cast(-2), tolerance); BOOST_CHECK_CLOSE(::boost::math::rising_factorial(static_cast(40.5), -41), static_cast(-2.75643016796662963097096639854040835565778207128865739e-47L), tolerance); BOOST_CHECK_EQUAL(::boost::math::rising_factorial(static_cast(-2), 3), static_cast(0)); BOOST_CHECK_EQUAL(::boost::math::rising_factorial(static_cast(-2), 2), static_cast(2)); BOOST_CHECK_EQUAL(::boost::math::rising_factorial(static_cast(-4), 3), static_cast(-24)); BOOST_CHECK_CLOSE(::boost::math::rising_factorial(static_cast(-4), -3), static_cast(-0.00476190476190476190476190476190476190476190476190476190476L), tolerance); if(ldexp(T(1), -150) != 0) { BOOST_CHECK_CLOSE(::boost::math::rising_factorial(ldexp(T(1), -150), 0), static_cast(1), tolerance); BOOST_CHECK_CLOSE(::boost::math::rising_factorial(ldexp(T(1), -150), -1), static_cast(-1.00000000000000000000000000000000000000000000070064923216241L), tolerance); BOOST_CHECK_CLOSE(::boost::math::rising_factorial(ldexp(T(1), -150), -2), static_cast(0.500000000000000000000000000000000000000000000525486924121806L), tolerance); BOOST_CHECK_CLOSE(::boost::math::rising_factorial(ldexp(T(1), -150), -25), static_cast(-6.44695028438447339619485321920468720529890442766578870603544e-26L), 15 * tolerance); if(std::numeric_limits::min_exponent10 < -50) { BOOST_CHECK_CLOSE(::boost::math::rising_factorial(ldexp(T(1), -150), -40), static_cast(1.22561743912838584942353998493975692372556196815242899727910e-48L), tolerance); } } // // Falling factorials: // BOOST_CHECK_CLOSE( ::boost::math::falling_factorial(static_cast(30.25), 0), static_cast(naive_falling_factorial(30.25L, 0)), tolerance); BOOST_CHECK_CLOSE( ::boost::math::falling_factorial(static_cast(30.25), 1), static_cast(naive_falling_factorial(30.25L, 1)), tolerance); BOOST_CHECK_CLOSE( ::boost::math::falling_factorial(static_cast(30.25), 2), static_cast(naive_falling_factorial(30.25L, 2)), tolerance); BOOST_CHECK_CLOSE( ::boost::math::falling_factorial(static_cast(30.25), 5), static_cast(naive_falling_factorial(30.25L, 5)), tolerance); BOOST_CHECK_CLOSE( ::boost::math::falling_factorial(static_cast(30.25), 22), static_cast(naive_falling_factorial(30.25L, 22)), tolerance); BOOST_CHECK_CLOSE( ::boost::math::falling_factorial(static_cast(100.5), 6), static_cast(naive_falling_factorial(100.5L, 6)), tolerance); BOOST_CHECK_CLOSE( ::boost::math::falling_factorial(static_cast(30.75), 30), static_cast(naive_falling_factorial(30.75L, 30)), tolerance * 3); if(boost::math::policies::digits >() > 50) { BOOST_CHECK_CLOSE( ::boost::math::falling_factorial(static_cast(-30.75L), 30), static_cast(naive_falling_factorial(-30.75L, 30)), tolerance * 3); BOOST_CHECK_CLOSE( ::boost::math::falling_factorial(static_cast(-30.75L), 27), static_cast(naive_falling_factorial(-30.75L, 27)), tolerance * 3); } BOOST_CHECK_CLOSE( ::boost::math::falling_factorial(static_cast(-12.0), 6), static_cast(naive_falling_factorial(-12.0L, 6)), tolerance); BOOST_CHECK_CLOSE( ::boost::math::falling_factorial(static_cast(-12), 5), static_cast(naive_falling_factorial(-12.0L, 5)), tolerance); BOOST_CHECK_CLOSE( ::boost::math::falling_factorial(static_cast(-3.0), 6), static_cast(naive_falling_factorial(-3.0L, 6)), tolerance); BOOST_CHECK_CLOSE( ::boost::math::falling_factorial(static_cast(-3), 5), static_cast(naive_falling_factorial(-3.0L, 5)), tolerance); BOOST_CHECK_CLOSE( ::boost::math::falling_factorial(static_cast(3.0), 6), static_cast(naive_falling_factorial(3.0L, 6)), tolerance); BOOST_CHECK_CLOSE( ::boost::math::falling_factorial(static_cast(3), 5), static_cast(naive_falling_factorial(3.0L, 5)), tolerance); BOOST_CHECK_CLOSE( ::boost::math::falling_factorial(static_cast(3.25), 4), static_cast(naive_falling_factorial(3.25L, 4)), tolerance); BOOST_CHECK_CLOSE( ::boost::math::falling_factorial(static_cast(3.25), 5), static_cast(naive_falling_factorial(3.25L, 5)), tolerance); BOOST_CHECK_CLOSE( ::boost::math::falling_factorial(static_cast(3.25), 6), static_cast(naive_falling_factorial(3.25L, 6)), tolerance); BOOST_CHECK_CLOSE( ::boost::math::falling_factorial(static_cast(3.25), 7), static_cast(naive_falling_factorial(3.25L, 7)), tolerance); BOOST_CHECK_CLOSE( ::boost::math::falling_factorial(static_cast(8.25), 12), static_cast(naive_falling_factorial(8.25L, 12)), tolerance); // // More cases reported as bugs by Rocco Romeo: // BOOST_CHECK_EQUAL(::boost::math::falling_factorial(static_cast(0), 1), static_cast(0)); BOOST_CHECK_CLOSE(::boost::math::falling_factorial(static_cast(-2), 3), static_cast(-24), tolerance); BOOST_CHECK_CLOSE(::boost::math::falling_factorial(static_cast(-2), 2), static_cast(6), tolerance); BOOST_CHECK_CLOSE(::boost::math::falling_factorial(static_cast(-4), 3), static_cast(-120), tolerance); if(ldexp(static_cast(1), -100) != 0) { BOOST_CHECK_CLOSE(::boost::math::falling_factorial(ldexp(static_cast(1), -100), 1), static_cast(7.888609052210118054117285652827862296732064351090230047e-31L), tolerance); BOOST_CHECK_CLOSE(::boost::math::falling_factorial(ldexp(static_cast(1), -100), 2), static_cast(-7.88860905221011805411728565282163928145420320938308598e-31L), tolerance); BOOST_CHECK_CLOSE(::boost::math::falling_factorial(ldexp(static_cast(1), -100), 3), static_cast(1.577721810442023610823457130563705554763054527705902790e-30L), tolerance); BOOST_CHECK_CLOSE(::boost::math::falling_factorial(ldexp(static_cast(1), -100), 35), static_cast(2.32897613101315187323300837924676081371219290005311315885e8L), 35 * tolerance); } if((ldexp(static_cast(1), -300) != 0) && (std::numeric_limits::max_exponent10 > 290)) { BOOST_CHECK_CLOSE(::boost::math::falling_factorial(ldexp(static_cast(1), -300), 20), static_cast(-5.97167167502482975928590631196751639118233432208390100e-74L), tolerance); BOOST_CHECK_CLOSE(::boost::math::falling_factorial(ldexp(static_cast(1), -300), 200), static_cast(-1.93579759151806711025267355739174942986011285920860098569075e282L), 10 * tolerance); } tolerance = boost::math::tools::epsilon() * 100 * 20; // 20 eps as a percent. unsigned i = boost::math::max_factorial::value; if((boost::is_floating_point::value) && (sizeof(T) <= sizeof(double))) { // Without Lanczos support, tgamma isn't accurate enough for this test: BOOST_CHECK_CLOSE( ::boost::math::unchecked_factorial(i), boost::math::tgamma(static_cast(i+1)), tolerance); } i += 10; while(boost::math::lgamma(static_cast(i+1)) < boost::math::tools::log_max_value()) { BOOST_CHECK_CLOSE( ::boost::math::factorial(i), boost::math::tgamma(static_cast(i+1)), tolerance); i += 10; } } // template void test_spots(T) BOOST_AUTO_TEST_CASE( test_main ) { BOOST_MATH_CONTROL_FP; test_spots(0.0F); test_spots(0.0); #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS test_spots(0.0L); #ifndef BOOST_MATH_NO_REAL_CONCEPT_TESTS test_spots(boost::math::concepts::real_concept(0.)); #endif #else std::cout << "The long double tests have been disabled on this platform " "either because the long double overloads of the usual math functions are " "not available at all, or because they are too inaccurate for these tests " "to pass." << std::endl; #endif if (std::numeric_limits::digits == std::numeric_limits::digits) { cout << "Types double and long double have the same number of floating-point significand bits (" << std::numeric_limits::digits << ") on this platform." << endl; } if (std::numeric_limits::digits == std::numeric_limits::digits) { cout << "Types float and double have the same number of floating-point significand bits (" << std::numeric_limits::digits << ") on this platform." << endl; } using boost::math::max_factorial; cout << "max factorial for float " << max_factorial::value << endl; cout << "max factorial for double " << max_factorial::value << endl; cout << "max factorial for long double " << max_factorial::value << endl; cout << "max factorial for real_concept " << max_factorial::value << endl; } /* Output is: Running 1 test case... Types double and long double have the same number of floating-point significand bits (53) on this platform. max factorial for float 34 max factorial for double 170 max factorial for long double 170 max factorial for real_concept 100 *** No errors detected */