Imported Upstream version 1.72.0
[platform/upstream/boost.git] / libs / multiprecision / test / test_cpp_bin_float_conv.cpp
1 ///////////////////////////////////////////////////////////////
2 //  Copyright 2012 John Maddock. Distributed under the Boost
3 //  Software License, Version 1.0. (See accompanying file
4 //  LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
5 //
6
7 #ifdef _MSC_VER
8 #define _SCL_SECURE_NO_WARNINGS
9 #endif
10
11 #include <boost/detail/lightweight_test.hpp>
12 #include <boost/array.hpp>
13 #include "test.hpp"
14
15 #include <boost/multiprecision/cpp_int.hpp>
16 #include <boost/multiprecision/cpp_bin_float.hpp>
17 #include <boost/random/mersenne_twister.hpp>
18 #include <boost/random/uniform_int.hpp>
19 #include <boost/cstdint.hpp>
20
21 template <class T>
22 T generate_random()
23 {
24    typedef int                   e_type;
25    static boost::random::mt19937 gen;
26    T                             val      = gen();
27    T                             prev_val = -1;
28    while (val != prev_val)
29    {
30       val *= (gen.max)();
31       prev_val = val;
32       val += gen();
33    }
34    e_type e;
35    val = frexp(val, &e);
36
37    static boost::random::uniform_int_distribution<e_type> ui(-20, 20);
38    return ldexp(val, ui(gen));
39 }
40
41 template <class T>
42 void check_round(const T& val, bool check_extended = false)
43 {
44    double d1    = val.template convert_to<double>();
45    double d2    = boost::math::nextafter(d1, d1 < val ? DBL_MAX : -DBL_MAX);
46    T      diff1 = abs(d1 - val);
47    T      diff2 = abs(d2 - val);
48    if (diff2 < diff1)
49    {
50       // Some debugging code here...
51       std::cout << val.str() << std::endl;
52       std::cout << std::setprecision(18);
53       std::cout << d1 << std::endl;
54       std::cout << d2 << std::endl;
55       std::cout << diff1 << std::endl;
56       std::cout << diff2 << std::endl;
57       d1 = val.template convert_to<double>();
58    }
59    BOOST_CHECK(diff2 >= diff1);
60    BOOST_CHECK_EQUAL(boost::math::signbit(val), boost::math::signbit(d1));
61
62    float f1 = val.template convert_to<float>();
63    float f2 = boost::math::nextafter(f1, f1 < val ? FLT_MAX : -FLT_MAX);
64    BOOST_CHECK(((abs(f1 - val) <= abs(f2 - val))));
65    BOOST_CHECK_EQUAL(boost::math::signbit(val), boost::math::signbit(f1));
66
67 #if !defined(BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS)
68
69    if (check_extended)
70    {
71       //
72       // We should check long double as well:
73       //
74       long double l1 = val.template convert_to<long double>();
75       long double l2 = boost::math::nextafter(d1, d1 < val ? LDBL_MAX : -LDBL_MAX);
76       diff1          = abs(l1 - val);
77       diff2          = abs(l2 - val);
78       if (diff2 < diff1)
79       {
80          // Some debugging code here...
81          std::cout << val.str() << std::endl;
82          std::cout << std::setprecision(18);
83          std::cout << l1 << std::endl;
84          std::cout << l2 << std::endl;
85          std::cout << diff1 << std::endl;
86          std::cout << diff2 << std::endl;
87          l1 = val.template convert_to<long double>();
88       }
89       BOOST_CHECK(diff2 >= diff1);
90       BOOST_CHECK_EQUAL(boost::math::signbit(val), boost::math::signbit(l1));
91    }
92
93 #endif
94 }
95
96 int main()
97 {
98    using namespace boost::multiprecision;
99
100    cpp_int          i(20);
101    cpp_bin_float_50 f50(i);
102    BOOST_CHECK_EQUAL(f50, 20);
103    f50 = i.convert_to<cpp_bin_float_50>();
104    BOOST_CHECK_EQUAL(f50, 20);
105
106    int1024_t         i1024(45);
107    cpp_bin_float_100 f100(i1024);
108    BOOST_CHECK_EQUAL(f100, 45);
109    f100 = i1024.convert_to<cpp_bin_float_100>();
110    BOOST_CHECK_EQUAL(f100, 45);
111
112    uint1024_t        ui1024(55);
113    cpp_bin_float_100 f100b(ui1024);
114    BOOST_CHECK_EQUAL(f100b, 55);
115    f100b = ui1024.convert_to<cpp_bin_float_100>();
116    BOOST_CHECK_EQUAL(f100b, 55);
117
118    typedef number<cpp_int_backend<32, 32>, et_off> i32_t;
119    i32_t                                           i32(67);
120    cpp_bin_float_100                               f100c(i32);
121    BOOST_CHECK_EQUAL(f100c, 67);
122    f100c = i32.convert_to<cpp_bin_float_100>();
123    BOOST_CHECK_EQUAL(f100c, 67);
124
125    typedef number<cpp_int_backend<32, 32, unsigned_magnitude>, et_off> ui32_t;
126    ui32_t                                                              ui32(98);
127    cpp_bin_float_100                                                   f100d(ui32);
128    BOOST_CHECK_EQUAL(f100d, 98);
129    f100d = ui32.convert_to<cpp_bin_float_100>();
130    BOOST_CHECK_EQUAL(f100d, 98);
131
132    typedef number<cpp_int_backend<64, 64>, et_off> i64_t;
133    i64_t                                           i64(67);
134    cpp_bin_float_100                               f100e(i64);
135    BOOST_CHECK_EQUAL(f100e, 67);
136    f100e = i64.convert_to<cpp_bin_float_100>();
137    BOOST_CHECK_EQUAL(f100e, 67);
138
139    typedef number<cpp_int_backend<64, 64, unsigned_magnitude>, et_off> ui64_t;
140    ui64_t                                                              ui64(98);
141    cpp_bin_float_100                                                   f100f(ui64);
142    BOOST_CHECK_EQUAL(f100f, 98);
143    f100f = ui64.convert_to<cpp_bin_float_100>();
144    BOOST_CHECK_EQUAL(f100f, 98);
145
146    typedef number<cpp_int_backend<128, 128>, et_off> i128_t;
147    i128_t                                            i128(67);
148    cpp_bin_float_100                                 f100g(i128);
149    BOOST_CHECK_EQUAL(f100g, 67);
150    f100g = i128.convert_to<cpp_bin_float_100>();
151    BOOST_CHECK_EQUAL(f100g, 67);
152
153    typedef number<cpp_int_backend<128, 128, unsigned_magnitude>, et_off> ui128_t;
154    ui128_t                                                               ui128(98);
155    cpp_bin_float_100                                                     f100h(ui128);
156    BOOST_CHECK_EQUAL(f100h, 98);
157    f100h = ui128.convert_to<cpp_bin_float_100>();
158    BOOST_CHECK_EQUAL(f100h, 98);
159
160    cpp_bin_float_quad q = (std::numeric_limits<float>::min)();
161    BOOST_CHECK_EQUAL(q.convert_to<float>(), (std::numeric_limits<float>::min)());
162    q = (std::numeric_limits<float>::max)();
163    BOOST_CHECK_EQUAL(q.convert_to<float>(), (std::numeric_limits<float>::max)());
164    q = (std::numeric_limits<float>::denorm_min)();
165    BOOST_CHECK_EQUAL(q.convert_to<float>(), (std::numeric_limits<float>::denorm_min)());
166    // See https://svn.boost.org/trac/boost/ticket/12512:
167    boost::multiprecision::number<boost::multiprecision::backends::cpp_bin_float<128, boost::multiprecision::backends::digit_base_2, void, boost::int64_t> > ext_float("1e-646456978");
168    BOOST_CHECK_EQUAL(ext_float.convert_to<float>(), 0);
169
170    q = -(std::numeric_limits<float>::min)();
171    BOOST_CHECK_EQUAL(q.convert_to<float>(), -(std::numeric_limits<float>::min)());
172    q = -(std::numeric_limits<float>::max)();
173    BOOST_CHECK_EQUAL(q.convert_to<float>(), -(std::numeric_limits<float>::max)());
174    q = -(std::numeric_limits<float>::denorm_min)();
175    BOOST_CHECK_EQUAL(q.convert_to<float>(), -(std::numeric_limits<float>::denorm_min)());
176    // See https://svn.boost.org/trac/boost/ticket/12512:
177    ext_float = boost::multiprecision::number<boost::multiprecision::backends::cpp_bin_float<128, boost::multiprecision::backends::digit_base_2, void, boost::int64_t> >("-1e-646456978");
178    BOOST_CHECK_EQUAL(ext_float.convert_to<float>(), 0);
179    ext_float = (std::numeric_limits<double>::max)();
180    ext_float *= 16;
181    if (std::numeric_limits<double>::has_infinity)
182    {
183       BOOST_CHECK_EQUAL(ext_float.convert_to<double>(), std::numeric_limits<double>::infinity());
184    }
185    else
186    {
187       BOOST_CHECK_EQUAL(ext_float.convert_to<double>(), (std::numeric_limits<double>::max)());
188    }
189    ext_float = -ext_float;
190    if (std::numeric_limits<double>::has_infinity)
191    {
192       BOOST_CHECK_EQUAL(ext_float.convert_to<double>(), -std::numeric_limits<double>::infinity());
193    }
194    else
195    {
196       BOOST_CHECK_EQUAL(ext_float.convert_to<double>(), -(std::numeric_limits<double>::max)());
197    }
198    //
199    // Check for double rounding when the result would be a denorm.
200    // See https://svn.boost.org/trac/boost/ticket/12527
201    //
202    cpp_bin_float_50 r1 = ldexp(cpp_bin_float_50(0x8000000000000bffull), -63 - 1023);
203    check_round(r1);
204    r1 = -r1;
205    check_round(r1);
206
207    r1 = ldexp(cpp_bin_float_50(0x8000017f), -31 - 127);
208    check_round(r1);
209    r1 = -r1;
210    check_round(r1);
211    //
212    // Check convertion to signed zero works OK:
213    //
214    r1 = -ldexp(cpp_bin_float_50(1), -3000);
215    check_round(r1);
216    r1 = 0;
217    r1 = -r1;
218    BOOST_CHECK(boost::math::signbit(r1));
219    check_round(r1);
220    //
221    // Check boundary as the exponent drops below what a double can cope with
222    // but we will be rounding up:
223    //
224    r1 = 3;
225    r1 = ldexp(r1, std::numeric_limits<double>::min_exponent);
226    do
227    {
228       check_round(r1);
229       check_round(boost::math::float_next(r1));
230       check_round(boost::math::float_prior(r1));
231       r1 = ldexp(r1, -1);
232    } while (ilogb(r1) > std::numeric_limits<double>::min_exponent - 5 - std::numeric_limits<double>::digits);
233    r1 = -3;
234    r1 = ldexp(r1, std::numeric_limits<double>::min_exponent);
235    do
236    {
237       check_round(r1);
238       check_round(boost::math::float_next(r1));
239       check_round(boost::math::float_prior(r1));
240       r1 = ldexp(r1, -1);
241    } while (ilogb(r1) > std::numeric_limits<double>::min_exponent - 5 - std::numeric_limits<double>::digits);
242    //
243    // Again when not rounding up:
244    //
245    r1 = 1;
246    r1 = ldexp(r1, std::numeric_limits<double>::min_exponent);
247    do
248    {
249       check_round(r1);
250       check_round(boost::math::float_next(r1));
251       check_round(boost::math::float_prior(r1));
252       r1 = ldexp(r1, -1);
253    } while (ilogb(r1) > std::numeric_limits<double>::min_exponent - 5 - std::numeric_limits<double>::digits);
254    r1 = -1;
255    r1 = ldexp(r1, std::numeric_limits<double>::min_exponent);
256    do
257    {
258       check_round(r1);
259       check_round(boost::math::float_next(r1));
260       check_round(boost::math::float_prior(r1));
261       r1 = ldexp(r1, -1);
262    } while (ilogb(r1) > std::numeric_limits<double>::min_exponent - 5 - std::numeric_limits<double>::digits);
263    //
264    // Test random conversions:
265    //
266    for (unsigned j = 0; j < 10000; ++j)
267    {
268       check_round(generate_random<cpp_bin_float_50>(), true);
269    }
270
271    return boost::report_errors();
272 }