• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //  (C) Copyright John Maddock 2008.
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 
6 #include <pch.hpp>
7 
8 #include <boost/math/concepts/real_concept.hpp>
9 #include <boost/math/tools/test.hpp>
10 #define BOOST_TEST_MAIN
11 #include <boost/test/unit_test.hpp>
12 #include <boost/test/tools/floating_point_comparison.hpp>
13 #include <boost/math/special_functions/next.hpp>
14 #include <boost/math/special_functions/ulp.hpp>
15 #include <boost/multiprecision/cpp_dec_float.hpp>
16 #include <boost/multiprecision/debug_adaptor.hpp>
17 #include <iostream>
18 #include <iomanip>
19 
20 #ifdef BOOST_MSVC
21 #pragma warning(disable:4127)
22 #endif
23 
24 template <class T>
is_normalized_value(const T & val)25 bool is_normalized_value(const T& val)
26 {
27    //
28    // Returns false if value has guard digits that are non-zero
29    //
30    boost::intmax_t shift = std::numeric_limits<T>::digits - ilogb(val) - 1;
31    T shifted = scalbn(val, shift);
32    return floor(shifted) == shifted;
33 }
34 
35 template <class T>
test_value(const T & val,const char * name)36 void test_value(const T& val, const char* name)
37 {
38    using namespace boost::math;
39    T upper = tools::max_value<T>();
40    T lower = -upper;
41 
42    std::cout << "Testing type " << name << " with initial value " << val << std::endl;
43 
44    BOOST_CHECK_EQUAL(float_distance(float_next(val), val), -1);
45    BOOST_CHECK(float_next(val) > val);
46    BOOST_CHECK_EQUAL(float_distance(float_prior(val), val), 1);
47    BOOST_CHECK(float_prior(val) < val);
48    BOOST_CHECK_EQUAL(float_distance((boost::math::nextafter)(val, upper), val), -1);
49    BOOST_CHECK((boost::math::nextafter)(val, upper) > val);
50    BOOST_CHECK_EQUAL(float_distance((boost::math::nextafter)(val, lower), val), 1);
51    BOOST_CHECK((boost::math::nextafter)(val, lower) < val);
52    BOOST_CHECK_EQUAL(float_distance(float_next(float_next(val)), val), -2);
53    BOOST_CHECK_EQUAL(float_distance(float_prior(float_prior(val)), val), 2);
54    BOOST_CHECK_EQUAL(float_distance(float_prior(float_prior(val)), float_next(float_next(val))), 4);
55    BOOST_CHECK_EQUAL(float_distance(float_prior(float_next(val)), val), 0);
56    BOOST_CHECK_EQUAL(float_distance(float_next(float_prior(val)), val), 0);
57    if (is_normalized_value(val))
58    {
59       BOOST_CHECK_EQUAL(float_prior(float_next(val)), val);
60       BOOST_CHECK_EQUAL(float_next(float_prior(val)), val);
61    }
62    BOOST_CHECK_EQUAL(float_distance(float_advance(val, 4), val), -4);
63    BOOST_CHECK_EQUAL(float_distance(float_advance(val, -4), val), 4);
64    if(std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == std::denorm_present))
65    {
66       BOOST_CHECK_EQUAL(float_distance(float_advance(float_next(float_next(val)), 4), float_next(float_next(val))), -4);
67       BOOST_CHECK_EQUAL(float_distance(float_advance(float_next(float_next(val)), -4), float_next(float_next(val))), 4);
68    }
69    if (is_normalized_value(val))
70    {
71       if (val > 0)
72       {
73          T n = val + ulp(val);
74          T fn = float_next(val);
75          if (n > fn)
76          {
77             BOOST_CHECK_LE(ulp(val), boost::math::tools::min_value<T>());
78          }
79          else
80          {
81             BOOST_CHECK_EQUAL(fn, n);
82          }
83       }
84       else if (val == 0)
85       {
86          BOOST_CHECK_GE(boost::math::tools::min_value<T>(), ulp(val));
87       }
88       else
89       {
90          T n = val - ulp(val);
91          T fp = float_prior(val);
92          if (n < fp)
93          {
94             BOOST_CHECK_LE(ulp(val), boost::math::tools::min_value<T>());
95          }
96          else
97          {
98             BOOST_CHECK_EQUAL(fp, n);
99          }
100       }
101    }
102 }
103 
104 template <class T>
test_values(const T & val,const char * name)105 void test_values(const T& val, const char* name)
106 {
107    static const T a = boost::lexical_cast<T>("1.3456724e22");
108    static const T b = boost::lexical_cast<T>("1.3456724e-22");
109    static const T z = 0;
110    static const T one = 1;
111    static const T radix = std::numeric_limits<T>::radix;
112 
113    std::cout << "Testing type " << name << std::endl;
114 
115    T den = (std::numeric_limits<T>::min)() / 4;
116    if(den != 0)
117    {
118       std::cout << "Denormals are active\n";
119    }
120    else
121    {
122       std::cout << "Denormals are flushed to zero.\n";
123    }
124 
125    test_value(a, name);
126    test_value(T(-a), name);
127    test_value(b, name);
128    test_value(T(-b), name);
129    test_value(T(b / 3), name);
130    test_value(T(-b / 3), name);
131    test_value(boost::math::tools::epsilon<T>(), name);
132    test_value(T(-boost::math::tools::epsilon<T>()), name);
133    test_value(boost::math::tools::min_value<T>(), name);
134    test_value(T(-boost::math::tools::min_value<T>()), name);
135    if (std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == std::denorm_present) && ((std::numeric_limits<T>::min)() / 2 != 0))
136    {
137       test_value(z, name);
138       test_value(T(-z), name);
139    }
140    test_value(one, name);
141    test_value(T(-one), name);
142    test_value(radix, name);
143    test_value(T(-radix), name);
144 
145    if(std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == std::denorm_present) && ((std::numeric_limits<T>::min)() / 2 != 0))
146    {
147       test_value(std::numeric_limits<T>::denorm_min(), name);
148       test_value(T(-std::numeric_limits<T>::denorm_min()), name);
149       test_value(T(2 * std::numeric_limits<T>::denorm_min()), name);
150       test_value(T(-2 * std::numeric_limits<T>::denorm_min()), name);
151    }
152 
153    static const int primes[] = {
154       11,     13,     17,     19,     23,     29,
155       31,     37,     41,     43,     47,     53,     59,     61,     67,     71,
156       73,     79,     83,     89,     97,    101,    103,    107,    109,    113,
157       127,    131,    137,    139,    149,    151,    157,    163,    167,    173,
158       179,    181,    191,    193,    197,    199,    211,    223,    227,    229,
159       233,    239,    241,    251,    257,    263,    269,    271,    277,    281,
160       283,    293,    307,    311,    313,    317,    331,    337,    347,    349,
161       353,    359,    367,    373,    379,    383,    389,    397,    401,    409,
162       419,    421,    431,    433,    439,    443,    449,    457,    461,    463,
163    };
164 
165    for(unsigned i = 0; i < sizeof(primes)/sizeof(primes[0]); ++i)
166    {
167       T v1 = val;
168       T v2 = val;
169       for(int j = 0; j < primes[i]; ++j)
170       {
171          v1 = boost::math::float_next(v1);
172          v2 = boost::math::float_prior(v2);
173       }
174       BOOST_CHECK_EQUAL(boost::math::float_distance(v1, val), -primes[i]);
175       BOOST_CHECK_EQUAL(boost::math::float_distance(v2, val), primes[i]);
176       BOOST_CHECK_EQUAL(boost::math::float_advance(val, primes[i]), v1);
177       BOOST_CHECK_EQUAL(boost::math::float_advance(val, -primes[i]), v2);
178    }
179    if(std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_infinity))
180    {
181       BOOST_CHECK_EQUAL(boost::math::float_prior(std::numeric_limits<T>::infinity()), (std::numeric_limits<T>::max)());
182       BOOST_CHECK_EQUAL(boost::math::float_next(-std::numeric_limits<T>::infinity()), -(std::numeric_limits<T>::max)());
183       BOOST_MATH_CHECK_THROW(boost::math::float_prior(-std::numeric_limits<T>::infinity()), std::domain_error);
184       BOOST_MATH_CHECK_THROW(boost::math::float_next(std::numeric_limits<T>::infinity()), std::domain_error);
185       if(boost::math::policies:: BOOST_MATH_OVERFLOW_ERROR_POLICY == boost::math::policies::throw_on_error)
186       {
187          BOOST_MATH_CHECK_THROW(boost::math::float_prior(-(std::numeric_limits<T>::max)()), std::overflow_error);
188          BOOST_MATH_CHECK_THROW(boost::math::float_next((std::numeric_limits<T>::max)()), std::overflow_error);
189       }
190       else
191       {
192          BOOST_CHECK_EQUAL(boost::math::float_prior(-(std::numeric_limits<T>::max)()), -std::numeric_limits<T>::infinity());
193          BOOST_CHECK_EQUAL(boost::math::float_next((std::numeric_limits<T>::max)()), std::numeric_limits<T>::infinity());
194       }
195    }
196 }
197 
BOOST_AUTO_TEST_CASE(test_main)198 BOOST_AUTO_TEST_CASE( test_main )
199 {
200    // Very slow, but debuggable:
201    //test_values(boost::multiprecision::number<boost::multiprecision::debug_adaptor<boost::multiprecision::cpp_dec_float_50::backend_type> >(0), "cpp_dec_float_50");
202 
203    // Faster, but no good for diagnosing the cause of any issues:
204    test_values(boost::multiprecision::cpp_dec_float_50(0), "cpp_dec_float_50");
205 }
206 
207 
208