Imported Upstream version 1.72.0
[platform/upstream/boost.git] / libs / math / test / test_next_decimal.cpp
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>
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>
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>
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
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 diagnising the cause of any issues:
204    test_values(boost::multiprecision::cpp_dec_float_50(0), "cpp_dec_float_50");
205 }
206
207