// test_negative_binomial.cpp // Copyright Paul A. Bristow 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) // Basic sanity test for Negative Binomial Cumulative Distribution Function. #define BOOST_MATH_THROW_ON_DOMAIN_ERROR #ifdef _MSC_VER //# pragma warning(disable: 4127) // conditional expression is constant. //# pragma warning(disable: 4100) // unreferenced formal parameter. //# pragma warning(disable: 4512) // assignment operator could not be generated. //# pragma warning(disable: 4996) // 'std::char_traits::copy' was declared deprecated. //# pragma warning(disable: 4244) // conversion from 'double' to 'const float', possible loss of data. #endif #include // for negative_binomial using ::boost::math::negative_binomial; using ::boost::math::negative_binomial_c; using ::boost::math::negative_binomial_inv; #include // for real_concept using ::boost::math::concepts::real_concept; #include // for test_main #include // for BOOST_CHECK_CLOSE #include using std::cout; using std::endl; #include using std::numeric_limits; template // RealType is any floating-point type. void test_spots(RealType) { // Basic sanity checks, tolerance is about numeric_limits::digits10 decimal places, // guaranteed for type RealType, eg 6 for float, 15 for double, // expressed as a percentage (so -2) for BOOST_CHECK_CLOSE, int decdigits = numeric_limits::digits10; decdigits -= 1; // Perhaps allow some decimal digits margin of numerical error. RealType tolerance = static_cast(std::pow(10., -(decdigits-2))); // 1e-6 (-2 so as %) tolerance *= 1; // Allow some bit(s) small margin (2 means + or - 1 bit) of numerical error. // Typically 2e-13% = 2e-15 as fraction for double. // Sources of spot test values: // MathCAD // pnbinom(k, n, p) // Returns cumulative negative binomial distribution. // qnbinom(p, n, q) // Returns the inverse negative binomial distribution function, // the smallest integer k so that pnbinom(k, n, q) >= p // MathWorld definition: negaBin[n, p] // number of failures that occur before achieving n successes, where probability of success in a trial is p. // Cephes probability that k or fewer failures preceeds the nth success. // Wikipedia For k + r trials with success probability p, // gives the probability of k failures and r successes, with sucess on the last trial. // Or probability of number of failures before the rth success. // Many be some combinations for which the result is 'exact', or at least is to 40 decimal digits. // 40 decimal digits includes 128-bit significand User Defined Floating-Point types, // but these are as yet undiscovered for negative binomial. TODO // Test negative binomial. // negative_binomial(k, n, p) BOOST_CHECK_CLOSE(negative_binomial( static_cast(0), // k. pnbinom(1,2,0.5) = 0.5 static_cast(2), // n static_cast(0.5)), // mean static_cast(0.25), // probability 1/4 tolerance); BOOST_CHECK_CLOSE(negative_binomial( static_cast(1), // k static_cast(4), // n static_cast(0.5)), // p static_cast(0.1875), // tolerance); BOOST_CHECK_CLOSE(negative_binomial( static_cast(1), // k static_cast(2), // n static_cast(0.5)), // pnbinom(1,2,0.5) = 0.5 static_cast(0.5), // tolerance); BOOST_CHECK_CLOSE(negative_binomial( static_cast(2), // k static_cast(2), // n static_cast(0.5)), // pnbinom(1,2,0.5) = 0.5 static_cast(0.6875), // tolerance); BOOST_CHECK_CLOSE(negative_binomial( static_cast(1), // k static_cast(3), // n static_cast(0.5)), // pnbinom(1,3,0.5) = 0.5 static_cast(0.3125), // 0.6875 tolerance); BOOST_CHECK_CLOSE(negative_binomial( static_cast(2), // k static_cast(2), // n static_cast(0.1)), // static_cast(0.0523), // tolerance); BOOST_CHECK_CLOSE(negative_binomial_c( static_cast(2), // k static_cast(2), // n static_cast(0.1)), // static_cast(1- 0.0523), // tolerance); BOOST_CHECK_CLOSE(negative_binomial( static_cast(26), // k static_cast(5), // n static_cast(0.4)), // p static_cast(0.998968624661119), tolerance); BOOST_CHECK_CLOSE(negative_binomial( static_cast(25), // k static_cast(5), // n static_cast(0.4)), // p static_cast(0.998489925933617), tolerance); BOOST_CHECK_CLOSE(negative_binomial_c( // complement. static_cast(26), // k static_cast(5), // n static_cast(0.4)), // p static_cast(1 - 0.998968624661119), tolerance * 100); // fails at tolerance * 10 // 0.0010313753388809799 // 0.0010313753388808430 // Shows a loss of about 3 decimal digits accuracy. // negative_binomial_inv(k, n, p) tests. BOOST_CHECK_CLOSE(negative_binomial( static_cast(5), // k. static_cast(10), // n static_cast(0.5)), // trial probability static_cast(0.15087890625000011), // probability of failure. tolerance); BOOST_CHECK_CLOSE(negative_binomial_inv( static_cast(5), // k. static_cast(10), // n static_cast(0.15087890625000011)), // probability of failure = negative_binomial(5, 10, 0.5). static_cast(0.5), // result is probability of success tolerance); BOOST_CHECK_CLOSE(negative_binomial( static_cast(5), // k failures. static_cast(10), // n successes. static_cast(0.1)), // trial probability of success. static_cast(1.8662024800000033e-007), // tolerance); BOOST_CHECK_CLOSE(negative_binomial_inv( static_cast(5), // k failures. static_cast(10), // n successes. static_cast(1.8662024800000033e-007)), // probability of failure = negative_binomial(5, 10, 0.1) static_cast(0.1), // results is trial probability tolerance); } // template void test_spots(RealType) int test_main(int, char* []) { // Basic sanity-check spot values. #ifdef BOOST_MATH_THROW_ON_DOMAIN_ERROR cout << "BOOST_MATH_THROW_ON_DOMAIN_ERROR" << " is defined to throw on domain error." << endl; #else cout << "BOOST_MATH_THROW_ON_DOMAIN_ERROR" << " is NOT defined, so NO throw on domain error." << endl; #endif //for (int i = 0; i < 10; i++) //{ // cout << i << ' ' << negative_binomial(i, 2, 0.5) << endl; //} //cout << endl; //cout.precision(17); //for (double p = 0.; p < 1; p+= 0.1) //{ // double y = negative_binomial(5, 10, p); // double z = negative_binomial_inv(5, 10, y); // cout << p << ' '<< y << ' ' << z << ' ' << p - z << endl; //} // (Parameter value, arbitrarily zero, only communicates the floating point type). test_spots(0.0F); // Test float. test_spots(0.0); // Test double. test_spots(0.0L); // Test long double. test_spots(boost::math::concepts::real_concept(0.)); // Test real concept. return 0; } // int test_main(int, char* []) /* Output: ------ Build started: Project: test_negative_binomial, Configuration: Debug Win32 ------ Compiling... test_negative_binomial.cpp Linking... Autorun "i:\boost-06-05-03-1300\libs\math\test\Math_test\debug\test_negative_binomial.exe" Running 1 test case... BOOST_MATH_THROW_ON_DOMAIN_ERROR is defined to throw on domain error. 0 0.25 1 0.5 2 0.6875 3 0.8125 4 0.890625 5 0.9375 6 0.964844 7 0.980469 8 0.989258 9 0.994141 0 0 -1.#INF 1.#INF 0.10000000000000001 1.8662024800000033e-007 0.10000000000000002 -1.3877787807814457e-017 0.20000000000000001 0.00011322566246400017 0.20000000000000004 -2.7755575615628914e-017 0.30000000000000004 0.0036525210084360034 0.29999999999999999 5.5511151231257827e-017 0.40000000000000002 0.033833302884352018 0.39999999999999997 5.5511151231257827e-017 0.5 0.15087890625000011 0.5 0 0.59999999999999998 0.40321555041484813 0.60000000000000009 -1.1102230246251565e-016 0.69999999999999996 0.72162144020436414 0.70000000000000007 -1.1102230246251565e-016 0.79999999999999993 0.93894857038233592 0.79999999999999982 1.1102230246251565e-016 0.89999999999999991 0.99775032991495194 0.89999999999999947 4.4408920985006262e-016 0.99999999999999989 1 1.#INF -1.#INF *** No errors detected Build Time 0:05 Build log was saved at "file://i:\boost-06-05-03-1300\libs\math\test\Math_test\test_negative_binomial\Debug\BuildLog.htm" test_negative_binomial - 0 error(s), 0 warning(s) ========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ========== */