diff options
Diffstat (limited to 'boost/multiprecision/float128.hpp')
-rw-r--r-- | boost/multiprecision/float128.hpp | 569 |
1 files changed, 569 insertions, 0 deletions
diff --git a/boost/multiprecision/float128.hpp b/boost/multiprecision/float128.hpp new file mode 100644 index 0000000000..ac09519c3f --- /dev/null +++ b/boost/multiprecision/float128.hpp @@ -0,0 +1,569 @@ +/////////////////////////////////////////////////////////////// +// Copyright 2013 John Maddock. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_ + +#ifndef BOOST_MP_FLOAT128_HPP +#define BOOST_MP_FLOAT128_HPP + +#include <boost/config.hpp> +#include <boost/scoped_array.hpp> +#include <boost/multiprecision/number.hpp> + +#if defined(BOOST_INTEL) && !defined(BOOST_MP_USE_FLOAT128) && !defined(BOOST_MP_USE_QUAD) +# if defined(BOOST_INTEL_CXX_VERSION) && (BOOST_INTEL_CXX_VERSION >= 1310) && defined(__GNUC__) +# if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) +# define BOOST_MP_USE_FLOAT128 +# endif +# endif + +# ifndef BOOST_MP_USE_FLOAT128 +# define BOOST_MP_USE_QUAD +# endif +#endif + +#if defined(__GNUC__) && !defined(BOOST_MP_USE_FLOAT128) && !defined(BOOST_MP_USE_QUAD) +# define BOOST_MP_USE_FLOAT128 +#endif + +#if !defined(BOOST_MP_USE_FLOAT128) && !defined(BOOST_MP_USE_QUAD) +# error "Sorry compiler is neither GCC, not Intel, don't know how to configure this header." +#endif +#if defined(BOOST_MP_USE_FLOAT128) && defined(BOOST_MP_USE_QUAD) +# error "Oh dear, both BOOST_MP_USE_FLOAT128 and BOOST_MP_USE_QUAD are defined, which one should I be using?" +#endif + +#if defined(BOOST_MP_USE_FLOAT128) + +extern "C" { +#include <quadmath.h> +} + +typedef __float128 float128_type; + +#elif defined(BOOST_MP_USE_QUAD) + +#include <boost/multiprecision/detail/float_string_cvt.hpp> + +typedef _Quad float128_type; + +extern "C" { +_Quad __ldexpq(_Quad, int); +_Quad __frexpq(_Quad, int*); +_Quad __fabsq(_Quad); +_Quad __floorq(_Quad); +_Quad __ceilq(_Quad); +_Quad __sqrtq(_Quad); +_Quad __truncq(_Quad); +_Quad __expq(_Quad); +_Quad __powq(_Quad, _Quad); +_Quad __logq(_Quad); +_Quad __log10q(_Quad); +_Quad __sinq(_Quad); +_Quad __cosq(_Quad); +_Quad __tanq(_Quad); +_Quad __asinq(_Quad); +_Quad __acosq(_Quad); +_Quad __atanq(_Quad); +_Quad __sinhq(_Quad); +_Quad __coshq(_Quad); +_Quad __tanhq(_Quad); +_Quad __fmodq(_Quad, _Quad); +_Quad __atan2q(_Quad, _Quad); + +#define ldexpq __ldexpq +#define frexpq __frexpq +#define fabsq __fabsq +#define floorq __floorq +#define ceilq __ceilq +#define sqrtq __sqrtq +#define truncq __truncq +#define expq __expq +#define powq __powq +#define logq __logq +#define log10q __log10q +#define sinq __sinq +#define cosq __cosq +#define tanq __tanq +#define asinq __asinq +#define acosq __acosq +#define atanq __atanq +#define sinhq __sinhq +#define coshq __coshq +#define tanhq __tanhq +#define fmodq __fmodq +#define atan2q __atan2q +} + +inline _Quad isnanq(_Quad v) +{ + return v != v; +} +inline _Quad isinfq(_Quad v) +{ + return __fabsq(v) > 1.18973149535723176508575932662800702e4932Q; +} + +#endif + +namespace boost{ +namespace multiprecision{ +namespace backends{ + +struct float128_backend; + +} + +using backends::float128_backend; + +template<> +struct number_category<backends::float128_backend> : public mpl::int_<number_kind_floating_point> {}; +template<> +struct number_category<float128_type> : public mpl::int_<number_kind_floating_point> {}; + +typedef number<float128_backend, et_off> float128; + +namespace backends{ + +struct float128_backend +{ + typedef mpl::list<signed char, short, int, long, long long> signed_types; + typedef mpl::list<unsigned char, unsigned short, + unsigned int, unsigned long, unsigned long long> unsigned_types; + typedef mpl::list<float, double, long double> float_types; + typedef int exponent_type; + +private: + float128_type m_value; +public: + BOOST_CONSTEXPR float128_backend() : m_value(0) {} + BOOST_CONSTEXPR float128_backend(const float128_backend& o) : m_value(o.m_value) {} + float128_backend& operator = (const float128_backend& o) + { + m_value = o.m_value; + return *this; + } + template <class T> + BOOST_CONSTEXPR float128_backend(const T& i, const typename enable_if_c<is_convertible<T, float128_type>::value>::type* = 0) + : m_value(i) {} + template <class T> + typename enable_if_c<is_arithmetic<T>::value || is_convertible<T, float128_type>::value, float128_backend&>::type operator = (const T& i) + { + m_value = i; + return *this; + } + float128_backend& operator = (const char* s) + { +#ifndef BOOST_MP_USE_QUAD + char* p_end; + m_value = strtoflt128(s, &p_end); + if(p_end - s != (std::ptrdiff_t)std::strlen(s)) + { + BOOST_THROW_EXCEPTION(std::runtime_error("Unable to interpret input string as a floating point value")); + } +#else + boost::multiprecision::detail::convert_from_string(*this, s); +#endif + return *this; + } + void swap(float128_backend& o) + { + std::swap(m_value, o.value()); + } + std::string str(std::streamsize digits, std::ios_base::fmtflags f)const + { +#ifndef BOOST_MP_USE_QUAD + char buf[100]; + boost::scoped_array<char> buf2; + std::string format = "%"; + if(f & std::ios_base::showpos) + format += "+"; + if(f & std::ios_base::showpoint) + format += "#"; + format += ".*"; + if(digits == 0) + digits = 36; + format += "Q"; + if(f & std::ios_base::scientific) + format += "e"; + else if(f & std::ios_base::fixed) + format += "f"; + else + format += "g"; + + int v = quadmath_snprintf (buf, 100, format.c_str(), digits, m_value); + + if((v < 0) || (v >= 99)) + { + int v_max = v; + buf2.reset(new char[v+3]); + v = quadmath_snprintf (&buf2[0], v_max + 3, format.c_str(), digits, m_value); + if(v >= v_max + 3) + { + BOOST_THROW_EXCEPTION(std::runtime_error("Formatting of float128_type failed.")); + } + return &buf2[0]; + } + return buf; +#else + return boost::multiprecision::detail::convert_to_string(*this, digits ? digits : 37, f); +#endif + } + void negate() + { + m_value = -m_value; + } + int compare(const float128_backend& o)const + { + return m_value == o.m_value ? 0 : m_value < o.m_value ? -1 : 1; + } + template <class T> + int compare(const T& i)const + { + return m_value == i ? 0 : m_value < i ? -1 : 1; + } + float128_type& value() + { + return m_value; + } + const float128_type& value()const + { + return m_value; + } +}; + +inline void eval_add(float128_backend& result, const float128_backend& a) +{ + result.value() += a.value(); +} +template <class A> +inline void eval_add(float128_backend& result, const A& a) +{ + result.value() += a; +} +inline void eval_subtract(float128_backend& result, const float128_backend& a) +{ + result.value() -= a.value(); +} +template <class A> +inline void eval_subtract(float128_backend& result, const A& a) +{ + result.value() -= a; +} +inline void eval_multiply(float128_backend& result, const float128_backend& a) +{ + result.value() *= a.value(); +} +template <class A> +inline void eval_multiply(float128_backend& result, const A& a) +{ + result.value() *= a; +} +inline void eval_divide(float128_backend& result, const float128_backend& a) +{ + result.value() /= a.value(); +} +template <class A> +inline void eval_divide(float128_backend& result, const A& a) +{ + result.value() /= a; +} + +inline void eval_add(float128_backend& result, const float128_backend& a, const float128_backend& b) +{ + result.value() = a.value() + b.value(); +} +template <class A> +inline void eval_add(float128_backend& result, const float128_backend& a, const A& b) +{ + result.value() = a.value() + b; +} +inline void eval_subtract(float128_backend& result, const float128_backend& a, const float128_backend& b) +{ + result.value() = a.value() - b.value(); +} +template <class A> +inline void eval_subtract(float128_backend& result, const float128_backend& a, const A& b) +{ + result.value() = a.value() - b; +} +template <class A> +inline void eval_subtract(float128_backend& result, const A& a, const float128_backend& b) +{ + result.value() = a - b.value(); +} +inline void eval_multiply(float128_backend& result, const float128_backend& a, const float128_backend& b) +{ + result.value() = a.value() * b.value(); +} +template <class A> +inline void eval_multiply(float128_backend& result, const float128_backend& a, const A& b) +{ + result.value() = a.value() * b; +} +inline void eval_divide(float128_backend& result, const float128_backend& a, const float128_backend& b) +{ + result.value() = a.value() / b.value(); +} + +template <class R> +inline void eval_convert_to(R* result, const float128_backend& val) +{ + *result = static_cast<R>(val.value()); +} + +inline void eval_frexp(float128_backend& result, const float128_backend& arg, int* exp) +{ + result.value() = frexpq(arg.value(), exp); +} + +inline void eval_ldexp(float128_backend& result, const float128_backend& arg, int exp) +{ + result.value() = ldexpq(arg.value(), exp); +} + +inline void eval_floor(float128_backend& result, const float128_backend& arg) +{ + result.value() = floorq(arg.value()); +} +inline void eval_ceil(float128_backend& result, const float128_backend& arg) +{ + result.value() = ceilq(arg.value()); +} +inline void eval_sqrt(float128_backend& result, const float128_backend& arg) +{ + result.value() = sqrtq(arg.value()); +} +inline int eval_fpclassify(const float128_backend& arg) +{ + return isnanq(arg.value()) ? FP_NAN : isinfq(arg.value()) ? FP_INFINITE : arg.value() == 0 ? FP_ZERO : FP_NORMAL; +} + +inline void eval_increment(float128_backend& arg) +{ + ++arg.value(); +} +inline void eval_decrement(float128_backend& arg) +{ + --arg.value(); +} + +/********************************************************************* +* +* abs/fabs: +* +*********************************************************************/ + +inline void eval_abs(float128_backend& result, const float128_backend& arg) +{ + result.value() = fabsq(arg.value()); +} +inline void eval_fabs(float128_backend& result, const float128_backend& arg) +{ + result.value() = fabsq(arg.value()); +} + +/********************************************************************* +* +* Floating point functions: +* +*********************************************************************/ + +inline void eval_trunc(float128_backend& result, const float128_backend& arg) +{ + if(isnanq(arg.value()) || isinfq(arg.value())) + { + result = boost::math::policies::raise_rounding_error( + "boost::multiprecision::trunc<%1%>(%1%)", 0, + number<float128_backend, et_off>(arg), + number<float128_backend, et_off>(arg), + boost::math::policies::policy<>()).backend(); + return; + } + result.value() = truncq(arg.value()); +} +/* +// +// This doesn't actually work... rely on our own default version instead. +// +inline void eval_round(float128_backend& result, const float128_backend& arg) +{ + if(isnanq(arg.value()) || isinf(arg.value())) + { + result = boost::math::policies::raise_rounding_error( + "boost::multiprecision::trunc<%1%>(%1%)", 0, + number<float128_backend, et_off>(arg), + number<float128_backend, et_off>(arg), + boost::math::policies::policy<>()).backend(); + return; + } + result.value() = roundq(arg.value()); +} +*/ + +inline void eval_exp(float128_backend& result, const float128_backend& arg) +{ + result.value() = expq(arg.value()); +} +inline void eval_log(float128_backend& result, const float128_backend& arg) +{ + result.value() = logq(arg.value()); +} +inline void eval_log10(float128_backend& result, const float128_backend& arg) +{ + result.value() = log10q(arg.value()); +} +inline void eval_sin(float128_backend& result, const float128_backend& arg) +{ + result.value() = sinq(arg.value()); +} +inline void eval_cos(float128_backend& result, const float128_backend& arg) +{ + result.value() = cosq(arg.value()); +} +inline void eval_tan(float128_backend& result, const float128_backend& arg) +{ + result.value() = tanq(arg.value()); +} +inline void eval_asin(float128_backend& result, const float128_backend& arg) +{ + result.value() = asinq(arg.value()); +} +inline void eval_acos(float128_backend& result, const float128_backend& arg) +{ + result.value() = acosq(arg.value()); +} +inline void eval_atan(float128_backend& result, const float128_backend& arg) +{ + result.value() = atanq(arg.value()); +} +inline void eval_sinh(float128_backend& result, const float128_backend& arg) +{ + result.value() = sinhq(arg.value()); +} +inline void eval_cosh(float128_backend& result, const float128_backend& arg) +{ + result.value() = coshq(arg.value()); +} +inline void eval_tanh(float128_backend& result, const float128_backend& arg) +{ + result.value() = tanhq(arg.value()); +} +inline void eval_fmod(float128_backend& result, const float128_backend& a, const float128_backend& b) +{ + result.value() = fmodq(a.value(), b.value()); +} +inline void eval_pow(float128_backend& result, const float128_backend& a, const float128_backend& b) +{ + result.value() = powq(a.value(), b.value()); +} +inline void eval_atan2(float128_backend& result, const float128_backend& a, const float128_backend& b) +{ + result.value() = atan2q(a.value(), b.value()); +} + +} // namespace backends + +}} // namespaces + +namespace boost{ +namespace archive{ + +class binary_oarchive; +class binary_iarchive; + +} + +namespace serialization{ namespace float128_detail{ + +template <class Archive> +void do_serialize(Archive& ar, boost::multiprecision::backends::float128_backend& val, const mpl::false_&, const mpl::false_&) +{ + // saving + // non-binary + std::string s(val.str(0, std::ios_base::scientific)); + ar & s; +} +template <class Archive> +void do_serialize(Archive& ar, boost::multiprecision::backends::float128_backend& val, const mpl::true_&, const mpl::false_&) +{ + // loading + // non-binary + std::string s; + ar & s; + val = s.c_str(); +} + +template <class Archive> +void do_serialize(Archive& ar, boost::multiprecision::backends::float128_backend& val, const mpl::false_&, const mpl::true_&) +{ + // saving + // binary + ar.save_binary(&val, sizeof(val)); +} +template <class Archive> +void do_serialize(Archive& ar, boost::multiprecision::backends::float128_backend& val, const mpl::true_&, const mpl::true_&) +{ + // loading + // binary + ar.load_binary(&val, sizeof(val)); +} + +} // detail + +template <class Archive> +void serialize(Archive& ar, boost::multiprecision::backends::float128_backend& val, unsigned int /*version*/) +{ + typedef typename Archive::is_loading load_tag; + typedef typename mpl::bool_<boost::is_same<Archive, boost::archive::binary_oarchive>::value || boost::is_same<Archive, boost::archive::binary_iarchive>::value> binary_tag; + + float128_detail::do_serialize(ar, val, load_tag(), binary_tag()); +} + +}} + +namespace std{ + +template <boost::multiprecision::expression_template_option ExpressionTemplates> +class numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> > +{ + typedef boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> number_type; +public: + BOOST_STATIC_CONSTEXPR bool is_specialized = true; + static number_type (min)() BOOST_NOEXCEPT { return 3.36210314311209350626267781732175260e-4932Q; } + static number_type (max)() BOOST_NOEXCEPT { return 1.18973149535723176508575932662800702e4932Q; } + static number_type lowest() BOOST_NOEXCEPT { return -(max)(); } + BOOST_STATIC_CONSTEXPR int digits = 113; + BOOST_STATIC_CONSTEXPR int digits10 = 34; + BOOST_STATIC_CONSTEXPR int max_digits10 = 36; + BOOST_STATIC_CONSTEXPR bool is_signed = true; + BOOST_STATIC_CONSTEXPR bool is_integer = false; + BOOST_STATIC_CONSTEXPR bool is_exact = false; + BOOST_STATIC_CONSTEXPR int radix = 2; + static number_type epsilon() { return 1.92592994438723585305597794258492732e-34Q; } + static number_type round_error() { return 0.5; } + BOOST_STATIC_CONSTEXPR int min_exponent = -16381; + BOOST_STATIC_CONSTEXPR int min_exponent10 = min_exponent * 301L / 1000L; + BOOST_STATIC_CONSTEXPR int max_exponent = 16384; + BOOST_STATIC_CONSTEXPR int max_exponent10 = max_exponent * 301L / 1000L; + BOOST_STATIC_CONSTEXPR bool has_infinity = true; + BOOST_STATIC_CONSTEXPR bool has_quiet_NaN = true; + BOOST_STATIC_CONSTEXPR bool has_signaling_NaN = false; + BOOST_STATIC_CONSTEXPR float_denorm_style has_denorm = denorm_absent; + BOOST_STATIC_CONSTEXPR bool has_denorm_loss = false; + static number_type infinity() { return 1.0q / 0.0q; } + static number_type quiet_NaN() { return number_type("nan"); } + static number_type signaling_NaN() { return 0; } + static number_type denorm_min() { return 0; } + BOOST_STATIC_CONSTEXPR bool is_iec559 = true; + BOOST_STATIC_CONSTEXPR bool is_bounded = false; + BOOST_STATIC_CONSTEXPR bool is_modulo = false; + BOOST_STATIC_CONSTEXPR bool traps = false; + BOOST_STATIC_CONSTEXPR bool tinyness_before = false; + BOOST_STATIC_CONSTEXPR float_round_style round_style = round_to_nearest; +}; + +} // namespace std + + +#endif |