Chris@102: /////////////////////////////////////////////////////////////////////////////// Chris@102: // Copyright Christopher Kormanyos 2014. Chris@102: // Copyright John Maddock 2014. Chris@102: // Copyright Paul Bristow 2014. Chris@102: // Distributed under the Boost Software License, Chris@102: // Version 1.0. (See accompanying file LICENSE_1_0.txt Chris@102: // or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@102: // Chris@102: Chris@102: // Implement quadruple-precision I/O stream operations. Chris@102: Chris@102: #ifndef _BOOST_CSTDFLOAT_IOSTREAM_2014_02_15_HPP_ Chris@102: #define _BOOST_CSTDFLOAT_IOSTREAM_2014_02_15_HPP_ Chris@102: Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: Chris@102: #if defined(BOOST_CSTDFLOAT_NO_LIBQUADMATH_CMATH) Chris@102: #error You can not use with BOOST_CSTDFLOAT_NO_LIBQUADMATH_CMATH defined. Chris@102: #endif Chris@102: Chris@102: #if defined(BOOST_CSTDFLOAT_HAS_INTERNAL_FLOAT128_T) && defined(BOOST_MATH_USE_FLOAT128) && !defined(BOOST_CSTDFLOAT_NO_LIBQUADMATH_SUPPORT) Chris@102: Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: Chris@102: // #if (0) Chris@102: #if defined(__GNUC__) Chris@102: Chris@102: // Forward declarations of quadruple-precision string functions. Chris@102: extern "C" int quadmath_snprintf(char *str, size_t size, const char *format, ...) throw(); Chris@102: extern "C" boost::math::cstdfloat::detail::float_internal128_t strtoflt128(const char*, char **) throw(); Chris@102: Chris@102: namespace std Chris@102: { Chris@102: template Chris@102: inline std::basic_ostream& operator<<(std::basic_ostream& os, const boost::math::cstdfloat::detail::float_internal128_t& x) Chris@102: { Chris@102: std::basic_ostringstream ostr; Chris@102: ostr.flags(os.flags()); Chris@102: ostr.imbue(os.getloc()); Chris@102: ostr.precision(os.precision()); Chris@102: Chris@102: char my_buffer[64U]; Chris@102: Chris@102: const int my_prec = static_cast(os.precision()); Chris@102: const int my_digits = ((my_prec == 0) ? 36 : my_prec); Chris@102: Chris@102: const std::ios_base::fmtflags my_flags = os.flags(); Chris@102: Chris@102: char my_format_string[8U]; Chris@102: Chris@102: std::size_t my_format_string_index = 0U; Chris@102: Chris@102: my_format_string[my_format_string_index] = '%'; Chris@102: ++my_format_string_index; Chris@102: Chris@102: if(my_flags & std::ios_base::showpos) { my_format_string[my_format_string_index] = '+'; ++my_format_string_index; } Chris@102: if(my_flags & std::ios_base::showpoint) { my_format_string[my_format_string_index] = '#'; ++my_format_string_index; } Chris@102: Chris@102: my_format_string[my_format_string_index + 0U] = '.'; Chris@102: my_format_string[my_format_string_index + 1U] = '*'; Chris@102: my_format_string[my_format_string_index + 2U] = 'Q'; Chris@102: Chris@102: my_format_string_index += 3U; Chris@102: Chris@102: char the_notation_char; Chris@102: Chris@102: if (my_flags & std::ios_base::scientific) { the_notation_char = 'e'; } Chris@102: else if(my_flags & std::ios_base::fixed) { the_notation_char = 'f'; } Chris@102: else { the_notation_char = 'g'; } Chris@102: Chris@102: my_format_string[my_format_string_index + 0U] = the_notation_char; Chris@102: my_format_string[my_format_string_index + 1U] = 0; Chris@102: Chris@102: const int v = ::quadmath_snprintf(my_buffer, Chris@102: static_cast(sizeof(my_buffer)), Chris@102: my_format_string, Chris@102: my_digits, Chris@102: x); Chris@102: Chris@102: if(v < 0) { BOOST_THROW_EXCEPTION(std::runtime_error("Formatting of boost::float128_t failed internally in quadmath_snprintf().")); } Chris@102: Chris@102: if(v >= static_cast(sizeof(my_buffer) - 1U)) Chris@102: { Chris@102: // Evidently there is a really long floating-point string here, Chris@102: // such as a small decimal representation in non-scientific notation. Chris@102: // So we have to use dynamic memory allocation for the output Chris@102: // string buffer. Chris@102: Chris@102: char* my_buffer2 = static_cast(0U); Chris@102: Chris@102: try Chris@102: { Chris@102: my_buffer2 = new char[v + 3]; Chris@102: } Chris@102: catch(const std::bad_alloc&) Chris@102: { Chris@102: BOOST_THROW_EXCEPTION(std::runtime_error("Formatting of boost::float128_t failed while allocating memory.")); Chris@102: } Chris@102: Chris@102: const int v2 = ::quadmath_snprintf(my_buffer2, Chris@102: v + 3, Chris@102: my_format_string, Chris@102: my_digits, Chris@102: x); Chris@102: Chris@102: if(v2 >= v + 3) Chris@102: { Chris@102: BOOST_THROW_EXCEPTION(std::runtime_error("Formatting of boost::float128_t failed.")); Chris@102: } Chris@102: Chris@102: static_cast(ostr << my_buffer2); Chris@102: Chris@102: delete [] my_buffer2; Chris@102: } Chris@102: else Chris@102: { Chris@102: static_cast(ostr << my_buffer); Chris@102: } Chris@102: Chris@102: return (os << ostr.str()); Chris@102: } Chris@102: Chris@102: template Chris@102: inline std::basic_istream& operator>>(std::basic_istream& is, boost::math::cstdfloat::detail::float_internal128_t& x) Chris@102: { Chris@102: std::string str; Chris@102: Chris@102: static_cast(is >> str); Chris@102: Chris@102: char* p_end; Chris@102: Chris@102: x = strtoflt128(str.c_str(), &p_end); Chris@102: Chris@102: if(static_cast(p_end - str.c_str()) != static_cast(str.length())) Chris@102: { Chris@102: for(std::string::const_reverse_iterator it = str.rbegin(); it != str.rend(); ++it) Chris@102: { Chris@102: static_cast(is.putback(*it)); Chris@102: } Chris@102: Chris@102: is.setstate(ios_base::failbit); Chris@102: Chris@102: BOOST_THROW_EXCEPTION(std::runtime_error("Unable to interpret input string as a boost::float128_t")); Chris@102: } Chris@102: Chris@102: return is; Chris@102: } Chris@102: } Chris@102: Chris@102: // #elif defined(__GNUC__) Chris@102: #elif defined(BOOST_INTEL) Chris@102: Chris@102: // The section for I/O stream support for the ICC compiler is particularly Chris@102: // long, because these functions must be painstakingly synthesized from Chris@102: // manually-written routines (ICC does not support I/O stream operations Chris@102: // for its _Quad type). Chris@102: Chris@102: // The following string-extraction routines are based on the methodology Chris@102: // used in Boost.Multiprecision by John Maddock and Christopher Kormanyos. Chris@102: // This methodology has been slightly modified here for boost::float128_t. Chris@102: Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: Chris@102: namespace boost { namespace math { namespace cstdfloat { namespace detail { Chris@102: Chris@102: template Chris@102: void format_float_string(string_type& str, Chris@102: int my_exp, Chris@102: int digits, Chris@102: const std::ios_base::fmtflags f, Chris@102: const bool iszero) Chris@102: { Chris@102: typedef typename string_type::size_type size_type; Chris@102: Chris@102: const bool scientific = ((f & std::ios_base::scientific) == std::ios_base::scientific); Chris@102: const bool fixed = ((f & std::ios_base::fixed) == std::ios_base::fixed); Chris@102: const bool showpoint = ((f & std::ios_base::showpoint) == std::ios_base::showpoint); Chris@102: const bool showpos = ((f & std::ios_base::showpos) == std::ios_base::showpos); Chris@102: Chris@102: const bool b_neg = ((str.size() != 0U) && (str[0] == '-')); Chris@102: Chris@102: if(b_neg) Chris@102: { Chris@102: str.erase(0, 1); Chris@102: } Chris@102: Chris@102: if(digits == 0) Chris@102: { Chris@102: digits = static_cast((std::max)(str.size(), size_type(16))); Chris@102: } Chris@102: Chris@102: if(iszero || str.empty() || (str.find_first_not_of('0') == string_type::npos)) Chris@102: { Chris@102: // We will be printing zero, even though the value might not Chris@102: // actually be zero (it just may have been rounded to zero). Chris@102: str = "0"; Chris@102: Chris@102: if(scientific || fixed) Chris@102: { Chris@102: str.append(1, '.'); Chris@102: str.append(size_type(digits), '0'); Chris@102: Chris@102: if(scientific) Chris@102: { Chris@102: str.append("e+00"); Chris@102: } Chris@102: } Chris@102: else Chris@102: { Chris@102: if(showpoint) Chris@102: { Chris@102: str.append(1, '.'); Chris@102: if(digits > 1) Chris@102: { Chris@102: str.append(size_type(digits - 1), '0'); Chris@102: } Chris@102: } Chris@102: } Chris@102: Chris@102: if(b_neg) Chris@102: { Chris@102: str.insert(0U, 1U, '-'); Chris@102: } Chris@102: else if(showpos) Chris@102: { Chris@102: str.insert(0U, 1U, '+'); Chris@102: } Chris@102: Chris@102: return; Chris@102: } Chris@102: Chris@102: if(!fixed && !scientific && !showpoint) Chris@102: { Chris@102: // Suppress trailing zeros. Chris@102: typename string_type::iterator pos = str.end(); Chris@102: Chris@102: while(pos != str.begin() && *--pos == '0') { ; } Chris@102: Chris@102: if(pos != str.end()) Chris@102: { Chris@102: ++pos; Chris@102: } Chris@102: Chris@102: str.erase(pos, str.end()); Chris@102: Chris@102: if(str.empty()) Chris@102: { Chris@102: str = '0'; Chris@102: } Chris@102: } Chris@102: else if(!fixed || (my_exp >= 0)) Chris@102: { Chris@102: // Pad out the end with zero's if we need to. Chris@102: Chris@102: int chars = static_cast(str.size()); Chris@102: chars = digits - chars; Chris@102: Chris@102: if(scientific) Chris@102: { Chris@102: ++chars; Chris@102: } Chris@102: Chris@102: if(chars > 0) Chris@102: { Chris@102: str.append(static_cast(chars), '0'); Chris@102: } Chris@102: } Chris@102: Chris@102: if(fixed || (!scientific && (my_exp >= -4) && (my_exp < digits))) Chris@102: { Chris@102: if((1 + my_exp) > static_cast(str.size())) Chris@102: { Chris@102: // Just pad out the end with zeros. Chris@102: str.append(static_cast((1 + my_exp) - static_cast(str.size())), '0'); Chris@102: Chris@102: if(showpoint || fixed) Chris@102: { Chris@102: str.append("."); Chris@102: } Chris@102: } Chris@102: else if(my_exp + 1 < static_cast(str.size())) Chris@102: { Chris@102: if(my_exp < 0) Chris@102: { Chris@102: str.insert(0U, static_cast(-1 - my_exp), '0'); Chris@102: str.insert(0U, "0."); Chris@102: } Chris@102: else Chris@102: { Chris@102: // Insert the decimal point: Chris@102: str.insert(static_cast(my_exp + 1), 1, '.'); Chris@102: } Chris@102: } Chris@102: else if(showpoint || fixed) // we have exactly the digits we require to left of the point Chris@102: { Chris@102: str += "."; Chris@102: } Chris@102: Chris@102: if(fixed) Chris@102: { Chris@102: // We may need to add trailing zeros. Chris@102: int l = static_cast(str.find('.') + 1U); Chris@102: l = digits - (static_cast(str.size()) - l); Chris@102: Chris@102: if(l > 0) Chris@102: { Chris@102: str.append(size_type(l), '0'); Chris@102: } Chris@102: } Chris@102: } Chris@102: else Chris@102: { Chris@102: // Scientific format: Chris@102: if(showpoint || (str.size() > 1)) Chris@102: { Chris@102: str.insert(1U, 1U, '.'); Chris@102: } Chris@102: Chris@102: str.append(1U, 'e'); Chris@102: string_type e = boost::lexical_cast(std::abs(my_exp)); Chris@102: Chris@102: if(e.size() < 2U) Chris@102: { Chris@102: e.insert(0U, 2U - e.size(), '0'); Chris@102: } Chris@102: Chris@102: if(my_exp < 0) Chris@102: { Chris@102: e.insert(0U, 1U, '-'); Chris@102: } Chris@102: else Chris@102: { Chris@102: e.insert(0U, 1U, '+'); Chris@102: } Chris@102: Chris@102: str.append(e); Chris@102: } Chris@102: Chris@102: if(b_neg) Chris@102: { Chris@102: str.insert(0U, 1U, '-'); Chris@102: } Chris@102: else if(showpos) Chris@102: { Chris@102: str.insert(0U, 1U, '+'); Chris@102: } Chris@102: } Chris@102: Chris@102: template inline void eval_convert_to(type_a* pa, const float_type& cb) { *pa = static_cast(cb); } Chris@102: template inline void eval_add (float_type& b, const type_a& a) { b += a; } Chris@102: template inline void eval_subtract (float_type& b, const type_a& a) { b -= a; } Chris@102: template inline void eval_multiply (float_type& b, const type_a& a) { b *= a; } Chris@102: template inline void eval_multiply (float_type& b, const float_type& cb, const float_type& cb2) { b = (cb * cb2); } Chris@102: template inline void eval_divide (float_type& b, const type_a& a) { b /= a; } Chris@102: template inline void eval_log10 (float_type& b, const float_type& cb) { b = std::log10(cb); } Chris@102: template inline void eval_floor (float_type& b, const float_type& cb) { b = std::floor(cb); } Chris@102: Chris@102: inline void round_string_up_at(std::string& s, int pos, int& expon) Chris@102: { Chris@102: // This subroutine rounds up a string representation of a Chris@102: // number at the given position pos. Chris@102: Chris@102: if(pos < 0) Chris@102: { Chris@102: s.insert(0U, 1U, '1'); Chris@102: s.erase(s.size() - 1U); Chris@102: ++expon; Chris@102: } Chris@102: else if(s[pos] == '9') Chris@102: { Chris@102: s[pos] = '0'; Chris@102: round_string_up_at(s, pos - 1, expon); Chris@102: } Chris@102: else Chris@102: { Chris@102: if((pos == 0) && (s[pos] == '0') && (s.size() == 1)) Chris@102: { Chris@102: ++expon; Chris@102: } Chris@102: Chris@102: ++s[pos]; Chris@102: } Chris@102: } Chris@102: Chris@102: template Chris@102: std::string convert_to_string(float_type& x, Chris@102: std::streamsize digits, Chris@102: const std::ios_base::fmtflags f) Chris@102: { Chris@102: const bool isneg = (x < 0); Chris@102: const bool iszero = ((!isneg) ? bool(+x < (std::numeric_limits::min)()) Chris@102: : bool(-x < (std::numeric_limits::min)())); Chris@102: const bool isnan = (x != x); Chris@102: const bool isinf = ((!isneg) ? bool(+x > (std::numeric_limits::max)()) Chris@102: : bool(-x > (std::numeric_limits::max)())); Chris@102: Chris@102: int expon = 0; Chris@102: Chris@102: if(digits <= 0) { digits = std::numeric_limits::max_digits10; } Chris@102: Chris@102: const int org_digits = static_cast(digits); Chris@102: Chris@102: std::string result; Chris@102: Chris@102: if(iszero) Chris@102: { Chris@102: result = "0"; Chris@102: } Chris@102: else if(isinf) Chris@102: { Chris@102: if(x < 0) Chris@102: { Chris@102: return "-inf"; Chris@102: } Chris@102: else Chris@102: { Chris@102: return ((f & std::ios_base::showpos) == std::ios_base::showpos) ? "+inf" : "inf"; Chris@102: } Chris@102: } Chris@102: else if(isnan) Chris@102: { Chris@102: return "nan"; Chris@102: } Chris@102: else Chris@102: { Chris@102: // Start by figuring out the base-10 exponent. Chris@102: if(isneg) { x = -x; } Chris@102: Chris@102: float_type t; Chris@102: float_type ten = 10; Chris@102: Chris@102: eval_log10(t, x); Chris@102: eval_floor(t, t); Chris@102: eval_convert_to(&expon, t); Chris@102: Chris@102: if(-expon > std::numeric_limits::max_exponent10 - 3) Chris@102: { Chris@102: int e = -expon / 2; Chris@102: Chris@102: const float_type t2 = boost::math::cstdfloat::detail::pown(ten, e); Chris@102: Chris@102: eval_multiply(t, t2, x); Chris@102: eval_multiply(t, t2); Chris@102: Chris@102: if((expon & 1) != 0) Chris@102: { Chris@102: eval_multiply(t, ten); Chris@102: } Chris@102: } Chris@102: else Chris@102: { Chris@102: t = boost::math::cstdfloat::detail::pown(ten, -expon); Chris@102: eval_multiply(t, x); Chris@102: } Chris@102: Chris@102: // Make sure that the value lies between [1, 10), and adjust if not. Chris@102: if(t < 1) Chris@102: { Chris@102: eval_multiply(t, 10); Chris@102: Chris@102: --expon; Chris@102: } Chris@102: else if(t >= 10) Chris@102: { Chris@102: eval_divide(t, 10); Chris@102: Chris@102: ++expon; Chris@102: } Chris@102: Chris@102: float_type digit; Chris@102: int cdigit; Chris@102: Chris@102: // Adjust the number of digits required based on formatting options. Chris@102: if(((f & std::ios_base::fixed) == std::ios_base::fixed) && (expon != -1)) Chris@102: { Chris@102: digits += (expon + 1); Chris@102: } Chris@102: Chris@102: if((f & std::ios_base::scientific) == std::ios_base::scientific) Chris@102: { Chris@102: ++digits; Chris@102: } Chris@102: Chris@102: // Extract the base-10 digits one at a time. Chris@102: for(int i = 0; i < digits; ++i) Chris@102: { Chris@102: eval_floor(digit, t); Chris@102: eval_convert_to(&cdigit, digit); Chris@102: Chris@102: result += static_cast('0' + cdigit); Chris@102: Chris@102: eval_subtract(t, digit); Chris@102: eval_multiply(t, ten); Chris@102: } Chris@102: Chris@102: // Possibly round the result. Chris@102: if(digits >= 0) Chris@102: { Chris@102: eval_floor(digit, t); Chris@102: eval_convert_to(&cdigit, digit); Chris@102: eval_subtract(t, digit); Chris@102: Chris@102: if((cdigit == 5) && (t == 0)) Chris@102: { Chris@102: // Use simple bankers rounding. Chris@102: Chris@102: if((static_cast(*result.rbegin() - '0') & 1) != 0) Chris@102: { Chris@102: round_string_up_at(result, static_cast(result.size() - 1U), expon); Chris@102: } Chris@102: } Chris@102: else if(cdigit >= 5) Chris@102: { Chris@102: round_string_up_at(result, static_cast(result.size() - 1), expon); Chris@102: } Chris@102: } Chris@102: } Chris@102: Chris@102: while((result.size() > static_cast(digits)) && result.size()) Chris@102: { Chris@102: // We may get here as a result of rounding. Chris@102: Chris@102: if(result.size() > 1U) Chris@102: { Chris@102: result.erase(result.size() - 1U); Chris@102: } Chris@102: else Chris@102: { Chris@102: if(expon > 0) Chris@102: { Chris@102: --expon; // so we put less padding in the result. Chris@102: } Chris@102: else Chris@102: { Chris@102: ++expon; Chris@102: } Chris@102: Chris@102: ++digits; Chris@102: } Chris@102: } Chris@102: Chris@102: if(isneg) Chris@102: { Chris@102: result.insert(0U, 1U, '-'); Chris@102: } Chris@102: Chris@102: format_float_string(result, expon, org_digits, f, iszero); Chris@102: Chris@102: return result; Chris@102: } Chris@102: Chris@102: template Chris@102: bool convert_from_string(float_type& value, const char* p) Chris@102: { Chris@102: value = 0; Chris@102: Chris@102: if((p == static_cast(0U)) || (*p == static_cast(0))) Chris@102: { Chris@102: return; Chris@102: } Chris@102: Chris@102: bool is_neg = false; Chris@102: bool is_neg_expon = false; Chris@102: Chris@102: BOOST_CONSTEXPR_OR_CONST int ten = 10; Chris@102: Chris@102: int expon = 0; Chris@102: int digits_seen = 0; Chris@102: Chris@102: BOOST_CONSTEXPR_OR_CONST int max_digits = std::numeric_limits::max_digits10 + 1; Chris@102: Chris@102: if(*p == static_cast('+')) Chris@102: { Chris@102: ++p; Chris@102: } Chris@102: else if(*p == static_cast('-')) Chris@102: { Chris@102: is_neg = true; Chris@102: ++p; Chris@102: } Chris@102: Chris@102: const bool isnan = ((std::strcmp(p, "nan") == 0) || (std::strcmp(p, "NaN") == 0) || (std::strcmp(p, "NAN") == 0)); Chris@102: Chris@102: if(isnan) Chris@102: { Chris@102: eval_divide(value, 0); Chris@102: Chris@102: if(is_neg) Chris@102: { Chris@102: value = -value; Chris@102: } Chris@102: Chris@102: return true; Chris@102: } Chris@102: Chris@102: const bool isinf = ((std::strcmp(p, "inf") == 0) || (std::strcmp(p, "Inf") == 0) || (std::strcmp(p, "INF") == 0)); Chris@102: Chris@102: if(isinf) Chris@102: { Chris@102: value = 1; Chris@102: eval_divide(value, 0); Chris@102: Chris@102: if(is_neg) Chris@102: { Chris@102: value = -value; Chris@102: } Chris@102: Chris@102: return true; Chris@102: } Chris@102: Chris@102: // Grab all the leading digits before the decimal point. Chris@102: while(std::isdigit(*p)) Chris@102: { Chris@102: eval_multiply(value, ten); Chris@102: eval_add(value, static_cast(*p - '0')); Chris@102: ++p; Chris@102: ++digits_seen; Chris@102: } Chris@102: Chris@102: if(*p == static_cast('.')) Chris@102: { Chris@102: // Grab everything after the point, stop when we've seen Chris@102: // enough digits, even if there are actually more available. Chris@102: Chris@102: ++p; Chris@102: Chris@102: while(std::isdigit(*p)) Chris@102: { Chris@102: eval_multiply(value, ten); Chris@102: eval_add(value, static_cast(*p - '0')); Chris@102: ++p; Chris@102: --expon; Chris@102: Chris@102: if(++digits_seen > max_digits) Chris@102: { Chris@102: break; Chris@102: } Chris@102: } Chris@102: Chris@102: while(std::isdigit(*p)) Chris@102: { Chris@102: ++p; Chris@102: } Chris@102: } Chris@102: Chris@102: // Parse the exponent. Chris@102: if((*p == static_cast('e')) || (*p == static_cast('E'))) Chris@102: { Chris@102: ++p; Chris@102: Chris@102: if(*p == static_cast('+')) Chris@102: { Chris@102: ++p; Chris@102: } Chris@102: else if(*p == static_cast('-')) Chris@102: { Chris@102: is_neg_expon = true; Chris@102: ++p; Chris@102: } Chris@102: Chris@102: int e2 = 0; Chris@102: Chris@102: while(std::isdigit(*p)) Chris@102: { Chris@102: e2 *= 10; Chris@102: e2 += (*p - '0'); Chris@102: ++p; Chris@102: } Chris@102: Chris@102: if(is_neg_expon) Chris@102: { Chris@102: e2 = -e2; Chris@102: } Chris@102: Chris@102: expon += e2; Chris@102: } Chris@102: Chris@102: if(expon) Chris@102: { Chris@102: // Scale by 10^expon. Note that 10^expon can be outside the range Chris@102: // of our number type, even though the result is within range. Chris@102: // If that looks likely, then split the calculation in two parts. Chris@102: float_type t; Chris@102: t = ten; Chris@102: Chris@102: if(expon > (std::numeric_limits::min_exponent10 + 2)) Chris@102: { Chris@102: t = boost::math::cstdfloat::detail::pown(t, expon); Chris@102: eval_multiply(value, t); Chris@102: } Chris@102: else Chris@102: { Chris@102: t = boost::math::cstdfloat::detail::pown(t, (expon + digits_seen + 1)); Chris@102: eval_multiply(value, t); Chris@102: t = ten; Chris@102: t = boost::math::cstdfloat::detail::pown(t, (-digits_seen - 1)); Chris@102: eval_multiply(value, t); Chris@102: } Chris@102: } Chris@102: Chris@102: if(is_neg) Chris@102: { Chris@102: value = -value; Chris@102: } Chris@102: Chris@102: return (*p == static_cast(0)); Chris@102: } Chris@102: } } } } // boost::math::cstdfloat::detail Chris@102: Chris@102: namespace std Chris@102: { Chris@102: template Chris@102: inline std::basic_ostream& operator<<(std::basic_ostream& os, const boost::math::cstdfloat::detail::float_internal128_t& x) Chris@102: { Chris@102: boost::math::cstdfloat::detail::float_internal128_t non_const_x = x; Chris@102: Chris@102: const std::string str = boost::math::cstdfloat::detail::convert_to_string(non_const_x, Chris@102: os.precision(), Chris@102: os.flags()); Chris@102: Chris@102: std::basic_ostringstream ostr; Chris@102: ostr.flags(os.flags()); Chris@102: ostr.imbue(os.getloc()); Chris@102: ostr.precision(os.precision()); Chris@102: Chris@102: static_cast(ostr << str); Chris@102: Chris@102: return (os << ostr.str()); Chris@102: } Chris@102: Chris@102: template Chris@102: inline std::basic_istream& operator>>(std::basic_istream& is, boost::math::cstdfloat::detail::float_internal128_t& x) Chris@102: { Chris@102: std::string str; Chris@102: Chris@102: static_cast(is >> str); Chris@102: Chris@102: const bool conversion_is_ok = boost::math::cstdfloat::detail::convert_from_string(x, str.c_str()); Chris@102: Chris@102: if(false == conversion_is_ok) Chris@102: { Chris@102: for(std::string::const_reverse_iterator it = str.rbegin(); it != str.rend(); ++it) Chris@102: { Chris@102: static_cast(is.putback(*it)); Chris@102: } Chris@102: Chris@102: is.setstate(ios_base::failbit); Chris@102: Chris@102: BOOST_THROW_EXCEPTION(std::runtime_error("Unable to interpret input string as a boost::float128_t")); Chris@102: } Chris@102: Chris@102: return is; Chris@102: } Chris@102: } Chris@102: Chris@102: #endif // Use __GNUC__ or BOOST_INTEL libquadmath Chris@102: Chris@102: #endif // Not BOOST_CSTDFLOAT_NO_LIBQUADMATH_SUPPORT (i.e., the user would like to have libquadmath support) Chris@102: Chris@102: #endif // _BOOST_CSTDFLOAT_IOSTREAM_2014_02_15_HPP_