]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /////////////////////////////////////////////////////////////// |
2 | // Copyright 2012 John Maddock. Distributed under the Boost | |
3 | // Software License, Version 1.0. (See accompanying file | |
92f5a8d4 | 4 | // LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt |
7c673cae FG |
5 | // |
6 | ||
7 | #ifdef _MSC_VER | |
92f5a8d4 | 8 | #define _SCL_SECURE_NO_WARNINGS |
7c673cae FG |
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> | |
b32b8144 FG |
17 | #include <boost/random/mersenne_twister.hpp> |
18 | #include <boost/random/uniform_int.hpp> | |
1e59de90 | 19 | #include <cstdint> |
b32b8144 | 20 | |
b32b8144 FG |
21 | template <class T> |
22 | T generate_random() | |
23 | { | |
92f5a8d4 | 24 | typedef int e_type; |
b32b8144 | 25 | static boost::random::mt19937 gen; |
92f5a8d4 TL |
26 | T val = gen(); |
27 | T prev_val = -1; | |
28 | while (val != prev_val) | |
b32b8144 FG |
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 | { | |
92f5a8d4 TL |
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) | |
b32b8144 FG |
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 | ||
92f5a8d4 TL |
67 | #if !defined(BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS) |
68 | ||
69 | if (check_extended) | |
b32b8144 FG |
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); | |
92f5a8d4 TL |
76 | diff1 = abs(l1 - val); |
77 | diff2 = abs(l2 - val); | |
78 | if (diff2 < diff1) | |
b32b8144 FG |
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 | } | |
b32b8144 | 92 | |
92f5a8d4 TL |
93 | #endif |
94 | } | |
7c673cae FG |
95 | |
96 | int main() | |
97 | { | |
98 | using namespace boost::multiprecision; | |
99 | ||
92f5a8d4 | 100 | cpp_int i(20); |
7c673cae FG |
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 | ||
92f5a8d4 | 106 | int1024_t i1024(45); |
7c673cae FG |
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 | ||
92f5a8d4 | 112 | uint1024_t ui1024(55); |
7c673cae FG |
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; | |
92f5a8d4 TL |
119 | i32_t i32(67); |
120 | cpp_bin_float_100 f100c(i32); | |
7c673cae FG |
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; | |
92f5a8d4 TL |
126 | ui32_t ui32(98); |
127 | cpp_bin_float_100 f100d(ui32); | |
7c673cae FG |
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; | |
92f5a8d4 TL |
133 | i64_t i64(67); |
134 | cpp_bin_float_100 f100e(i64); | |
7c673cae FG |
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; | |
92f5a8d4 TL |
140 | ui64_t ui64(98); |
141 | cpp_bin_float_100 f100f(ui64); | |
7c673cae FG |
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; | |
92f5a8d4 TL |
147 | i128_t i128(67); |
148 | cpp_bin_float_100 f100g(i128); | |
7c673cae FG |
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; | |
92f5a8d4 TL |
154 | ui128_t ui128(98); |
155 | cpp_bin_float_100 f100h(ui128); | |
7c673cae FG |
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: | |
1e59de90 | 167 | boost::multiprecision::number<boost::multiprecision::backends::cpp_bin_float<128, boost::multiprecision::backends::digit_base_2, void, std::int64_t> > ext_float("1e-646456978"); |
7c673cae FG |
168 | BOOST_CHECK_EQUAL(ext_float.convert_to<float>(), 0); |
169 | ||
b32b8144 FG |
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: | |
1e59de90 | 177 | ext_float = boost::multiprecision::number<boost::multiprecision::backends::cpp_bin_float<128, boost::multiprecision::backends::digit_base_2, void, std::int64_t> >("-1e-646456978"); |
b32b8144 FG |
178 | BOOST_CHECK_EQUAL(ext_float.convert_to<float>(), 0); |
179 | ext_float = (std::numeric_limits<double>::max)(); | |
180 | ext_float *= 16; | |
92f5a8d4 | 181 | if (std::numeric_limits<double>::has_infinity) |
b32b8144 FG |
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; | |
92f5a8d4 | 190 | if (std::numeric_limits<double>::has_infinity) |
b32b8144 FG |
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); | |
7c673cae | 206 | |
b32b8144 FG |
207 | r1 = ldexp(cpp_bin_float_50(0x8000017f), -31 - 127); |
208 | check_round(r1); | |
209 | r1 = -r1; | |
210 | check_round(r1); | |
211 | // | |
f67539c2 | 212 | // Check conversion to signed zero works OK: |
b32b8144 FG |
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); | |
92f5a8d4 | 232 | } while (ilogb(r1) > std::numeric_limits<double>::min_exponent - 5 - std::numeric_limits<double>::digits); |
b32b8144 FG |
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); | |
92f5a8d4 | 241 | } while (ilogb(r1) > std::numeric_limits<double>::min_exponent - 5 - std::numeric_limits<double>::digits); |
b32b8144 FG |
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); | |
92f5a8d4 | 253 | } while (ilogb(r1) > std::numeric_limits<double>::min_exponent - 5 - std::numeric_limits<double>::digits); |
b32b8144 FG |
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); | |
92f5a8d4 | 262 | } while (ilogb(r1) > std::numeric_limits<double>::min_exponent - 5 - std::numeric_limits<double>::digits); |
b32b8144 FG |
263 | // |
264 | // Test random conversions: | |
265 | // | |
92f5a8d4 | 266 | for (unsigned j = 0; j < 10000; ++j) |
b32b8144 FG |
267 | { |
268 | check_round(generate_random<cpp_bin_float_50>(), true); | |
269 | } | |
7c673cae | 270 | |
b32b8144 FG |
271 | return boost::report_errors(); |
272 | } |