1 ///////////////////////////////////////////////////////////////
2 //  Copyright 2013 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 #ifndef BOOST_MP_FLOAT128_HPP
7 #define BOOST_MP_FLOAT128_HPP
8 
9 #include <boost/config.hpp>
10 #include <boost/scoped_array.hpp>
11 #include <boost/functional/hash.hpp>
12 #include <boost/multiprecision/number.hpp>
13 
14 #if defined(BOOST_INTEL) && !defined(BOOST_MP_USE_FLOAT128) && !defined(BOOST_MP_USE_QUAD)
15 #if defined(BOOST_INTEL_CXX_VERSION) && (BOOST_INTEL_CXX_VERSION >= 1310) && defined(__GNUC__)
16 #if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6))
17 #define BOOST_MP_USE_FLOAT128
18 #endif
19 #endif
20 
21 #ifndef BOOST_MP_USE_FLOAT128
22 #define BOOST_MP_USE_QUAD
23 #endif
24 #endif
25 
26 #if defined(__GNUC__) && !defined(BOOST_MP_USE_FLOAT128) && !defined(BOOST_MP_USE_QUAD)
27 #define BOOST_MP_USE_FLOAT128
28 #endif
29 
30 #if !defined(BOOST_MP_USE_FLOAT128) && !defined(BOOST_MP_USE_QUAD)
31 #error "Sorry compiler is neither GCC, not Intel, don't know how to configure this header."
32 #endif
33 #if defined(BOOST_MP_USE_FLOAT128) && defined(BOOST_MP_USE_QUAD)
34 #error "Oh dear, both BOOST_MP_USE_FLOAT128 and BOOST_MP_USE_QUAD are defined, which one should I be using?"
35 #endif
36 
37 #if defined(BOOST_MP_USE_FLOAT128)
38 
39 extern "C" {
40 #include <quadmath.h>
41 }
42 
43 typedef __float128 float128_type;
44 
45 #elif defined(BOOST_MP_USE_QUAD)
46 
47 #include <boost/multiprecision/detail/float_string_cvt.hpp>
48 
49 typedef _Quad float128_type;
50 
51 extern "C" {
52 _Quad __ldexpq(_Quad, int);
53 _Quad __frexpq(_Quad, int*);
54 _Quad __fabsq(_Quad);
55 _Quad __floorq(_Quad);
56 _Quad __ceilq(_Quad);
57 _Quad __sqrtq(_Quad);
58 _Quad __truncq(_Quad);
59 _Quad __expq(_Quad);
60 _Quad __powq(_Quad, _Quad);
61 _Quad __logq(_Quad);
62 _Quad __log10q(_Quad);
63 _Quad __sinq(_Quad);
64 _Quad __cosq(_Quad);
65 _Quad __tanq(_Quad);
66 _Quad __asinq(_Quad);
67 _Quad __acosq(_Quad);
68 _Quad __atanq(_Quad);
69 _Quad __sinhq(_Quad);
70 _Quad __coshq(_Quad);
71 _Quad __tanhq(_Quad);
72 _Quad __fmodq(_Quad, _Quad);
73 _Quad __atan2q(_Quad, _Quad);
74 
75 #define ldexpq __ldexpq
76 #define frexpq __frexpq
77 #define fabsq __fabsq
78 #define floorq __floorq
79 #define ceilq __ceilq
80 #define sqrtq __sqrtq
81 #define truncq __truncq
82 #define expq __expq
83 #define powq __powq
84 #define logq __logq
85 #define log10q __log10q
86 #define sinq __sinq
87 #define cosq __cosq
88 #define tanq __tanq
89 #define asinq __asinq
90 #define acosq __acosq
91 #define atanq __atanq
92 #define sinhq __sinhq
93 #define coshq __coshq
94 #define tanhq __tanhq
95 #define fmodq __fmodq
96 #define atan2q __atan2q
97 }
98 
isnanq(_Quad v)99 inline _Quad isnanq(_Quad v)
100 {
101    return v != v;
102 }
isinfq(_Quad v)103 inline _Quad isinfq(_Quad v)
104 {
105    return __fabsq(v) > 1.18973149535723176508575932662800702e4932Q;
106 }
107 
108 #endif
109 
110 namespace boost {
111 namespace multiprecision {
112 
113 #ifndef BOOST_MP_BITS_OF_FLOAT128_DEFINED
114 
115 namespace detail {
116 
117 template <>
118 struct bits_of<float128_type>
119 {
120    static const unsigned value = 113;
121 };
122 
123 }
124 
125 #endif
126 
127 namespace backends {
128 
129 struct float128_backend;
130 
131 }
132 
133 using backends::float128_backend;
134 
135 template <>
136 struct number_category<backends::float128_backend> : public mpl::int_<number_kind_floating_point>
137 {};
138 #if defined(BOOST_MP_USE_QUAD)
139 template <>
140 struct number_category<float128_type> : public mpl::int_<number_kind_floating_point>
141 {};
142 #endif
143 
144 typedef number<float128_backend, et_off> float128;
145 
146 #ifndef BOOST_NO_CXX11_CONSTEXPR
147 
148 namespace quad_constants {
149 constexpr __float128 quad_min = static_cast<__float128>(1) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) / 1073741824;
150 
151 constexpr __float128 quad_denorm_min = static_cast<__float128>(1) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) * static_cast<__float128>(DBL_MIN) / 5.5751862996326557854e+42;
152 
153 constexpr double     dbl_mult = 8.9884656743115795386e+307;                                              // This has one bit set only.
154 constexpr __float128 quad_max = (static_cast<__float128>(1) - 9.62964972193617926527988971292463659e-35) // This now has all bits sets to 1
155                                 * static_cast<__float128>(dbl_mult) * static_cast<__float128>(dbl_mult) * static_cast<__float128>(dbl_mult) * static_cast<__float128>(dbl_mult) * static_cast<__float128>(dbl_mult) * static_cast<__float128>(dbl_mult) * static_cast<__float128>(dbl_mult) * static_cast<__float128>(dbl_mult) * static_cast<__float128>(dbl_mult) * static_cast<__float128>(dbl_mult) * static_cast<__float128>(dbl_mult) * static_cast<__float128>(dbl_mult) * static_cast<__float128>(dbl_mult) * static_cast<__float128>(dbl_mult) * static_cast<__float128>(dbl_mult) * static_cast<__float128>(dbl_mult) * 65536;
156 } // namespace quad_constants
157 
158 #define BOOST_MP_QUAD_MIN boost::multiprecision::quad_constants::quad_min
159 #define BOOST_MP_QUAD_DENORM_MIN boost::multiprecision::quad_constants::quad_denorm_min
160 #define BOOST_MP_QUAD_MAX boost::multiprecision::quad_constants::quad_max
161 
162 #else
163 
164 #define BOOST_MP_QUAD_MIN 3.36210314311209350626267781732175260e-4932Q
165 #define BOOST_MP_QUAD_DENORM_MIN 6.475175119438025110924438958227646552e-4966Q
166 #define BOOST_MP_QUAD_MAX 1.18973149535723176508575932662800702e4932Q
167 
168 #endif
169 
170 namespace backends {
171 
172 struct float128_backend
173 {
174    typedef mpl::list<signed char, short, int, long, boost::long_long_type> signed_types;
175    typedef mpl::list<unsigned char, unsigned short,
176                      unsigned int, unsigned long, boost::ulong_long_type>
177        unsigned_types;
178    typedef mpl::list<float, double, long double> float_types;
179    typedef int                                   exponent_type;
180 
181  private:
182    float128_type m_value;
183 
184  public:
float128_backendboost::multiprecision::backends::float128_backend185    BOOST_CONSTEXPR   float128_backend() BOOST_NOEXCEPT : m_value(0) {}
float128_backendboost::multiprecision::backends::float128_backend186    BOOST_CONSTEXPR   float128_backend(const float128_backend& o) BOOST_NOEXCEPT : m_value(o.m_value) {}
operator =boost::multiprecision::backends::float128_backend187    BOOST_MP_CXX14_CONSTEXPR float128_backend& operator=(const float128_backend& o) BOOST_NOEXCEPT
188    {
189       m_value = o.m_value;
190       return *this;
191    }
192    template <class T>
float128_backendboost::multiprecision::backends::float128_backend193    BOOST_CONSTEXPR float128_backend(const T& i, const typename enable_if_c<is_convertible<T, float128_type>::value>::type* = 0) BOOST_NOEXCEPT_IF(noexcept(std::declval<float128_type&>() = std::declval<const T&>()))
194        : m_value(i) {}
195    template <class T>
operator =boost::multiprecision::backends::float128_backend196    BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_arithmetic<T>::value || is_convertible<T, float128_type>::value, float128_backend&>::type operator=(const T& i) BOOST_NOEXCEPT_IF(noexcept(std::declval<float128_type&>() = std::declval<const T&>()))
197    {
198       m_value = i;
199       return *this;
200    }
float128_backendboost::multiprecision::backends::float128_backend201    BOOST_MP_CXX14_CONSTEXPR float128_backend(long double const& f) : m_value(f)
202    {
203       if (::fabsl(f) > LDBL_MAX)
204          m_value = (f < 0) ? -static_cast<__float128>(HUGE_VAL) : static_cast<__float128>(HUGE_VAL);
205    }
operator =boost::multiprecision::backends::float128_backend206    BOOST_MP_CXX14_CONSTEXPR float128_backend& operator=(long double const& f)
207    {
208       if (f > LDBL_MAX)
209          m_value = static_cast<__float128>(HUGE_VAL);
210       else if (-f > LDBL_MAX)
211          m_value = -static_cast<__float128>(HUGE_VAL);
212       else
213          m_value = f;
214       return *this;
215    }
operator =boost::multiprecision::backends::float128_backend216    float128_backend& operator=(const char* s)
217    {
218 #ifndef BOOST_MP_USE_QUAD
219       char* p_end;
220       m_value = strtoflt128(s, &p_end);
221       if (p_end - s != (std::ptrdiff_t)std::strlen(s))
222       {
223          BOOST_THROW_EXCEPTION(std::runtime_error("Unable to interpret input string as a floating point value"));
224       }
225 #else
226       boost::multiprecision::detail::convert_from_string(*this, s);
227 #endif
228       return *this;
229    }
swapboost::multiprecision::backends::float128_backend230    BOOST_MP_CXX14_CONSTEXPR void swap(float128_backend& o) BOOST_NOEXCEPT
231    {
232       // We don't call std::swap here because it's no constexpr (yet):
233       float128_type t(o.value());
234       o.value() = m_value;
235       m_value = t;
236    }
strboost::multiprecision::backends::float128_backend237    std::string str(std::streamsize digits, std::ios_base::fmtflags f) const
238    {
239 #ifndef BOOST_MP_USE_QUAD
240       char        buf[128];
241       std::string format = "%";
242       if (f & std::ios_base::showpos)
243          format += "+";
244       if (f & std::ios_base::showpoint)
245          format += "#";
246       format += ".*";
247       if (digits == 0)
248          digits = 36;
249       format += "Q";
250 
251       if (f & std::ios_base::scientific)
252          format += "e";
253       else if (f & std::ios_base::fixed)
254          format += "f";
255       else
256          format += "g";
257 
258       int v;
259       if ((f & std::ios_base::scientific) && (f & std::ios_base::fixed))
260       {
261          v = quadmath_snprintf(buf, sizeof buf, "%Qa", m_value);
262       }
263       else
264       {
265          v = quadmath_snprintf(buf, sizeof buf, format.c_str(), digits, m_value);
266       }
267 
268       if ((v < 0) || (v >= 127))
269       {
270          int                       v_max = v;
271          boost::scoped_array<char> buf2;
272          buf2.reset(new char[v + 3]);
273          v = quadmath_snprintf(&buf2[0], v_max + 3, format.c_str(), digits, m_value);
274          if (v >= v_max + 3)
275          {
276             BOOST_THROW_EXCEPTION(std::runtime_error("Formatting of float128_type failed."));
277          }
278          return &buf2[0];
279       }
280       return buf;
281 #else
282       return boost::multiprecision::detail::convert_to_string(*this, digits ? digits : 37, f);
283 #endif
284    }
negateboost::multiprecision::backends::float128_backend285    BOOST_MP_CXX14_CONSTEXPR void negate() BOOST_NOEXCEPT
286    {
287       m_value = -m_value;
288    }
compareboost::multiprecision::backends::float128_backend289    BOOST_MP_CXX14_CONSTEXPR int compare(const float128_backend& o) const
290    {
291       return m_value == o.m_value ? 0 : m_value < o.m_value ? -1 : 1;
292    }
293    template <class T>
compareboost::multiprecision::backends::float128_backend294    BOOST_MP_CXX14_CONSTEXPR int compare(const T& i) const
295    {
296       return m_value == i ? 0 : m_value < i ? -1 : 1;
297    }
valueboost::multiprecision::backends::float128_backend298    BOOST_MP_CXX14_CONSTEXPR float128_type& value()
299    {
300       return m_value;
301    }
valueboost::multiprecision::backends::float128_backend302    BOOST_MP_CXX14_CONSTEXPR const float128_type& value() const
303    {
304       return m_value;
305    }
306 };
307 
eval_add(float128_backend & result,const float128_backend & a)308 inline BOOST_MP_CXX14_CONSTEXPR void eval_add(float128_backend& result, const float128_backend& a)
309 {
310    result.value() += a.value();
311 }
312 template <class A>
eval_add(float128_backend & result,const A & a)313 inline BOOST_MP_CXX14_CONSTEXPR void eval_add(float128_backend& result, const A& a)
314 {
315    result.value() += a;
316 }
eval_subtract(float128_backend & result,const float128_backend & a)317 inline BOOST_MP_CXX14_CONSTEXPR void eval_subtract(float128_backend& result, const float128_backend& a)
318 {
319    result.value() -= a.value();
320 }
321 template <class A>
eval_subtract(float128_backend & result,const A & a)322 inline BOOST_MP_CXX14_CONSTEXPR void eval_subtract(float128_backend& result, const A& a)
323 {
324    result.value() -= a;
325 }
eval_multiply(float128_backend & result,const float128_backend & a)326 inline BOOST_MP_CXX14_CONSTEXPR void eval_multiply(float128_backend& result, const float128_backend& a)
327 {
328    result.value() *= a.value();
329 }
330 template <class A>
eval_multiply(float128_backend & result,const A & a)331 inline BOOST_MP_CXX14_CONSTEXPR void eval_multiply(float128_backend& result, const A& a)
332 {
333    result.value() *= a;
334 }
eval_divide(float128_backend & result,const float128_backend & a)335 inline BOOST_MP_CXX14_CONSTEXPR void eval_divide(float128_backend& result, const float128_backend& a)
336 {
337    result.value() /= a.value();
338 }
339 template <class A>
eval_divide(float128_backend & result,const A & a)340 inline BOOST_MP_CXX14_CONSTEXPR void eval_divide(float128_backend& result, const A& a)
341 {
342    result.value() /= a;
343 }
344 
eval_add(float128_backend & result,const float128_backend & a,const float128_backend & b)345 inline BOOST_MP_CXX14_CONSTEXPR void eval_add(float128_backend& result, const float128_backend& a, const float128_backend& b)
346 {
347    result.value() = a.value() + b.value();
348 }
349 template <class A>
eval_add(float128_backend & result,const float128_backend & a,const A & b)350 inline BOOST_MP_CXX14_CONSTEXPR void eval_add(float128_backend& result, const float128_backend& a, const A& b)
351 {
352    result.value() = a.value() + b;
353 }
eval_subtract(float128_backend & result,const float128_backend & a,const float128_backend & b)354 inline BOOST_MP_CXX14_CONSTEXPR void eval_subtract(float128_backend& result, const float128_backend& a, const float128_backend& b)
355 {
356    result.value() = a.value() - b.value();
357 }
358 template <class A>
eval_subtract(float128_backend & result,const float128_backend & a,const A & b)359 inline BOOST_MP_CXX14_CONSTEXPR void eval_subtract(float128_backend& result, const float128_backend& a, const A& b)
360 {
361    result.value() = a.value() - b;
362 }
363 template <class A>
eval_subtract(float128_backend & result,const A & a,const float128_backend & b)364 inline BOOST_MP_CXX14_CONSTEXPR void eval_subtract(float128_backend& result, const A& a, const float128_backend& b)
365 {
366    result.value() = a - b.value();
367 }
eval_multiply(float128_backend & result,const float128_backend & a,const float128_backend & b)368 inline BOOST_MP_CXX14_CONSTEXPR void eval_multiply(float128_backend& result, const float128_backend& a, const float128_backend& b)
369 {
370    result.value() = a.value() * b.value();
371 }
372 template <class A>
eval_multiply(float128_backend & result,const float128_backend & a,const A & b)373 inline BOOST_MP_CXX14_CONSTEXPR void eval_multiply(float128_backend& result, const float128_backend& a, const A& b)
374 {
375    result.value() = a.value() * b;
376 }
eval_divide(float128_backend & result,const float128_backend & a,const float128_backend & b)377 inline BOOST_MP_CXX14_CONSTEXPR void eval_divide(float128_backend& result, const float128_backend& a, const float128_backend& b)
378 {
379    result.value() = a.value() / b.value();
380 }
381 
382 template <class R>
eval_convert_to(R * result,const float128_backend & val)383 inline BOOST_MP_CXX14_CONSTEXPR void eval_convert_to(R* result, const float128_backend& val)
384 {
385    *result = static_cast<R>(val.value());
386 }
387 
eval_frexp(float128_backend & result,const float128_backend & arg,int * exp)388 inline void eval_frexp(float128_backend& result, const float128_backend& arg, int* exp)
389 {
390    result.value() = frexpq(arg.value(), exp);
391 }
392 
eval_ldexp(float128_backend & result,const float128_backend & arg,int exp)393 inline void eval_ldexp(float128_backend& result, const float128_backend& arg, int exp)
394 {
395    result.value() = ldexpq(arg.value(), exp);
396 }
397 
eval_floor(float128_backend & result,const float128_backend & arg)398 inline void eval_floor(float128_backend& result, const float128_backend& arg)
399 {
400    result.value() = floorq(arg.value());
401 }
eval_ceil(float128_backend & result,const float128_backend & arg)402 inline void eval_ceil(float128_backend& result, const float128_backend& arg)
403 {
404    result.value() = ceilq(arg.value());
405 }
eval_sqrt(float128_backend & result,const float128_backend & arg)406 inline void eval_sqrt(float128_backend& result, const float128_backend& arg)
407 {
408    result.value() = sqrtq(arg.value());
409 }
eval_rsqrt(float128_backend & result,const float128_backend & arg)410 inline void eval_rsqrt(float128_backend& result, const float128_backend& arg)
411 {
412    using std::sqrt;
413    if (arg.value() < std::numeric_limits<long double>::denorm_min() || arg.value() > (std::numeric_limits<long double>::max)()) {
414       result.value() = 1/sqrtq(arg.value());
415       return;
416    }
417    float128_backend xk = 1/sqrt(static_cast<long double>(arg.value()));
418 
419    // Newton iteration for f(x) = arg.value() - 1/x^2.
420    BOOST_IF_CONSTEXPR (sizeof(long double) == sizeof(double)) {
421        // If the long double is the same as a double, then we need two Newton iterations:
422        xk.value() = xk.value() + xk.value()*(1-arg.value()*xk.value()*xk.value())/2;
423        result.value() = xk.value() + xk.value()*(1-arg.value()*xk.value()*xk.value())/2;
424        return;
425    }
426 
427    // 80 bit long double only needs a single iteration to produce ~2ULPs.
428    result.value() = xk.value() + xk.value()*(1-arg.value()*xk.value()*xk.value())/2;
429    return;
430 }
431 #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
432 inline BOOST_MP_CXX14_CONSTEXPR
433 #else
434 inline
435 #endif
eval_fpclassify(const float128_backend & arg)436 int eval_fpclassify(const float128_backend& arg)
437 {
438    float128_type v = arg.value();
439 #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
440    if (BOOST_MP_IS_CONST_EVALUATED(v))
441    {
442       if (v != v)
443          return FP_NAN;
444       if (v == 0)
445          return FP_ZERO;
446       float128_type t(v);
447       if (t < 0)
448          t = -t;
449       if (t > BOOST_MP_QUAD_MAX)
450          return FP_INFINITE;
451       if (t < BOOST_MP_QUAD_MIN)
452          return FP_SUBNORMAL;
453       return FP_NORMAL;
454    }
455    else
456 #endif
457    {
458       if (isnanq(v))
459          return FP_NAN;
460       else if (isinfq(v))
461          return FP_INFINITE;
462       else if (v == 0)
463          return FP_ZERO;
464 
465       float128_backend t(arg);
466       if (t.value() < 0)
467          t.negate();
468       if (t.value() < BOOST_MP_QUAD_MIN)
469          return FP_SUBNORMAL;
470       return FP_NORMAL;
471    }
472 }
473 #if defined(BOOST_GCC) && (__GNUC__ == 9)
474 // See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91705
eval_increment(float128_backend & arg)475 inline BOOST_MP_CXX14_CONSTEXPR void eval_increment(float128_backend& arg)
476 {
477    arg.value() = 1 + arg.value();
478 }
eval_decrement(float128_backend & arg)479 inline BOOST_MP_CXX14_CONSTEXPR void eval_decrement(float128_backend& arg)
480 {
481    arg.value() = arg.value() - 1;
482 }
483 #else
eval_increment(float128_backend & arg)484 inline BOOST_MP_CXX14_CONSTEXPR void eval_increment(float128_backend& arg)
485 {
486    ++arg.value();
487 }
eval_decrement(float128_backend & arg)488 inline BOOST_MP_CXX14_CONSTEXPR void eval_decrement(float128_backend& arg)
489 {
490    --arg.value();
491 }
492 #endif
493 
494 /*********************************************************************
495 *
496 * abs/fabs:
497 *
498 *********************************************************************/
499 
500 #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
eval_abs(float128_backend & result,const float128_backend & arg)501 inline BOOST_MP_CXX14_CONSTEXPR void eval_abs(float128_backend& result, const float128_backend& arg)
502 #else
503 inline void eval_abs(float128_backend& result, const float128_backend& arg)
504 #endif
505 {
506    float128_type v(arg.value());
507 #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
508    if (BOOST_MP_IS_CONST_EVALUATED(v))
509    {
510       result.value() = v < 0 ? -v : v;
511    }
512    else
513 #endif
514    {
515       result.value() = fabsq(arg.value());
516    }
517 }
518 #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
eval_fabs(float128_backend & result,const float128_backend & arg)519 inline BOOST_MP_CXX14_CONSTEXPR void eval_fabs(float128_backend& result, const float128_backend& arg)
520 #else
521 inline void eval_fabs(float128_backend& result, const float128_backend& arg)
522 #endif
523 {
524    float128_type v(arg.value());
525 #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
526    if (BOOST_MP_IS_CONST_EVALUATED(v))
527    {
528       result.value() = v < 0 ? -v : v;
529    }
530    else
531 #endif
532    {
533       result.value() = fabsq(arg.value());
534    }
535 }
536 
537 /*********************************************************************
538 *
539 * Floating point functions:
540 *
541 *********************************************************************/
542 
eval_trunc(float128_backend & result,const float128_backend & arg)543 inline void eval_trunc(float128_backend& result, const float128_backend& arg)
544 {
545    result.value() = truncq(arg.value());
546 }
547 /*
548 //
549 // This doesn't actually work... rely on our own default version instead.
550 //
551 inline void eval_round(float128_backend& result, const float128_backend& arg)
552 {
553    if(isnanq(arg.value()) || isinf(arg.value()))
554    {
555       result = boost::math::policies::raise_rounding_error(
556             "boost::multiprecision::trunc<%1%>(%1%)", 0,
557             number<float128_backend, et_off>(arg),
558             number<float128_backend, et_off>(arg),
559             boost::math::policies::policy<>()).backend();
560       return;
561    }
562    result.value() = roundq(arg.value());
563 }
564 */
565 
eval_exp(float128_backend & result,const float128_backend & arg)566 inline void eval_exp(float128_backend& result, const float128_backend& arg)
567 {
568    result.value() = expq(arg.value());
569 }
eval_log(float128_backend & result,const float128_backend & arg)570 inline void eval_log(float128_backend& result, const float128_backend& arg)
571 {
572    result.value() = logq(arg.value());
573 }
eval_log10(float128_backend & result,const float128_backend & arg)574 inline void eval_log10(float128_backend& result, const float128_backend& arg)
575 {
576    result.value() = log10q(arg.value());
577 }
eval_sin(float128_backend & result,const float128_backend & arg)578 inline void eval_sin(float128_backend& result, const float128_backend& arg)
579 {
580    result.value() = sinq(arg.value());
581 }
eval_cos(float128_backend & result,const float128_backend & arg)582 inline void eval_cos(float128_backend& result, const float128_backend& arg)
583 {
584    result.value() = cosq(arg.value());
585 }
eval_tan(float128_backend & result,const float128_backend & arg)586 inline void eval_tan(float128_backend& result, const float128_backend& arg)
587 {
588    result.value() = tanq(arg.value());
589 }
eval_asin(float128_backend & result,const float128_backend & arg)590 inline void eval_asin(float128_backend& result, const float128_backend& arg)
591 {
592    result.value() = asinq(arg.value());
593 }
eval_acos(float128_backend & result,const float128_backend & arg)594 inline void eval_acos(float128_backend& result, const float128_backend& arg)
595 {
596    result.value() = acosq(arg.value());
597 }
eval_atan(float128_backend & result,const float128_backend & arg)598 inline void eval_atan(float128_backend& result, const float128_backend& arg)
599 {
600    result.value() = atanq(arg.value());
601 }
eval_sinh(float128_backend & result,const float128_backend & arg)602 inline void eval_sinh(float128_backend& result, const float128_backend& arg)
603 {
604    result.value() = sinhq(arg.value());
605 }
eval_cosh(float128_backend & result,const float128_backend & arg)606 inline void eval_cosh(float128_backend& result, const float128_backend& arg)
607 {
608    result.value() = coshq(arg.value());
609 }
eval_tanh(float128_backend & result,const float128_backend & arg)610 inline void eval_tanh(float128_backend& result, const float128_backend& arg)
611 {
612    result.value() = tanhq(arg.value());
613 }
eval_fmod(float128_backend & result,const float128_backend & a,const float128_backend & b)614 inline void eval_fmod(float128_backend& result, const float128_backend& a, const float128_backend& b)
615 {
616    result.value() = fmodq(a.value(), b.value());
617 }
eval_pow(float128_backend & result,const float128_backend & a,const float128_backend & b)618 inline void eval_pow(float128_backend& result, const float128_backend& a, const float128_backend& b)
619 {
620    result.value() = powq(a.value(), b.value());
621 }
eval_atan2(float128_backend & result,const float128_backend & a,const float128_backend & b)622 inline void eval_atan2(float128_backend& result, const float128_backend& a, const float128_backend& b)
623 {
624    result.value() = atan2q(a.value(), b.value());
625 }
626 #ifndef BOOST_MP_USE_QUAD
eval_multiply_add(float128_backend & result,const float128_backend & a,const float128_backend & b,const float128_backend & c)627 inline void eval_multiply_add(float128_backend& result, const float128_backend& a, const float128_backend& b, const float128_backend& c)
628 {
629    result.value() = fmaq(a.value(), b.value(), c.value());
630 }
BOOST_PREVENT_MACRO_SUBSTITUTION(const float128_backend & arg)631 inline int eval_signbit BOOST_PREVENT_MACRO_SUBSTITUTION(const float128_backend& arg)
632 {
633    return ::signbitq(arg.value());
634 }
635 #endif
636 
hash_value(const float128_backend & val)637 inline std::size_t hash_value(const float128_backend& val)
638 {
639    return boost::hash_value(static_cast<double>(val.value()));
640 }
641 
642 } // namespace backends
643 
644 template <boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend,ExpressionTemplates> & arg)645 inline boost::multiprecision::number<float128_backend, ExpressionTemplates> asinh BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend, ExpressionTemplates>& arg)
646 {
647    return asinhq(arg.backend().value());
648 }
649 template <boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend,ExpressionTemplates> & arg)650 inline boost::multiprecision::number<float128_backend, ExpressionTemplates> acosh BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend, ExpressionTemplates>& arg)
651 {
652    return acoshq(arg.backend().value());
653 }
654 template <boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend,ExpressionTemplates> & arg)655 inline boost::multiprecision::number<float128_backend, ExpressionTemplates> atanh BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend, ExpressionTemplates>& arg)
656 {
657    return atanhq(arg.backend().value());
658 }
659 template <boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend,ExpressionTemplates> & arg)660 inline boost::multiprecision::number<float128_backend, ExpressionTemplates> cbrt BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend, ExpressionTemplates>& arg)
661 {
662    return cbrtq(arg.backend().value());
663 }
664 template <boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend,ExpressionTemplates> & arg)665 inline boost::multiprecision::number<float128_backend, ExpressionTemplates> erf BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend, ExpressionTemplates>& arg)
666 {
667    return erfq(arg.backend().value());
668 }
669 template <boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend,ExpressionTemplates> & arg)670 inline boost::multiprecision::number<float128_backend, ExpressionTemplates> erfc BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend, ExpressionTemplates>& arg)
671 {
672    return erfcq(arg.backend().value());
673 }
674 template <boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend,ExpressionTemplates> & arg)675 inline boost::multiprecision::number<float128_backend, ExpressionTemplates> expm1 BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend, ExpressionTemplates>& arg)
676 {
677    return expm1q(arg.backend().value());
678 }
679 template <boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend,ExpressionTemplates> & arg)680 inline boost::multiprecision::number<float128_backend, ExpressionTemplates> lgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend, ExpressionTemplates>& arg)
681 {
682    return lgammaq(arg.backend().value());
683 }
684 template <boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend,ExpressionTemplates> & arg)685 inline boost::multiprecision::number<float128_backend, ExpressionTemplates> tgamma BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend, ExpressionTemplates>& arg)
686 {
687    if(eval_signbit(arg.backend()) != 0)
688    {
689       const bool result_is_neg = ((static_cast<unsigned long long>(floorq(-arg.backend().value())) % 2U) == 0U);
690 
691       const boost::multiprecision::number<float128_backend, ExpressionTemplates> result_of_tgammaq = fabsq(tgammaq(arg.backend().value()));
692 
693       return ((result_is_neg == false) ? result_of_tgammaq : -result_of_tgammaq);
694    }
695    else
696    {
697       return tgammaq(arg.backend().value());
698    }
699 }
700 template <boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend,ExpressionTemplates> & arg)701 inline boost::multiprecision::number<float128_backend, ExpressionTemplates> log1p BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend, ExpressionTemplates>& arg)
702 {
703    return log1pq(arg.backend().value());
704 }
705 template <boost::multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend,ExpressionTemplates> & arg)706 inline boost::multiprecision::number<float128_backend, ExpressionTemplates> rsqrt BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<float128_backend, ExpressionTemplates>& arg)
707 {
708    boost::multiprecision::number<float128_backend, ExpressionTemplates> res;
709    eval_rsqrt(res.backend(), arg.backend());
710    return res;
711 }
712 
713 #ifndef BOOST_MP_USE_QUAD
714 template <multiprecision::expression_template_option ExpressionTemplates>
BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::backends::float128_backend,ExpressionTemplates> & a,const boost::multiprecision::number<boost::multiprecision::backends::float128_backend,ExpressionTemplates> & b)715 inline boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> copysign BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates>& a, const boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates>& b)
716 {
717    return ::copysignq(a.backend().value(), b.backend().value());
718 }
719 
eval_remainder(float128_backend & result,const float128_backend & a,const float128_backend & b)720 inline void eval_remainder(float128_backend& result, const float128_backend& a, const float128_backend& b)
721 {
722    result.value() = remainderq(a.value(), b.value());
723 }
eval_remainder(float128_backend & result,const float128_backend & a,const float128_backend & b,int * pi)724 inline void eval_remainder(float128_backend& result, const float128_backend& a, const float128_backend& b, int* pi)
725 {
726    result.value() = remquoq(a.value(), b.value(), pi);
727 }
728 #endif
729 
730 } // namespace multiprecision
731 
732 namespace math {
733 
734 using boost::multiprecision::copysign;
735 using boost::multiprecision::signbit;
736 
737 } // namespace math
738 
739 } // namespace boost
740 
741 namespace boost {
742 namespace archive {
743 
744 class binary_oarchive;
745 class binary_iarchive;
746 
747 } // namespace archive
748 
749 namespace serialization {
750 namespace float128_detail {
751 
752 template <class Archive>
do_serialize(Archive & ar,boost::multiprecision::backends::float128_backend & val,const mpl::false_ &,const mpl::false_ &)753 void do_serialize(Archive& ar, boost::multiprecision::backends::float128_backend& val, const mpl::false_&, const mpl::false_&)
754 {
755    // saving
756    // non-binary
757    std::string s(val.str(0, std::ios_base::scientific));
758    ar&         boost::make_nvp("value", s);
759 }
760 template <class Archive>
do_serialize(Archive & ar,boost::multiprecision::backends::float128_backend & val,const mpl::true_ &,const mpl::false_ &)761 void do_serialize(Archive& ar, boost::multiprecision::backends::float128_backend& val, const mpl::true_&, const mpl::false_&)
762 {
763    // loading
764    // non-binary
765    std::string s;
766    ar&         boost::make_nvp("value", s);
767    val = s.c_str();
768 }
769 
770 template <class Archive>
do_serialize(Archive & ar,boost::multiprecision::backends::float128_backend & val,const mpl::false_ &,const mpl::true_ &)771 void do_serialize(Archive& ar, boost::multiprecision::backends::float128_backend& val, const mpl::false_&, const mpl::true_&)
772 {
773    // saving
774    // binary
775    ar.save_binary(&val, sizeof(val));
776 }
777 template <class Archive>
do_serialize(Archive & ar,boost::multiprecision::backends::float128_backend & val,const mpl::true_ &,const mpl::true_ &)778 void do_serialize(Archive& ar, boost::multiprecision::backends::float128_backend& val, const mpl::true_&, const mpl::true_&)
779 {
780    // loading
781    // binary
782    ar.load_binary(&val, sizeof(val));
783 }
784 
785 } // namespace float128_detail
786 
787 template <class Archive>
serialize(Archive & ar,boost::multiprecision::backends::float128_backend & val,unsigned int)788 void serialize(Archive& ar, boost::multiprecision::backends::float128_backend& val, unsigned int /*version*/)
789 {
790    typedef typename Archive::is_loading                                                                                                                            load_tag;
791    typedef typename mpl::bool_<boost::is_same<Archive, boost::archive::binary_oarchive>::value || boost::is_same<Archive, boost::archive::binary_iarchive>::value> binary_tag;
792 
793    float128_detail::do_serialize(ar, val, load_tag(), binary_tag());
794 }
795 
796 } // namespace serialization
797 
798 } // namespace boost
799 
800 namespace std {
801 
802 template <boost::multiprecision::expression_template_option ExpressionTemplates>
803 class numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >
804 {
805    typedef boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> number_type;
806 
807  public:
808    BOOST_STATIC_CONSTEXPR bool is_specialized = true;
number_type(min)809    static BOOST_MP_CXX14_CONSTEXPR number_type(min)() BOOST_NOEXCEPT { return BOOST_MP_QUAD_MIN; }
number_type(max)810    static BOOST_MP_CXX14_CONSTEXPR number_type(max)() BOOST_NOEXCEPT { return BOOST_MP_QUAD_MAX; }
lowest()811    static BOOST_MP_CXX14_CONSTEXPR number_type          lowest() BOOST_NOEXCEPT { return -(max)(); }
812    BOOST_STATIC_CONSTEXPR int  digits       = 113;
813    BOOST_STATIC_CONSTEXPR int  digits10     = 33;
814    BOOST_STATIC_CONSTEXPR int  max_digits10 = 36;
815    BOOST_STATIC_CONSTEXPR bool is_signed    = true;
816    BOOST_STATIC_CONSTEXPR bool is_integer   = false;
817    BOOST_STATIC_CONSTEXPR bool is_exact     = false;
818    BOOST_STATIC_CONSTEXPR int  radix        = 2;
epsilon()819    static BOOST_MP_CXX14_CONSTEXPR number_type          epsilon() { return 1.92592994438723585305597794258492732e-34; /* this double value has only one bit set and so is exact */ }
round_error()820    static BOOST_MP_CXX14_CONSTEXPR number_type          round_error() { return 0.5; }
821    BOOST_STATIC_CONSTEXPR int  min_exponent                  = -16381;
822    BOOST_STATIC_CONSTEXPR int  min_exponent10                = min_exponent * 301L / 1000L;
823    BOOST_STATIC_CONSTEXPR int  max_exponent                  = 16384;
824    BOOST_STATIC_CONSTEXPR int  max_exponent10                = max_exponent * 301L / 1000L;
825    BOOST_STATIC_CONSTEXPR bool has_infinity                  = true;
826    BOOST_STATIC_CONSTEXPR bool has_quiet_NaN                 = true;
827    BOOST_STATIC_CONSTEXPR bool has_signaling_NaN             = false;
828    BOOST_STATIC_CONSTEXPR float_denorm_style has_denorm      = denorm_present;
829    BOOST_STATIC_CONSTEXPR bool               has_denorm_loss = true;
infinity()830    static BOOST_MP_CXX14_CONSTEXPR number_type                        infinity() { return HUGE_VAL; /* conversion from double infinity OK */ }
quiet_NaN()831    static BOOST_MP_CXX14_CONSTEXPR number_type                        quiet_NaN() { return number_type("nan"); }
signaling_NaN()832    static BOOST_MP_CXX14_CONSTEXPR number_type                        signaling_NaN() { return 0; }
denorm_min()833    static BOOST_MP_CXX14_CONSTEXPR number_type                        denorm_min() { return BOOST_MP_QUAD_DENORM_MIN; }
834    BOOST_STATIC_CONSTEXPR bool               is_iec559       = true;
835    BOOST_STATIC_CONSTEXPR bool               is_bounded      = true;
836    BOOST_STATIC_CONSTEXPR bool               is_modulo       = false;
837    BOOST_STATIC_CONSTEXPR bool               traps           = false;
838    BOOST_STATIC_CONSTEXPR bool               tinyness_before = false;
839    BOOST_STATIC_CONSTEXPR float_round_style round_style      = round_to_nearest;
840 };
841 
842 template <boost::multiprecision::expression_template_option ExpressionTemplates>
843 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::is_specialized;
844 template <boost::multiprecision::expression_template_option ExpressionTemplates>
845 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::digits;
846 template <boost::multiprecision::expression_template_option ExpressionTemplates>
847 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::digits10;
848 template <boost::multiprecision::expression_template_option ExpressionTemplates>
849 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::max_digits10;
850 
851 template <boost::multiprecision::expression_template_option ExpressionTemplates>
852 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::is_signed;
853 template <boost::multiprecision::expression_template_option ExpressionTemplates>
854 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::is_integer;
855 template <boost::multiprecision::expression_template_option ExpressionTemplates>
856 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::is_exact;
857 template <boost::multiprecision::expression_template_option ExpressionTemplates>
858 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::radix;
859 
860 template <boost::multiprecision::expression_template_option ExpressionTemplates>
861 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::min_exponent;
862 template <boost::multiprecision::expression_template_option ExpressionTemplates>
863 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::max_exponent;
864 template <boost::multiprecision::expression_template_option ExpressionTemplates>
865 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::min_exponent10;
866 template <boost::multiprecision::expression_template_option ExpressionTemplates>
867 BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::max_exponent10;
868 
869 template <boost::multiprecision::expression_template_option ExpressionTemplates>
870 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::has_infinity;
871 template <boost::multiprecision::expression_template_option ExpressionTemplates>
872 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::has_quiet_NaN;
873 template <boost::multiprecision::expression_template_option ExpressionTemplates>
874 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::has_signaling_NaN;
875 template <boost::multiprecision::expression_template_option ExpressionTemplates>
876 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::has_denorm_loss;
877 
878 template <boost::multiprecision::expression_template_option ExpressionTemplates>
879 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::is_iec559;
880 template <boost::multiprecision::expression_template_option ExpressionTemplates>
881 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::is_bounded;
882 template <boost::multiprecision::expression_template_option ExpressionTemplates>
883 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::is_modulo;
884 template <boost::multiprecision::expression_template_option ExpressionTemplates>
885 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::traps;
886 template <boost::multiprecision::expression_template_option ExpressionTemplates>
887 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::tinyness_before;
888 
889 template <boost::multiprecision::expression_template_option ExpressionTemplates>
890 BOOST_CONSTEXPR_OR_CONST float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::round_style;
891 template <boost::multiprecision::expression_template_option ExpressionTemplates>
892 BOOST_CONSTEXPR_OR_CONST float_denorm_style numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::has_denorm;
893 
894 } // namespace std
895 
896 #endif
897