]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/multiprecision/tommath.hpp
bump version to 18.2.4-pve3
[ceph.git] / ceph / src / boost / boost / multiprecision / tommath.hpp
CommitLineData
7c673cae 1///////////////////////////////////////////////////////////////////////////////
1e59de90
TL
2// Copyright 2011 John Maddock.
3// Copyright 2021 Matt Borland. Distributed under the Boost
7c673cae
FG
4// Software License, Version 1.0. (See accompanying file
5// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6
7#ifndef BOOST_MATH_MP_TOMMATH_BACKEND_HPP
8#define BOOST_MATH_MP_TOMMATH_BACKEND_HPP
9
1e59de90
TL
10#include <boost/multiprecision/detail/standalone_config.hpp>
11#include <boost/multiprecision/detail/fpclassify.hpp>
7c673cae
FG
12#include <boost/multiprecision/number.hpp>
13#include <boost/multiprecision/rational_adaptor.hpp>
14#include <boost/multiprecision/detail/integer_ops.hpp>
1e59de90
TL
15#include <boost/multiprecision/detail/hash.hpp>
16#include <boost/multiprecision/detail/no_exceptions_support.hpp>
17#include <boost/multiprecision/detail/assert.hpp>
18#include <cstdint>
7c673cae 19#include <tommath.h>
92f5a8d4 20#include <cctype>
7c673cae
FG
21#include <cmath>
22#include <limits>
23#include <climits>
1e59de90
TL
24#include <cstddef>
25#include <cstdlib>
26#include <string>
7c673cae 27
f67539c2
TL
28namespace boost {
29namespace multiprecision {
92f5a8d4 30namespace backends {
7c673cae 31
92f5a8d4 32namespace detail {
7c673cae 33
f67539c2
TL
34template <class ErrType>
35inline void check_tommath_result(ErrType v)
7c673cae 36{
92f5a8d4 37 if (v != MP_OKAY)
7c673cae 38 {
1e59de90 39 BOOST_MP_THROW_EXCEPTION(std::runtime_error(mp_error_to_string(v)));
7c673cae
FG
40 }
41}
42
92f5a8d4 43} // namespace detail
7c673cae
FG
44
45struct tommath_int;
46
47void eval_multiply(tommath_int& t, const tommath_int& o);
48void eval_add(tommath_int& t, const tommath_int& o);
49
50struct tommath_int
51{
1e59de90
TL
52 using signed_types = std::tuple<std::int32_t, long long> ;
53 using unsigned_types = std::tuple<std::uint32_t, unsigned long long>;
54 using float_types = std::tuple<long double> ;
7c673cae
FG
55
56 tommath_int()
57 {
58 detail::check_tommath_result(mp_init(&m_data));
59 }
60 tommath_int(const tommath_int& o)
61 {
62 detail::check_tommath_result(mp_init_copy(&m_data, const_cast< ::mp_int*>(&o.m_data)));
63 }
1e59de90
TL
64 // rvalues:
65 tommath_int(tommath_int&& o) noexcept
7c673cae 66 {
92f5a8d4 67 m_data = o.m_data;
7c673cae
FG
68 o.m_data.dp = 0;
69 }
92f5a8d4 70 tommath_int& operator=(tommath_int&& o)
7c673cae
FG
71 {
72 mp_exch(&m_data, &o.m_data);
73 return *this;
74 }
92f5a8d4 75 tommath_int& operator=(const tommath_int& o)
7c673cae 76 {
92f5a8d4 77 if (m_data.dp == 0)
7c673cae 78 detail::check_tommath_result(mp_init(&m_data));
92f5a8d4 79 if (o.m_data.dp)
7c673cae
FG
80 detail::check_tommath_result(mp_copy(const_cast< ::mp_int*>(&o.m_data), &m_data));
81 return *this;
82 }
1e59de90 83#ifndef mp_get_u64
f67539c2 84 // Pick off 32 bit chunks for mp_set_int:
1e59de90 85 tommath_int& operator=(unsigned long long i)
7c673cae 86 {
92f5a8d4 87 if (m_data.dp == 0)
7c673cae 88 detail::check_tommath_result(mp_init(&m_data));
1e59de90 89 unsigned long long mask = ((1uLL << 32) - 1);
f67539c2
TL
90 unsigned shift = 0;
91 ::mp_int t;
7c673cae
FG
92 detail::check_tommath_result(mp_init(&t));
93 mp_zero(&m_data);
92f5a8d4 94 while (i)
7c673cae
FG
95 {
96 detail::check_tommath_result(mp_set_int(&t, static_cast<unsigned>(i & mask)));
92f5a8d4 97 if (shift)
7c673cae
FG
98 detail::check_tommath_result(mp_mul_2d(&t, shift, &t));
99 detail::check_tommath_result((mp_add(&m_data, &t, &m_data)));
f67539c2
TL
100 shift += 32;
101 i >>= 32;
102 }
103 mp_clear(&t);
104 return *this;
105 }
106#elif !defined(ULLONG_MAX) || (ULLONG_MAX != 18446744073709551615uLL)
1e59de90
TL
107 // Pick off 64 bit chunks for mp_set_u64:
108 tommath_int& operator=(unsigned long long i)
f67539c2
TL
109 {
110 if (m_data.dp == 0)
111 detail::check_tommath_result(mp_init(&m_data));
1e59de90 112 if(sizeof(unsigned long long) * CHAR_BIT == 64)
f67539c2
TL
113 {
114 mp_set_u64(&m_data, i);
115 return *this;
116 }
1e59de90 117 unsigned long long mask = ((1uLL << 64) - 1);
f67539c2
TL
118 unsigned shift = 0;
119 ::mp_int t;
120 detail::check_tommath_result(mp_init(&t));
121 mp_zero(&m_data);
122 while (i)
123 {
1e59de90 124 detail::check_tommath_result(mp_set_u64(&t, static_cast<std::uint64_t>(i & mask)));
f67539c2
TL
125 if (shift)
126 detail::check_tommath_result(mp_mul_2d(&t, shift, &t));
127 detail::check_tommath_result((mp_add(&m_data, &t, &m_data)));
128 shift += 64;
129 i >>= 64;
7c673cae
FG
130 }
131 mp_clear(&t);
132 return *this;
133 }
f67539c2 134#else
1e59de90 135 tommath_int& operator=(unsigned long long i)
f67539c2
TL
136 {
137 if (m_data.dp == 0)
138 detail::check_tommath_result(mp_init(&m_data));
139 mp_set_u64(&m_data, i);
140 return *this;
141 }
142#endif
1e59de90 143 tommath_int& operator=(long long i)
7c673cae 144 {
92f5a8d4 145 if (m_data.dp == 0)
7c673cae
FG
146 detail::check_tommath_result(mp_init(&m_data));
147 bool neg = i < 0;
92f5a8d4
TL
148 *this = boost::multiprecision::detail::unsigned_abs(i);
149 if (neg)
7c673cae
FG
150 detail::check_tommath_result(mp_neg(&m_data, &m_data));
151 return *this;
152 }
1e59de90
TL
153#ifdef BOOST_HAS_INT128
154 // Pick off 64 bit chunks for mp_set_u64:
155 tommath_int& operator=(uint128_type i)
156 {
157 if (m_data.dp == 0)
158 detail::check_tommath_result(mp_init(&m_data));
159
160 int128_type mask = ((static_cast<uint128_type>(1u) << 64) - 1);
161 unsigned shift = 0;
162 ::mp_int t;
163 detail::check_tommath_result(mp_init(&t));
164 mp_zero(&m_data);
165 while (i)
166 {
167#ifndef mp_get_u32
168 detail::check_tommath_result(mp_set_long_long(&t, static_cast<std::uint64_t>(i & mask)));
169#else
170 mp_set_u64(&t, static_cast<std::uint64_t>(i & mask));
171#endif
172 if (shift)
173 detail::check_tommath_result(mp_mul_2d(&t, shift, &t));
174 detail::check_tommath_result((mp_add(&m_data, &t, &m_data)));
175 shift += 64;
176 i >>= 64;
177 }
178 mp_clear(&t);
179 return *this;
180 }
181 tommath_int& operator=(int128_type i)
182 {
183 if (m_data.dp == 0)
184 detail::check_tommath_result(mp_init(&m_data));
185 bool neg = i < 0;
186 *this = boost::multiprecision::detail::unsigned_abs(i);
187 if (neg)
188 detail::check_tommath_result(mp_neg(&m_data, &m_data));
189 return *this;
190 }
191#endif
7c673cae
FG
192 //
193 // Note that although mp_set_int takes an unsigned long as an argument
194 // it only sets the first 32-bits to the result, and ignores the rest.
195 // So use uint32_t as the largest type to pass to this function.
196 //
1e59de90 197 tommath_int& operator=(std::uint32_t i)
7c673cae 198 {
92f5a8d4 199 if (m_data.dp == 0)
7c673cae 200 detail::check_tommath_result(mp_init(&m_data));
1e59de90 201#ifndef mp_get_u32
7c673cae 202 detail::check_tommath_result((mp_set_int(&m_data, i)));
f67539c2
TL
203#else
204 mp_set_u32(&m_data, i);
205#endif
7c673cae
FG
206 return *this;
207 }
1e59de90 208 tommath_int& operator=(std::int32_t i)
7c673cae 209 {
92f5a8d4 210 if (m_data.dp == 0)
7c673cae
FG
211 detail::check_tommath_result(mp_init(&m_data));
212 bool neg = i < 0;
92f5a8d4
TL
213 *this = boost::multiprecision::detail::unsigned_abs(i);
214 if (neg)
7c673cae
FG
215 detail::check_tommath_result(mp_neg(&m_data, &m_data));
216 return *this;
217 }
1e59de90
TL
218 template <class F>
219 tommath_int& assign_float(F a)
7c673cae 220 {
1e59de90 221 BOOST_MP_FLOAT128_USING using std::floor; using std::frexp; using std::ldexp;
7c673cae 222
92f5a8d4 223 if (m_data.dp == 0)
7c673cae
FG
224 detail::check_tommath_result(mp_init(&m_data));
225
92f5a8d4
TL
226 if (a == 0)
227 {
1e59de90 228#ifndef mp_get_u32
7c673cae 229 detail::check_tommath_result(mp_set_int(&m_data, 0));
f67539c2
TL
230#else
231 mp_set_i32(&m_data, 0);
232#endif
7c673cae
FG
233 return *this;
234 }
235
92f5a8d4
TL
236 if (a == 1)
237 {
1e59de90 238#ifndef mp_get_u32
7c673cae 239 detail::check_tommath_result(mp_set_int(&m_data, 1));
f67539c2
TL
240#else
241 mp_set_i32(&m_data, 1);
242#endif
7c673cae
FG
243 return *this;
244 }
245
1e59de90
TL
246 BOOST_MP_ASSERT(!BOOST_MP_ISINF(a));
247 BOOST_MP_ASSERT(!BOOST_MP_ISNAN(a));
7c673cae 248
92f5a8d4 249 int e;
1e59de90
TL
250 F f, term;
251#ifndef mp_get_u32
7c673cae 252 detail::check_tommath_result(mp_set_int(&m_data, 0u));
f67539c2
TL
253#else
254 mp_set_i32(&m_data, 0);
255#endif
7c673cae
FG
256 ::mp_int t;
257 detail::check_tommath_result(mp_init(&t));
258
259 f = frexp(a, &e);
260
1e59de90
TL
261#ifdef MP_DIGIT_BIT
262 constexpr const int shift = std::numeric_limits<int>::digits - 1;
263 using part_type = int ;
f67539c2 264#else
1e59de90
TL
265 constexpr const int shift = std::numeric_limits<std::int64_t>::digits - 1;
266 using part_type = std::int64_t;
f67539c2 267#endif
7c673cae 268
92f5a8d4 269 while (f)
7c673cae
FG
270 {
271 // extract int sized bits from f:
92f5a8d4 272 f = ldexp(f, shift);
7c673cae
FG
273 term = floor(f);
274 e -= shift;
275 detail::check_tommath_result(mp_mul_2d(&m_data, shift, &m_data));
92f5a8d4 276 if (term > 0)
7c673cae 277 {
1e59de90 278#ifndef mp_get_u64
f67539c2
TL
279 detail::check_tommath_result(mp_set_int(&t, static_cast<part_type>(term)));
280#else
281 mp_set_i64(&t, static_cast<part_type>(term));
282#endif
7c673cae
FG
283 detail::check_tommath_result(mp_add(&m_data, &t, &m_data));
284 }
285 else
286 {
1e59de90 287#ifndef mp_get_u64
f67539c2
TL
288 detail::check_tommath_result(mp_set_int(&t, static_cast<part_type>(-term)));
289#else
290 mp_set_i64(&t, static_cast<part_type>(-term));
291#endif
7c673cae
FG
292 detail::check_tommath_result(mp_sub(&m_data, &t, &m_data));
293 }
294 f -= term;
295 }
92f5a8d4 296 if (e > 0)
7c673cae 297 detail::check_tommath_result(mp_mul_2d(&m_data, e, &m_data));
92f5a8d4 298 else if (e < 0)
7c673cae
FG
299 {
300 tommath_int t2;
301 detail::check_tommath_result(mp_div_2d(&m_data, -e, &m_data, &t2.data()));
302 }
303 mp_clear(&t);
304 return *this;
305 }
1e59de90
TL
306 tommath_int& operator=(long double a)
307 {
308 return assign_float(a);
309 }
310#ifdef BOOST_HAS_FLOAT128
311 tommath_int& operator= (float128_type a)
312 {
313 return assign_float(a);
314 }
315#endif
92f5a8d4 316 tommath_int& operator=(const char* s)
7c673cae
FG
317 {
318 //
319 // We don't use libtommath's own routine because it doesn't error check the input :-(
320 //
92f5a8d4 321 if (m_data.dp == 0)
7c673cae 322 detail::check_tommath_result(mp_init(&m_data));
92f5a8d4 323 std::size_t n = s ? std::strlen(s) : 0;
1e59de90 324 *this = static_cast<std::uint32_t>(0u);
7c673cae 325 unsigned radix = 10;
92f5a8d4
TL
326 bool isneg = false;
327 if (n && (*s == '-'))
7c673cae
FG
328 {
329 --n;
330 ++s;
331 isneg = true;
332 }
92f5a8d4 333 if (n && (*s == '0'))
7c673cae 334 {
92f5a8d4 335 if ((n > 1) && ((s[1] == 'x') || (s[1] == 'X')))
7c673cae
FG
336 {
337 radix = 16;
92f5a8d4 338 s += 2;
7c673cae
FG
339 n -= 2;
340 }
341 else
342 {
343 radix = 8;
344 n -= 1;
345 }
346 }
92f5a8d4 347 if (n)
7c673cae 348 {
92f5a8d4 349 if (radix == 8 || radix == 16)
7c673cae 350 {
f67539c2 351 unsigned shift = radix == 8 ? 3 : 4;
1e59de90 352#ifndef MP_DIGIT_BIT
f67539c2
TL
353 unsigned block_count = DIGIT_BIT / shift;
354#else
355 unsigned block_count = MP_DIGIT_BIT / shift;
356#endif
92f5a8d4 357 unsigned block_shift = shift * block_count;
1e59de90 358 unsigned long long val, block;
92f5a8d4 359 while (*s)
7c673cae
FG
360 {
361 block = 0;
92f5a8d4 362 for (unsigned i = 0; (i < block_count); ++i)
7c673cae 363 {
92f5a8d4 364 if (*s >= '0' && *s <= '9')
7c673cae 365 val = *s - '0';
92f5a8d4 366 else if (*s >= 'a' && *s <= 'f')
7c673cae 367 val = 10 + *s - 'a';
92f5a8d4 368 else if (*s >= 'A' && *s <= 'F')
7c673cae
FG
369 val = 10 + *s - 'A';
370 else
371 val = 400;
92f5a8d4 372 if (val > radix)
7c673cae 373 {
1e59de90 374 BOOST_MP_THROW_EXCEPTION(std::runtime_error("Unexpected content found while parsing character string."));
7c673cae
FG
375 }
376 block <<= shift;
377 block |= val;
92f5a8d4 378 if (!*++s)
7c673cae
FG
379 {
380 // final shift is different:
381 block_shift = (i + 1) * shift;
382 break;
383 }
384 }
385 detail::check_tommath_result(mp_mul_2d(&data(), block_shift, &data()));
92f5a8d4 386 if (data().used)
7c673cae
FG
387 data().dp[0] |= block;
388 else
389 *this = block;
390 }
391 }
392 else
393 {
394 // Base 10, we extract blocks of size 10^9 at a time, that way
395 // the number of multiplications is kept to a minimum:
1e59de90 396 std::uint32_t block_mult = 1000000000;
92f5a8d4 397 while (*s)
7c673cae 398 {
1e59de90 399 std::uint32_t block = 0;
92f5a8d4 400 for (unsigned i = 0; i < 9; ++i)
7c673cae 401 {
1e59de90 402 std::uint32_t val;
92f5a8d4 403 if (*s >= '0' && *s <= '9')
7c673cae
FG
404 val = *s - '0';
405 else
1e59de90 406 BOOST_MP_THROW_EXCEPTION(std::runtime_error("Unexpected character encountered in input."));
7c673cae
FG
407 block *= 10;
408 block += val;
92f5a8d4 409 if (!*++s)
7c673cae 410 {
1e59de90 411 constexpr const std::uint32_t block_multiplier[9] = {10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
92f5a8d4 412 block_mult = block_multiplier[i];
7c673cae
FG
413 break;
414 }
415 }
416 tommath_int t;
417 t = block_mult;
418 eval_multiply(*this, t);
419 t = block;
420 eval_add(*this, t);
421 }
422 }
423 }
92f5a8d4 424 if (isneg)
7c673cae
FG
425 this->negate();
426 return *this;
427 }
92f5a8d4 428 std::string str(std::streamsize /*digits*/, std::ios_base::fmtflags f) const
7c673cae 429 {
1e59de90 430 BOOST_MP_ASSERT(m_data.dp);
7c673cae 431 int base = 10;
92f5a8d4 432 if ((f & std::ios_base::oct) == std::ios_base::oct)
7c673cae 433 base = 8;
92f5a8d4 434 else if ((f & std::ios_base::hex) == std::ios_base::hex)
7c673cae
FG
435 base = 16;
436 //
437 // sanity check, bases 8 and 16 are only available for positive numbers:
438 //
92f5a8d4 439 if ((base != 10) && m_data.sign)
1e59de90
TL
440 BOOST_MP_THROW_EXCEPTION(std::runtime_error("Formatted output in bases 8 or 16 is only available for positive numbers"));
441
7c673cae
FG
442 int s;
443 detail::check_tommath_result(mp_radix_size(const_cast< ::mp_int*>(&m_data), base, &s));
1e59de90
TL
444 std::unique_ptr<char[]> a(new char[s + 1]);
445#ifndef mp_to_binary
92f5a8d4 446 detail::check_tommath_result(mp_toradix_n(const_cast< ::mp_int*>(&m_data), a.get(), base, s + 1));
f67539c2
TL
447#else
448 std::size_t written;
449 detail::check_tommath_result(mp_to_radix(&m_data, a.get(), s + 1, &written, base));
450#endif
7c673cae 451 std::string result = a.get();
92f5a8d4
TL
452 if (f & std::ios_base::uppercase)
453 for (size_t i = 0; i < result.length(); ++i)
454 result[i] = std::toupper(result[i]);
455 if ((base != 10) && (f & std::ios_base::showbase))
7c673cae 456 {
92f5a8d4
TL
457 int pos = result[0] == '-' ? 1 : 0;
458 const char* pp = base == 8 ? "0" : (f & std::ios_base::uppercase) ? "0X" : "0x";
7c673cae
FG
459 result.insert(static_cast<std::string::size_type>(pos), pp);
460 }
92f5a8d4 461 if ((f & std::ios_base::showpos) && (result[0] != '-'))
7c673cae 462 result.insert(static_cast<std::string::size_type>(0), 1, '+');
f67539c2
TL
463 if (((f & std::ios_base::uppercase) == 0) && (base == 16))
464 {
465 for (std::size_t i = 0; i < result.size(); ++i)
466 result[i] = std::tolower(result[i]);
467 }
7c673cae
FG
468 return result;
469 }
470 ~tommath_int()
471 {
92f5a8d4 472 if (m_data.dp)
7c673cae
FG
473 mp_clear(&m_data);
474 }
475 void negate()
476 {
1e59de90 477 BOOST_MP_ASSERT(m_data.dp);
f67539c2 478 detail::check_tommath_result(mp_neg(&m_data, &m_data));
7c673cae 479 }
92f5a8d4 480 int compare(const tommath_int& o) const
7c673cae 481 {
1e59de90 482 BOOST_MP_ASSERT(m_data.dp && o.m_data.dp);
7c673cae
FG
483 return mp_cmp(const_cast< ::mp_int*>(&m_data), const_cast< ::mp_int*>(&o.m_data));
484 }
485 template <class V>
92f5a8d4 486 int compare(V v) const
7c673cae
FG
487 {
488 tommath_int d;
489 tommath_int t(*this);
490 detail::check_tommath_result(mp_shrink(&t.data()));
491 d = v;
492 return t.compare(d);
493 }
92f5a8d4
TL
494 ::mp_int& data()
495 {
1e59de90 496 BOOST_MP_ASSERT(m_data.dp);
92f5a8d4 497 return m_data;
7c673cae 498 }
92f5a8d4
TL
499 const ::mp_int& data() const
500 {
1e59de90 501 BOOST_MP_ASSERT(m_data.dp);
92f5a8d4 502 return m_data;
7c673cae 503 }
1e59de90 504 void swap(tommath_int& o) noexcept
7c673cae
FG
505 {
506 mp_exch(&m_data, &o.data());
507 }
92f5a8d4
TL
508
509 protected:
7c673cae
FG
510 ::mp_int m_data;
511};
512
1e59de90 513#ifndef mp_isneg
92f5a8d4
TL
514#define BOOST_MP_TOMMATH_BIT_OP_CHECK(x) \
515 if (SIGN(&x.data())) \
1e59de90 516 BOOST_MP_THROW_EXCEPTION(std::runtime_error("Bitwise operations on libtommath negative valued integers are disabled as they produce unpredictable results"))
f67539c2
TL
517#else
518#define BOOST_MP_TOMMATH_BIT_OP_CHECK(x) \
519 if (mp_isneg(&x.data())) \
1e59de90 520 BOOST_MP_THROW_EXCEPTION(std::runtime_error("Bitwise operations on libtommath negative valued integers are disabled as they produce unpredictable results"))
f67539c2 521#endif
7c673cae
FG
522
523int eval_get_sign(const tommath_int& val);
524
525inline void eval_add(tommath_int& t, const tommath_int& o)
526{
527 detail::check_tommath_result(mp_add(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
528}
529inline void eval_subtract(tommath_int& t, const tommath_int& o)
530{
531 detail::check_tommath_result(mp_sub(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
532}
533inline void eval_multiply(tommath_int& t, const tommath_int& o)
534{
535 detail::check_tommath_result(mp_mul(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
536}
537inline void eval_divide(tommath_int& t, const tommath_int& o)
538{
539 using default_ops::eval_is_zero;
540 tommath_int temp;
92f5a8d4 541 if (eval_is_zero(o))
1e59de90 542 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Integer division by zero"));
7c673cae
FG
543 detail::check_tommath_result(mp_div(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data(), &temp.data()));
544}
545inline void eval_modulus(tommath_int& t, const tommath_int& o)
546{
547 using default_ops::eval_is_zero;
92f5a8d4 548 if (eval_is_zero(o))
1e59de90 549 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Integer division by zero"));
92f5a8d4 550 bool neg = eval_get_sign(t) < 0;
7c673cae
FG
551 bool neg2 = eval_get_sign(o) < 0;
552 detail::check_tommath_result(mp_mod(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
92f5a8d4 553 if ((neg != neg2) && (eval_get_sign(t) != 0))
7c673cae
FG
554 {
555 t.negate();
556 detail::check_tommath_result(mp_add(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
557 t.negate();
558 }
92f5a8d4 559 else if (neg && (t.compare(o) == 0))
7c673cae
FG
560 {
561 mp_zero(&t.data());
562 }
563}
564template <class UI>
565inline void eval_left_shift(tommath_int& t, UI i)
566{
567 detail::check_tommath_result(mp_mul_2d(&t.data(), static_cast<unsigned>(i), &t.data()));
568}
569template <class UI>
570inline void eval_right_shift(tommath_int& t, UI i)
571{
7c673cae 572 using default_ops::eval_decrement;
92f5a8d4
TL
573 using default_ops::eval_increment;
574 bool neg = eval_get_sign(t) < 0;
7c673cae 575 tommath_int d;
92f5a8d4 576 if (neg)
7c673cae
FG
577 eval_increment(t);
578 detail::check_tommath_result(mp_div_2d(&t.data(), static_cast<unsigned>(i), &t.data(), &d.data()));
92f5a8d4 579 if (neg)
7c673cae
FG
580 eval_decrement(t);
581}
582template <class UI>
583inline void eval_left_shift(tommath_int& t, const tommath_int& v, UI i)
584{
585 detail::check_tommath_result(mp_mul_2d(const_cast< ::mp_int*>(&v.data()), static_cast<unsigned>(i), &t.data()));
586}
587/*
588template <class UI>
589inline void eval_right_shift(tommath_int& t, const tommath_int& v, UI i)
590{
591 tommath_int d;
592 detail::check_tommath_result(mp_div_2d(const_cast< ::mp_int*>(&v.data()), static_cast<unsigned long>(i), &t.data(), &d.data()));
593}
594*/
595inline void eval_bitwise_and(tommath_int& result, const tommath_int& v)
596{
597 BOOST_MP_TOMMATH_BIT_OP_CHECK(result);
598 BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
599 detail::check_tommath_result(mp_and(&result.data(), const_cast< ::mp_int*>(&v.data()), &result.data()));
600}
601
602inline void eval_bitwise_or(tommath_int& result, const tommath_int& v)
603{
604 BOOST_MP_TOMMATH_BIT_OP_CHECK(result);
605 BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
606 detail::check_tommath_result(mp_or(&result.data(), const_cast< ::mp_int*>(&v.data()), &result.data()));
607}
608
609inline void eval_bitwise_xor(tommath_int& result, const tommath_int& v)
610{
611 BOOST_MP_TOMMATH_BIT_OP_CHECK(result);
612 BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
613 detail::check_tommath_result(mp_xor(&result.data(), const_cast< ::mp_int*>(&v.data()), &result.data()));
614}
615
616inline void eval_add(tommath_int& t, const tommath_int& p, const tommath_int& o)
617{
618 detail::check_tommath_result(mp_add(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data()));
619}
620inline void eval_subtract(tommath_int& t, const tommath_int& p, const tommath_int& o)
621{
622 detail::check_tommath_result(mp_sub(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data()));
623}
624inline void eval_multiply(tommath_int& t, const tommath_int& p, const tommath_int& o)
625{
626 detail::check_tommath_result(mp_mul(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data()));
627}
628inline void eval_divide(tommath_int& t, const tommath_int& p, const tommath_int& o)
629{
630 using default_ops::eval_is_zero;
631 tommath_int d;
92f5a8d4 632 if (eval_is_zero(o))
1e59de90 633 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Integer division by zero"));
7c673cae
FG
634 detail::check_tommath_result(mp_div(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data(), &d.data()));
635}
636inline void eval_modulus(tommath_int& t, const tommath_int& p, const tommath_int& o)
637{
638 using default_ops::eval_is_zero;
92f5a8d4 639 if (eval_is_zero(o))
1e59de90 640 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Integer division by zero"));
92f5a8d4 641 bool neg = eval_get_sign(p) < 0;
7c673cae
FG
642 bool neg2 = eval_get_sign(o) < 0;
643 detail::check_tommath_result(mp_mod(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data()));
92f5a8d4 644 if ((neg != neg2) && (eval_get_sign(t) != 0))
7c673cae
FG
645 {
646 t.negate();
647 detail::check_tommath_result(mp_add(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
648 t.negate();
649 }
92f5a8d4 650 else if (neg && (t.compare(o) == 0))
7c673cae
FG
651 {
652 mp_zero(&t.data());
653 }
654}
655
656inline void eval_bitwise_and(tommath_int& result, const tommath_int& u, const tommath_int& v)
657{
658 BOOST_MP_TOMMATH_BIT_OP_CHECK(u);
659 BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
660 detail::check_tommath_result(mp_and(const_cast< ::mp_int*>(&u.data()), const_cast< ::mp_int*>(&v.data()), &result.data()));
661}
662
663inline void eval_bitwise_or(tommath_int& result, const tommath_int& u, const tommath_int& v)
664{
665 BOOST_MP_TOMMATH_BIT_OP_CHECK(u);
666 BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
667 detail::check_tommath_result(mp_or(const_cast< ::mp_int*>(&u.data()), const_cast< ::mp_int*>(&v.data()), &result.data()));
668}
669
670inline void eval_bitwise_xor(tommath_int& result, const tommath_int& u, const tommath_int& v)
671{
672 BOOST_MP_TOMMATH_BIT_OP_CHECK(u);
673 BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
674 detail::check_tommath_result(mp_xor(const_cast< ::mp_int*>(&u.data()), const_cast< ::mp_int*>(&v.data()), &result.data()));
675}
676/*
677inline void eval_complement(tommath_int& result, const tommath_int& u)
678{
679 //
680 // Although this code works, it doesn't really do what the user might expect....
681 // and it's hard to see how it ever could. Disabled for now:
682 //
683 result = u;
684 for(int i = 0; i < result.data().used; ++i)
685 {
686 result.data().dp[i] = MP_MASK & ~(result.data().dp[i]);
687 }
688 //
689 // We now need to pad out the left of the value with 1's to round up to a whole number of
690 // CHAR_BIT * sizeof(mp_digit) units. Otherwise we'll end up with a very strange number of
691 // bits set!
692 //
693 unsigned shift = result.data().used * DIGIT_BIT; // How many bits we're actually using
694 // How many bits we actually need, reduced by one to account for a mythical sign bit:
695 int padding = result.data().used * std::numeric_limits<mp_digit>::digits - shift - 1;
696 while(padding >= std::numeric_limits<mp_digit>::digits)
697 padding -= std::numeric_limits<mp_digit>::digits;
698
699 // Create a mask providing the extra bits we need and add to result:
700 tommath_int mask;
1e59de90 701 mask = static_cast<long long>((1u << padding) - 1);
7c673cae
FG
702 eval_left_shift(mask, shift);
703 add(result, mask);
704}
705*/
706inline bool eval_is_zero(const tommath_int& val)
707{
708 return mp_iszero(&val.data());
709}
710inline int eval_get_sign(const tommath_int& val)
711{
1e59de90 712#ifndef mp_isneg
7c673cae 713 return mp_iszero(&val.data()) ? 0 : SIGN(&val.data()) ? -1 : 1;
f67539c2
TL
714#else
715 return mp_iszero(&val.data()) ? 0 : mp_isneg(&val.data()) ? -1 : 1;
716#endif
7c673cae 717}
1e59de90
TL
718
719inline void eval_convert_to(unsigned long long* result, const tommath_int& val)
720{
721 if (mp_isneg(&val.data()))
722 {
723 BOOST_MP_THROW_EXCEPTION(std::range_error("Converting negative arbitrary precision value to unsigned."));
724 }
725#ifdef MP_DEPRECATED
726 *result = mp_get_ull(&val.data());
727#else
728 *result = mp_get_long_long(const_cast<mp_int*>(&val.data()));
729#endif
730}
731
732inline void eval_convert_to(long long* result, const tommath_int& val)
733{
734 if (!mp_iszero(&val.data()) && (mp_count_bits(const_cast<::mp_int*>(&val.data())) > std::numeric_limits<long long>::digits))
735 {
736 *result = mp_isneg(&val.data()) ? (std::numeric_limits<long long>::min)() : (std::numeric_limits<long long>::max)();
737 return;
738 }
739#ifdef MP_DEPRECATED
740 unsigned long long r = mp_get_mag_ull(&val.data());
741#else
742 unsigned long long r = mp_get_long_long(const_cast<mp_int*>(&val.data()));
743#endif
744 if (mp_isneg(&val.data()))
745 *result = -static_cast<long long>(r);
746 else
747 *result = r;
748}
749
750#ifdef BOOST_HAS_INT128
751inline void eval_convert_to(uint128_type* result, const tommath_int& val)
752{
753#ifdef MP_DEPRECATED
754 if (mp_ubin_size(&val.data()) > sizeof(uint128_type))
755 {
756 *result = ~static_cast<uint128_type>(0);
757 return;
758 }
759 unsigned char buf[sizeof(uint128_type)];
760 std::size_t len;
761 detail::check_tommath_result(mp_to_ubin(&val.data(), buf, sizeof(buf), &len));
762 *result = 0;
763 for (std::size_t i = 0; i < len; ++i)
764 {
765 *result <<= CHAR_BIT;
766 *result |= buf[i];
767 }
768#else
769 std::size_t len = mp_unsigned_bin_size(const_cast<mp_int*>(&val.data()));
770 if (len > sizeof(uint128_type))
771 {
772 *result = ~static_cast<uint128_type>(0);
773 return;
774 }
775 unsigned char buf[sizeof(uint128_type)];
776 detail::check_tommath_result(mp_to_unsigned_bin(const_cast<mp_int*>(&val.data()), buf));
777 *result = 0;
778 for (std::size_t i = 0; i < len; ++i)
779 {
780 *result <<= CHAR_BIT;
781 *result |= buf[i];
782 }
783#endif
784}
785inline void eval_convert_to(int128_type* result, const tommath_int& val)
7c673cae 786{
1e59de90
TL
787 uint128_type r;
788 eval_convert_to(&r, val);
789 if (mp_isneg(&val.data()))
790 *result = -static_cast<int128_type>(r);
791 else
792 *result = r;
7c673cae 793}
1e59de90
TL
794#endif
795#if defined(BOOST_HAS_FLOAT128)
796inline void eval_convert_to(float128_type* result, const tommath_int& val) noexcept
7c673cae 797{
1e59de90 798 *result = float128_procs::strtoflt128(val.str(0, std::ios_base::scientific).c_str(), nullptr);
7c673cae 799}
1e59de90
TL
800#endif
801inline void eval_convert_to(long double* result, const tommath_int& val) noexcept
7c673cae 802{
1e59de90 803 *result = std::strtold(val.str(0, std::ios_base::scientific).c_str(), nullptr);
7c673cae 804}
1e59de90 805inline void eval_convert_to(double* result, const tommath_int& val) noexcept
7c673cae 806{
1e59de90 807 *result = std::strtod(val.str(0, std::ios_base::scientific).c_str(), nullptr);
7c673cae 808}
1e59de90
TL
809inline void eval_convert_to(float* result, const tommath_int& val) noexcept
810{
811 *result = std::strtof(val.str(0, std::ios_base::scientific).c_str(), nullptr);
812}
813
814
7c673cae
FG
815inline void eval_abs(tommath_int& result, const tommath_int& val)
816{
817 detail::check_tommath_result(mp_abs(const_cast< ::mp_int*>(&val.data()), &result.data()));
818}
819inline void eval_gcd(tommath_int& result, const tommath_int& a, const tommath_int& b)
820{
821 detail::check_tommath_result(mp_gcd(const_cast< ::mp_int*>(&a.data()), const_cast< ::mp_int*>(&b.data()), const_cast< ::mp_int*>(&result.data())));
822}
823inline void eval_lcm(tommath_int& result, const tommath_int& a, const tommath_int& b)
824{
825 detail::check_tommath_result(mp_lcm(const_cast< ::mp_int*>(&a.data()), const_cast< ::mp_int*>(&b.data()), const_cast< ::mp_int*>(&result.data())));
826}
827inline void eval_powm(tommath_int& result, const tommath_int& base, const tommath_int& p, const tommath_int& m)
828{
92f5a8d4 829 if (eval_get_sign(p) < 0)
7c673cae 830 {
1e59de90 831 BOOST_MP_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
7c673cae
FG
832 }
833 detail::check_tommath_result(mp_exptmod(const_cast< ::mp_int*>(&base.data()), const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&m.data()), &result.data()));
834}
835
92f5a8d4
TL
836inline void eval_qr(const tommath_int& x, const tommath_int& y,
837 tommath_int& q, tommath_int& r)
7c673cae
FG
838{
839 detail::check_tommath_result(mp_div(const_cast< ::mp_int*>(&x.data()), const_cast< ::mp_int*>(&y.data()), &q.data(), &r.data()));
840}
841
1e59de90 842inline std::size_t eval_lsb(const tommath_int& val)
7c673cae
FG
843{
844 int c = eval_get_sign(val);
92f5a8d4 845 if (c == 0)
7c673cae 846 {
1e59de90 847 BOOST_MP_THROW_EXCEPTION(std::domain_error("No bits were set in the operand."));
7c673cae 848 }
92f5a8d4 849 if (c < 0)
7c673cae 850 {
1e59de90 851 BOOST_MP_THROW_EXCEPTION(std::domain_error("Testing individual bits in negative values is not supported - results are undefined."));
7c673cae
FG
852 }
853 return mp_cnt_lsb(const_cast< ::mp_int*>(&val.data()));
854}
855
1e59de90 856inline std::size_t eval_msb(const tommath_int& val)
7c673cae
FG
857{
858 int c = eval_get_sign(val);
92f5a8d4 859 if (c == 0)
7c673cae 860 {
1e59de90 861 BOOST_MP_THROW_EXCEPTION(std::domain_error("No bits were set in the operand."));
7c673cae 862 }
92f5a8d4 863 if (c < 0)
7c673cae 864 {
1e59de90 865 BOOST_MP_THROW_EXCEPTION(std::domain_error("Testing individual bits in negative values is not supported - results are undefined."));
7c673cae
FG
866 }
867 return mp_count_bits(const_cast< ::mp_int*>(&val.data())) - 1;
868}
869
870template <class Integer>
1e59de90 871inline typename std::enable_if<boost::multiprecision::detail::is_unsigned<Integer>::value, Integer>::type eval_integer_modulus(const tommath_int& x, Integer val)
7c673cae 872{
1e59de90
TL
873#ifndef MP_DIGIT_BIT
874 constexpr const mp_digit m = (static_cast<mp_digit>(1) << DIGIT_BIT) - 1;
f67539c2 875#else
1e59de90 876 constexpr const mp_digit m = (static_cast<mp_digit>(1) << MP_DIGIT_BIT) - 1;
f67539c2 877#endif
92f5a8d4 878 if (val <= m)
7c673cae
FG
879 {
880 mp_digit d;
881 detail::check_tommath_result(mp_mod_d(const_cast< ::mp_int*>(&x.data()), static_cast<mp_digit>(val), &d));
882 return d;
883 }
884 else
885 {
886 return default_ops::eval_integer_modulus(x, val);
887 }
888}
889template <class Integer>
1e59de90 890inline typename std::enable_if<boost::multiprecision::detail::is_signed<Integer>::value && boost::multiprecision::detail::is_integral<Integer>::value, Integer>::type eval_integer_modulus(const tommath_int& x, Integer val)
7c673cae
FG
891{
892 return eval_integer_modulus(x, boost::multiprecision::detail::unsigned_abs(val));
893}
894
895inline std::size_t hash_value(const tommath_int& val)
896{
897 std::size_t result = 0;
92f5a8d4
TL
898 std::size_t len = val.data().used;
899 for (std::size_t i = 0; i < len; ++i)
1e59de90
TL
900 boost::multiprecision::detail::hash_combine(result, val.data().dp[i]);
901 boost::multiprecision::detail::hash_combine(result, val.data().sign);
7c673cae
FG
902 return result;
903}
904
905} // namespace backends
906
907using boost::multiprecision::backends::tommath_int;
908
92f5a8d4 909template <>
1e59de90 910struct number_category<tommath_int> : public std::integral_constant<int, number_kind_integer>
92f5a8d4 911{};
7c673cae 912
1e59de90
TL
913using tom_int = number<tommath_int> ;
914using tommath_rational = rational_adaptor<tommath_int>;
915using tom_rational = number<tommath_rational> ;
f67539c2
TL
916}
917} // namespace boost::multiprecision
7c673cae 918
92f5a8d4 919namespace std {
7c673cae 920
92f5a8d4 921template <boost::multiprecision::expression_template_option ExpressionTemplates>
7c673cae
FG
922class numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >
923{
1e59de90 924 using number_type = boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates>;
92f5a8d4
TL
925
926 public:
1e59de90 927 static constexpr bool is_specialized = true;
7c673cae
FG
928 //
929 // Largest and smallest numbers are bounded only by available memory, set
930 // to zero:
931 //
92f5a8d4
TL
932 static number_type(min)()
933 {
7c673cae
FG
934 return number_type();
935 }
92f5a8d4
TL
936 static number_type(max)()
937 {
7c673cae
FG
938 return number_type();
939 }
f67539c2 940 static number_type lowest() { return (min)(); }
1e59de90
TL
941 static constexpr int digits = INT_MAX;
942 static constexpr int digits10 = (INT_MAX / 1000) * 301L;
943 static constexpr int max_digits10 = digits10 + 3;
944 static constexpr bool is_signed = true;
945 static constexpr bool is_integer = true;
946 static constexpr bool is_exact = true;
947 static constexpr int radix = 2;
f67539c2
TL
948 static number_type epsilon() { return number_type(); }
949 static number_type round_error() { return number_type(); }
1e59de90
TL
950 static constexpr int min_exponent = 0;
951 static constexpr int min_exponent10 = 0;
952 static constexpr int max_exponent = 0;
953 static constexpr int max_exponent10 = 0;
954 static constexpr bool has_infinity = false;
955 static constexpr bool has_quiet_NaN = false;
956 static constexpr bool has_signaling_NaN = false;
957 static constexpr float_denorm_style has_denorm = denorm_absent;
958 static constexpr bool has_denorm_loss = false;
92f5a8d4
TL
959 static number_type infinity() { return number_type(); }
960 static number_type quiet_NaN() { return number_type(); }
961 static number_type signaling_NaN() { return number_type(); }
962 static number_type denorm_min() { return number_type(); }
1e59de90
TL
963 static constexpr bool is_iec559 = false;
964 static constexpr bool is_bounded = false;
965 static constexpr bool is_modulo = false;
966 static constexpr bool traps = false;
967 static constexpr bool tinyness_before = false;
968 static constexpr float_round_style round_style = round_toward_zero;
7c673cae
FG
969};
970
7c673cae 971template <boost::multiprecision::expression_template_option ExpressionTemplates>
1e59de90 972constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::digits;
7c673cae 973template <boost::multiprecision::expression_template_option ExpressionTemplates>
1e59de90 974constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::digits10;
7c673cae 975template <boost::multiprecision::expression_template_option ExpressionTemplates>
1e59de90 976constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::max_digits10;
7c673cae 977template <boost::multiprecision::expression_template_option ExpressionTemplates>
1e59de90 978constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_signed;
7c673cae 979template <boost::multiprecision::expression_template_option ExpressionTemplates>
1e59de90 980constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_integer;
7c673cae 981template <boost::multiprecision::expression_template_option ExpressionTemplates>
1e59de90 982constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_exact;
7c673cae 983template <boost::multiprecision::expression_template_option ExpressionTemplates>
1e59de90 984constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::radix;
7c673cae 985template <boost::multiprecision::expression_template_option ExpressionTemplates>
1e59de90 986constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::min_exponent;
7c673cae 987template <boost::multiprecision::expression_template_option ExpressionTemplates>
1e59de90 988constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::min_exponent10;
7c673cae 989template <boost::multiprecision::expression_template_option ExpressionTemplates>
1e59de90 990constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::max_exponent;
7c673cae 991template <boost::multiprecision::expression_template_option ExpressionTemplates>
1e59de90 992constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::max_exponent10;
7c673cae 993template <boost::multiprecision::expression_template_option ExpressionTemplates>
1e59de90 994constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_infinity;
7c673cae 995template <boost::multiprecision::expression_template_option ExpressionTemplates>
1e59de90 996constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_quiet_NaN;
7c673cae 997template <boost::multiprecision::expression_template_option ExpressionTemplates>
1e59de90 998constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_signaling_NaN;
7c673cae 999template <boost::multiprecision::expression_template_option ExpressionTemplates>
1e59de90 1000constexpr float_denorm_style numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_denorm;
7c673cae 1001template <boost::multiprecision::expression_template_option ExpressionTemplates>
1e59de90 1002constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_denorm_loss;
7c673cae 1003template <boost::multiprecision::expression_template_option ExpressionTemplates>
1e59de90 1004constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_iec559;
7c673cae 1005template <boost::multiprecision::expression_template_option ExpressionTemplates>
1e59de90 1006constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_bounded;
7c673cae 1007template <boost::multiprecision::expression_template_option ExpressionTemplates>
1e59de90 1008constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_modulo;
7c673cae 1009template <boost::multiprecision::expression_template_option ExpressionTemplates>
1e59de90 1010constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::traps;
7c673cae 1011template <boost::multiprecision::expression_template_option ExpressionTemplates>
1e59de90 1012constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::tinyness_before;
7c673cae 1013template <boost::multiprecision::expression_template_option ExpressionTemplates>
1e59de90 1014constexpr float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::round_style;
7c673cae 1015
92f5a8d4 1016} // namespace std
7c673cae
FG
1017
1018#endif