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>
generate_random()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>
check_round(const T & val,bool check_extended=false)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
main()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 conversion 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 }
273