// (C) Copyright John Maddock 2008. // 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 #include #include #define BOOST_TEST_MAIN #include #include #include #include #include #include #include #include #ifdef BOOST_MSVC #pragma warning(disable:4127) #endif template bool is_normalized_value(const T& val) { // // Returns false if value has guard digits that are non-zero // boost::intmax_t shift = std::numeric_limits::digits - ilogb(val) - 1; T shifted = scalbn(val, shift); return floor(shifted) == shifted; } template void test_value(const T& val, const char* name) { using namespace boost::math; T upper = tools::max_value(); T lower = -upper; std::cout << "Testing type " << name << " with initial value " << val << std::endl; BOOST_CHECK_EQUAL(float_distance(float_next(val), val), -1); BOOST_CHECK(float_next(val) > val); BOOST_CHECK_EQUAL(float_distance(float_prior(val), val), 1); BOOST_CHECK(float_prior(val) < val); BOOST_CHECK_EQUAL(float_distance((boost::math::nextafter)(val, upper), val), -1); BOOST_CHECK((boost::math::nextafter)(val, upper) > val); BOOST_CHECK_EQUAL(float_distance((boost::math::nextafter)(val, lower), val), 1); BOOST_CHECK((boost::math::nextafter)(val, lower) < val); BOOST_CHECK_EQUAL(float_distance(float_next(float_next(val)), val), -2); BOOST_CHECK_EQUAL(float_distance(float_prior(float_prior(val)), val), 2); BOOST_CHECK_EQUAL(float_distance(float_prior(float_prior(val)), float_next(float_next(val))), 4); BOOST_CHECK_EQUAL(float_distance(float_prior(float_next(val)), val), 0); BOOST_CHECK_EQUAL(float_distance(float_next(float_prior(val)), val), 0); if (is_normalized_value(val)) { BOOST_CHECK_EQUAL(float_prior(float_next(val)), val); BOOST_CHECK_EQUAL(float_next(float_prior(val)), val); } BOOST_CHECK_EQUAL(float_distance(float_advance(val, 4), val), -4); BOOST_CHECK_EQUAL(float_distance(float_advance(val, -4), val), 4); if(std::numeric_limits::is_specialized && (std::numeric_limits::has_denorm == std::denorm_present)) { BOOST_CHECK_EQUAL(float_distance(float_advance(float_next(float_next(val)), 4), float_next(float_next(val))), -4); BOOST_CHECK_EQUAL(float_distance(float_advance(float_next(float_next(val)), -4), float_next(float_next(val))), 4); } if (is_normalized_value(val)) { if (val > 0) { T n = val + ulp(val); T fn = float_next(val); if (n > fn) { BOOST_CHECK_LE(ulp(val), boost::math::tools::min_value()); } else { BOOST_CHECK_EQUAL(fn, n); } } else if (val == 0) { BOOST_CHECK_GE(boost::math::tools::min_value(), ulp(val)); } else { T n = val - ulp(val); T fp = float_prior(val); if (n < fp) { BOOST_CHECK_LE(ulp(val), boost::math::tools::min_value()); } else { BOOST_CHECK_EQUAL(fp, n); } } } } template void test_values(const T& val, const char* name) { static const T a = boost::lexical_cast("1.3456724e22"); static const T b = boost::lexical_cast("1.3456724e-22"); static const T z = 0; static const T one = 1; static const T radix = std::numeric_limits::radix; std::cout << "Testing type " << name << std::endl; T den = (std::numeric_limits::min)() / 4; if(den != 0) { std::cout << "Denormals are active\n"; } else { std::cout << "Denormals are flushed to zero.\n"; } test_value(a, name); test_value(T(-a), name); test_value(b, name); test_value(T(-b), name); test_value(T(b / 3), name); test_value(T(-b / 3), name); test_value(boost::math::tools::epsilon(), name); test_value(T(-boost::math::tools::epsilon()), name); test_value(boost::math::tools::min_value(), name); test_value(T(-boost::math::tools::min_value()), name); if (std::numeric_limits::is_specialized && (std::numeric_limits::has_denorm == std::denorm_present) && ((std::numeric_limits::min)() / 2 != 0)) { test_value(z, name); test_value(T(-z), name); } test_value(one, name); test_value(T(-one), name); test_value(radix, name); test_value(T(-radix), name); if(std::numeric_limits::is_specialized && (std::numeric_limits::has_denorm == std::denorm_present) && ((std::numeric_limits::min)() / 2 != 0)) { test_value(std::numeric_limits::denorm_min(), name); test_value(T(-std::numeric_limits::denorm_min()), name); test_value(T(2 * std::numeric_limits::denorm_min()), name); test_value(T(-2 * std::numeric_limits::denorm_min()), name); } static const int primes[] = { 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, }; for(unsigned i = 0; i < sizeof(primes)/sizeof(primes[0]); ++i) { T v1 = val; T v2 = val; for(int j = 0; j < primes[i]; ++j) { v1 = boost::math::float_next(v1); v2 = boost::math::float_prior(v2); } BOOST_CHECK_EQUAL(boost::math::float_distance(v1, val), -primes[i]); BOOST_CHECK_EQUAL(boost::math::float_distance(v2, val), primes[i]); BOOST_CHECK_EQUAL(boost::math::float_advance(val, primes[i]), v1); BOOST_CHECK_EQUAL(boost::math::float_advance(val, -primes[i]), v2); } if(std::numeric_limits::is_specialized && (std::numeric_limits::has_infinity)) { BOOST_CHECK_EQUAL(boost::math::float_prior(std::numeric_limits::infinity()), (std::numeric_limits::max)()); BOOST_CHECK_EQUAL(boost::math::float_next(-std::numeric_limits::infinity()), -(std::numeric_limits::max)()); BOOST_MATH_CHECK_THROW(boost::math::float_prior(-std::numeric_limits::infinity()), std::domain_error); BOOST_MATH_CHECK_THROW(boost::math::float_next(std::numeric_limits::infinity()), std::domain_error); if(boost::math::policies:: BOOST_MATH_OVERFLOW_ERROR_POLICY == boost::math::policies::throw_on_error) { BOOST_MATH_CHECK_THROW(boost::math::float_prior(-(std::numeric_limits::max)()), std::overflow_error); BOOST_MATH_CHECK_THROW(boost::math::float_next((std::numeric_limits::max)()), std::overflow_error); } else { BOOST_CHECK_EQUAL(boost::math::float_prior(-(std::numeric_limits::max)()), -std::numeric_limits::infinity()); BOOST_CHECK_EQUAL(boost::math::float_next((std::numeric_limits::max)()), std::numeric_limits::infinity()); } } } BOOST_AUTO_TEST_CASE( test_main ) { // Very slow, but debuggable: //test_values(boost::multiprecision::number >(0), "cpp_dec_float_50"); // Faster, but no good for diagnising the cause of any issues: test_values(boost::multiprecision::cpp_dec_float_50(0), "cpp_dec_float_50"); }