File indexing completed on 2025-07-01 08:19:08
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef BOOST_MATH_CSTDFLOAT_IOSTREAM_2014_02_15_HPP_
0013 #define BOOST_MATH_CSTDFLOAT_IOSTREAM_2014_02_15_HPP_
0014
0015 #include <boost/math/cstdfloat/cstdfloat_types.hpp>
0016 #include <boost/math/cstdfloat/cstdfloat_limits.hpp>
0017 #include <boost/math/cstdfloat/cstdfloat_cmath.hpp>
0018
0019 #if defined(BOOST_CSTDFLOAT_NO_LIBQUADMATH_CMATH)
0020 #error You can not use <boost/math/cstdfloat/cstdfloat_iostream.hpp> with BOOST_CSTDFLOAT_NO_LIBQUADMATH_CMATH defined.
0021 #endif
0022
0023 #if defined(BOOST_CSTDFLOAT_HAS_INTERNAL_FLOAT128_T) && defined(BOOST_MATH_USE_FLOAT128) && !defined(BOOST_CSTDFLOAT_NO_LIBQUADMATH_SUPPORT)
0024
0025 #include <cstddef>
0026 #include <istream>
0027 #include <ostream>
0028 #include <sstream>
0029 #include <stdexcept>
0030 #include <string>
0031 #include <boost/math/tools/assert.hpp>
0032 #include <boost/math/tools/nothrow.hpp>
0033 #include <boost/math/tools/throw_exception.hpp>
0034
0035 namespace boost {
0036 namespace math {
0037 namespace detail {
0038
0039
0040
0041
0042
0043
0044
0045 inline std::string read_string_while(std::istream& is, std::string const& permitted_chars)
0046 {
0047 std::ios_base::iostate state = std::ios_base::goodbit;
0048 const std::istream::sentry sentry_check(is);
0049 std::string result;
0050
0051 if (sentry_check)
0052 {
0053 int c = is.rdbuf()->sgetc();
0054
0055 for (;; c = is.rdbuf()->snextc())
0056 if (std::istream::traits_type::eq_int_type(std::istream::traits_type::eof(), c))
0057 {
0058 state |= std::ios_base::eofbit;
0059 break;
0060 }
0061 else if (permitted_chars.find_first_of(std::istream::traits_type::to_char_type(c)) == std::string::npos)
0062 {
0063
0064
0065 break;
0066 }
0067 else
0068 {
0069 result.append(1, std::istream::traits_type::to_char_type(c));
0070 }
0071 }
0072
0073 if (!result.size())
0074 state |= std::ios_base::failbit;
0075 is.setstate(state);
0076 return result;
0077 }
0078
0079 }
0080 }
0081 }
0082
0083 #if defined(__GNUC__) && !defined(BOOST_MATH_TEST_IO_AS_INTEL_QUAD)
0084
0085
0086 extern "C" int quadmath_snprintf(char *str, size_t size, const char *format, ...) BOOST_MATH_NOTHROW;
0087 extern "C" boost::math::cstdfloat::detail::float_internal128_t strtoflt128(const char*, char **) BOOST_MATH_NOTHROW;
0088
0089 namespace std
0090 {
0091 template<typename char_type, class traits_type>
0092 inline std::basic_ostream<char_type, traits_type>& operator<<(std::basic_ostream<char_type, traits_type>& os, const boost::math::cstdfloat::detail::float_internal128_t& x)
0093 {
0094 std::basic_ostringstream<char_type, traits_type> ostr;
0095 ostr.flags(os.flags());
0096 ostr.imbue(os.getloc());
0097 ostr.precision(os.precision());
0098
0099 char my_buffer[64U];
0100
0101 const int my_prec = static_cast<int>(os.precision());
0102 const int my_digits = ((my_prec == 0) ? 36 : my_prec);
0103
0104 const std::ios_base::fmtflags my_flags = os.flags();
0105
0106 char my_format_string[8U];
0107
0108 std::size_t my_format_string_index = 0U;
0109
0110 my_format_string[my_format_string_index] = '%';
0111 ++my_format_string_index;
0112
0113 if(my_flags & std::ios_base::showpos) { my_format_string[my_format_string_index] = '+'; ++my_format_string_index; }
0114 if(my_flags & std::ios_base::showpoint) { my_format_string[my_format_string_index] = '#'; ++my_format_string_index; }
0115
0116 my_format_string[my_format_string_index + 0U] = '.';
0117 my_format_string[my_format_string_index + 1U] = '*';
0118 my_format_string[my_format_string_index + 2U] = 'Q';
0119
0120 my_format_string_index += 3U;
0121
0122 char the_notation_char;
0123
0124 if (my_flags & std::ios_base::scientific) { the_notation_char = 'e'; }
0125 else if(my_flags & std::ios_base::fixed) { the_notation_char = 'f'; }
0126 else { the_notation_char = 'g'; }
0127
0128 my_format_string[my_format_string_index + 0U] = the_notation_char;
0129 my_format_string[my_format_string_index + 1U] = 0;
0130
0131 const int v = ::quadmath_snprintf(my_buffer,
0132 static_cast<int>(sizeof(my_buffer)),
0133 my_format_string,
0134 my_digits,
0135 x);
0136
0137 if(v < 0) { BOOST_MATH_THROW_EXCEPTION(std::runtime_error("Formatting of boost::float128_t failed internally in quadmath_snprintf().")); }
0138
0139 if(v >= static_cast<int>(sizeof(my_buffer) - 1U))
0140 {
0141
0142
0143
0144
0145
0146 char* my_buffer2 = nullptr;
0147
0148 #ifndef BOOST_MATH_NO_EXCEPTIONS
0149 try
0150 {
0151 #endif
0152 my_buffer2 = new char[v + 3];
0153 #ifndef BOOST_MATH_NO_EXCEPTIONS
0154 }
0155 catch(const std::bad_alloc&)
0156 {
0157 BOOST_MATH_THROW_EXCEPTION(std::runtime_error("Formatting of boost::float128_t failed while allocating memory."));
0158 }
0159 #endif
0160 const int v2 = ::quadmath_snprintf(my_buffer2,
0161 v + 3,
0162 my_format_string,
0163 my_digits,
0164 x);
0165
0166 if(v2 >= v + 3)
0167 {
0168 BOOST_MATH_THROW_EXCEPTION(std::runtime_error("Formatting of boost::float128_t failed."));
0169 }
0170
0171 static_cast<void>(ostr << my_buffer2);
0172
0173 delete [] my_buffer2;
0174 }
0175 else
0176 {
0177 static_cast<void>(ostr << my_buffer);
0178 }
0179
0180 return (os << ostr.str());
0181 }
0182
0183 template<typename char_type, class traits_type>
0184 inline std::basic_istream<char_type, traits_type>& operator>>(std::basic_istream<char_type, traits_type>& is, boost::math::cstdfloat::detail::float_internal128_t& x)
0185 {
0186 std::string str = boost::math::detail::read_string_while(is, "+-eE.0123456789infINFnanNANinfinityINFINITY");
0187
0188 char* p_end;
0189
0190 x = strtoflt128(str.c_str(), &p_end);
0191
0192 if(static_cast<std::ptrdiff_t>(p_end - str.c_str()) != static_cast<std::ptrdiff_t>(str.length()))
0193 {
0194 for(std::string::const_reverse_iterator it = str.rbegin(); it != str.rend(); ++it)
0195 {
0196 static_cast<void>(is.putback(*it));
0197 }
0198
0199 is.setstate(ios_base::failbit);
0200
0201 BOOST_MATH_THROW_EXCEPTION(std::runtime_error("Unable to interpret input string as a boost::float128_t"));
0202 }
0203
0204 return is;
0205 }
0206 }
0207
0208 #elif defined(__INTEL_COMPILER) || defined(BOOST_MATH_TEST_IO_AS_INTEL_QUAD)
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220 #include <cstring>
0221 #include <cctype>
0222
0223 namespace boost { namespace math { namespace cstdfloat { namespace detail {
0224
0225 template<class string_type>
0226 void format_float_string(string_type& str,
0227 int my_exp,
0228 int digits,
0229 const std::ios_base::fmtflags f,
0230 const bool iszero)
0231 {
0232 typedef typename string_type::size_type size_type;
0233
0234 const bool scientific = ((f & std::ios_base::scientific) == std::ios_base::scientific);
0235 const bool fixed = ((f & std::ios_base::fixed) == std::ios_base::fixed);
0236 const bool showpoint = ((f & std::ios_base::showpoint) == std::ios_base::showpoint);
0237 const bool showpos = ((f & std::ios_base::showpos) == std::ios_base::showpos);
0238
0239 const bool b_neg = ((str.size() != 0U) && (str[0] == '-'));
0240
0241 if(b_neg)
0242 {
0243 str.erase(0, 1);
0244 }
0245
0246 if(digits == 0)
0247 {
0248 digits = static_cast<int>((std::max)(str.size(), size_type(16)));
0249 }
0250
0251 if(iszero || str.empty() || (str.find_first_not_of('0') == string_type::npos))
0252 {
0253
0254
0255 str = "0";
0256
0257 if(scientific || fixed)
0258 {
0259 str.append(1, '.');
0260 str.append(size_type(digits), '0');
0261
0262 if(scientific)
0263 {
0264 str.append("e+00");
0265 }
0266 }
0267 else
0268 {
0269 if(showpoint)
0270 {
0271 str.append(1, '.');
0272 if(digits > 1)
0273 {
0274 str.append(size_type(digits - 1), '0');
0275 }
0276 }
0277 }
0278
0279 if(b_neg)
0280 {
0281 str.insert(0U, 1U, '-');
0282 }
0283 else if(showpos)
0284 {
0285 str.insert(0U, 1U, '+');
0286 }
0287
0288 return;
0289 }
0290
0291 if(!fixed && !scientific && !showpoint)
0292 {
0293
0294 typename string_type::iterator pos = str.end();
0295
0296 while(pos != str.begin() && *--pos == '0') { ; }
0297
0298 if(pos != str.end())
0299 {
0300 ++pos;
0301 }
0302
0303 str.erase(pos, str.end());
0304
0305 if(str.empty())
0306 {
0307 str = '0';
0308 }
0309 }
0310 else if(!fixed || (my_exp >= 0))
0311 {
0312
0313
0314 std::ptrdiff_t chars = static_cast<std::ptrdiff_t>(str.size());
0315 chars = digits - chars;
0316
0317 if(scientific)
0318 {
0319 ++chars;
0320 }
0321
0322 if(chars > 0)
0323 {
0324 str.append(static_cast<size_type>(chars), '0');
0325 }
0326 }
0327
0328 if(fixed || (!scientific && (my_exp >= -4) && (my_exp < digits)))
0329 {
0330 if((1 + my_exp) > static_cast<int>(str.size()))
0331 {
0332
0333 str.append(static_cast<size_type>((1 + my_exp) - static_cast<int>(str.size())), '0');
0334
0335 if(showpoint || fixed)
0336 {
0337 str.append(".");
0338 }
0339 }
0340 else if(my_exp + 1 < static_cast<int>(str.size()))
0341 {
0342 if(my_exp < 0)
0343 {
0344 str.insert(0U, static_cast<size_type>(-1 - my_exp), '0');
0345 str.insert(0U, "0.");
0346 }
0347 else
0348 {
0349
0350 str.insert(static_cast<size_type>(my_exp + 1), 1, '.');
0351 }
0352 }
0353 else if(showpoint || fixed)
0354 {
0355 str += ".";
0356 }
0357
0358 if(fixed)
0359 {
0360
0361 int l = static_cast<int>(str.find('.') + 1U);
0362 l = digits - (static_cast<int>(str.size()) - l);
0363
0364 if(l > 0)
0365 {
0366 str.append(size_type(l), '0');
0367 }
0368 }
0369 }
0370 else
0371 {
0372
0373 if(showpoint || (str.size() > 1))
0374 {
0375 str.insert(1U, 1U, '.');
0376 }
0377
0378 str.append(1U, 'e');
0379
0380 string_type e = std::to_string(std::abs(my_exp));
0381
0382 if(e.size() < 2U)
0383 {
0384 e.insert(0U, 2U - e.size(), '0');
0385 }
0386
0387 if(my_exp < 0)
0388 {
0389 e.insert(0U, 1U, '-');
0390 }
0391 else
0392 {
0393 e.insert(0U, 1U, '+');
0394 }
0395
0396 str.append(e);
0397 }
0398
0399 if(b_neg)
0400 {
0401 str.insert(0U, 1U, '-');
0402 }
0403 else if(showpos)
0404 {
0405 str.insert(0U, 1U, '+');
0406 }
0407 }
0408
0409 template<class float_type, class type_a> inline void eval_convert_to(type_a* pa, const float_type& cb) { *pa = static_cast<type_a>(cb); }
0410 template<class float_type, class type_a> inline void eval_add (float_type& b, const type_a& a) { b += a; }
0411 template<class float_type, class type_a> inline void eval_subtract (float_type& b, const type_a& a) { b -= a; }
0412 template<class float_type, class type_a> inline void eval_multiply (float_type& b, const type_a& a) { b *= a; }
0413 template<class float_type> inline void eval_multiply (float_type& b, const float_type& cb, const float_type& cb2) { b = (cb * cb2); }
0414 template<class float_type, class type_a> inline void eval_divide (float_type& b, const type_a& a) { b /= a; }
0415 template<class float_type> inline void eval_log10 (float_type& b, const float_type& cb) { b = std::log10(cb); }
0416 template<class float_type> inline void eval_floor (float_type& b, const float_type& cb) { b = std::floor(cb); }
0417
0418 inline void round_string_up_at(std::string& s, int pos, int& expon)
0419 {
0420
0421
0422
0423 if(pos < 0)
0424 {
0425 s.insert(0U, 1U, '1');
0426 s.erase(s.size() - 1U);
0427 ++expon;
0428 }
0429 else if(s[pos] == '9')
0430 {
0431 s[pos] = '0';
0432 round_string_up_at(s, pos - 1, expon);
0433 }
0434 else
0435 {
0436 if((pos == 0) && (s[pos] == '0') && (s.size() == 1))
0437 {
0438 ++expon;
0439 }
0440
0441 ++s[pos];
0442 }
0443 }
0444
0445 template<class float_type>
0446 std::string convert_to_string(float_type& x,
0447 std::streamsize digits,
0448 const std::ios_base::fmtflags f)
0449 {
0450 const bool isneg = (x < 0);
0451 const bool iszero = ((!isneg) ? bool(+x < (std::numeric_limits<float_type>::min)())
0452 : bool(-x < (std::numeric_limits<float_type>::min)()));
0453 const bool isnan = (x != x);
0454 const bool isinf = ((!isneg) ? bool(+x > (std::numeric_limits<float_type>::max)())
0455 : bool(-x > (std::numeric_limits<float_type>::max)()));
0456
0457 int expon = 0;
0458
0459 if(digits <= 0) { digits = std::numeric_limits<float_type>::max_digits10; }
0460
0461 const int org_digits = static_cast<int>(digits);
0462
0463 std::string result;
0464
0465 if(iszero)
0466 {
0467 result = "0";
0468 }
0469 else if(isinf)
0470 {
0471 if(x < 0)
0472 {
0473 return "-inf";
0474 }
0475 else
0476 {
0477 return ((f & std::ios_base::showpos) == std::ios_base::showpos) ? "+inf" : "inf";
0478 }
0479 }
0480 else if(isnan)
0481 {
0482 return "nan";
0483 }
0484 else
0485 {
0486
0487 if(isneg) { x = -x; }
0488
0489 float_type t;
0490 constexpr float_type ten = 10;
0491
0492 eval_log10(t, x);
0493 eval_floor(t, t);
0494 eval_convert_to(&expon, t);
0495
0496 if(-expon > std::numeric_limits<float_type>::max_exponent10 - 3)
0497 {
0498 int e = -expon / 2;
0499
0500 const float_type t2 = boost::math::cstdfloat::detail::pown(ten, e);
0501
0502 eval_multiply(t, t2, x);
0503 eval_multiply(t, t2);
0504
0505 if((expon & 1) != 0)
0506 {
0507 eval_multiply(t, ten);
0508 }
0509 }
0510 else
0511 {
0512 t = boost::math::cstdfloat::detail::pown(ten, -expon);
0513 eval_multiply(t, x);
0514 }
0515
0516
0517 if(t < 1)
0518 {
0519 eval_multiply(t, 10);
0520
0521 --expon;
0522 }
0523 else if(t >= 10)
0524 {
0525 eval_divide(t, 10);
0526
0527 ++expon;
0528 }
0529
0530 float_type digit;
0531 int cdigit;
0532
0533
0534 if(((f & std::ios_base::fixed) == std::ios_base::fixed) && (expon != -1))
0535 {
0536 digits += (expon + 1);
0537 }
0538
0539 if((f & std::ios_base::scientific) == std::ios_base::scientific)
0540 {
0541 ++digits;
0542 }
0543
0544
0545 for(int i = 0; i < digits; ++i)
0546 {
0547 eval_floor(digit, t);
0548 eval_convert_to(&cdigit, digit);
0549
0550 result += static_cast<char>('0' + cdigit);
0551
0552 eval_subtract(t, digit);
0553 eval_multiply(t, ten);
0554 }
0555 if (result.size() == 0)
0556 result = "0";
0557
0558
0559 if(digits >= 0)
0560 {
0561 eval_floor(digit, t);
0562 eval_convert_to(&cdigit, digit);
0563 eval_subtract(t, digit);
0564
0565 if((cdigit == 5) && (t == 0))
0566 {
0567
0568
0569 if((static_cast<int>(*result.rbegin() - '0') & 1) != 0)
0570 {
0571 round_string_up_at(result, static_cast<int>(result.size() - 1U), expon);
0572 if (digits == 0) digits = 1;
0573 }
0574 }
0575 else if(cdigit >= 5)
0576 {
0577 round_string_up_at(result, static_cast<int>(result.size() - 1u), expon);
0578 if (digits == 0) digits = 1;
0579 }
0580 }
0581 }
0582
0583 while((result.size() > static_cast<std::string::size_type>(digits)) && result.size())
0584 {
0585
0586
0587 if(result.size() > 1U)
0588 {
0589 result.erase(result.size() - 1U);
0590 }
0591 else
0592 {
0593 if(expon > 0)
0594 {
0595 --expon;
0596 }
0597 else
0598 {
0599 ++expon;
0600 }
0601
0602 ++digits;
0603 }
0604 }
0605
0606 if(isneg)
0607 {
0608 result.insert(0U, 1U, '-');
0609 }
0610
0611 format_float_string(result, expon, org_digits, f, iszero);
0612
0613 return result;
0614 }
0615
0616 template <class float_type>
0617 bool convert_from_string(float_type& value, const char* p)
0618 {
0619 value = 0;
0620
0621 if((p == nullptr) || (*p == '\0'))
0622 {
0623 return false;
0624 }
0625
0626 bool is_neg = false;
0627 bool is_neg_expon = false;
0628
0629 constexpr int ten = 10;
0630
0631 int expon = 0;
0632 int digits_seen = 0;
0633
0634 constexpr int max_digits = std::numeric_limits<float_type>::max_digits10 + 1;
0635
0636 if(*p == '+')
0637 {
0638 ++p;
0639 }
0640 else if(*p == '-')
0641 {
0642 is_neg = true;
0643 ++p;
0644 }
0645
0646 const bool isnan = ((std::strcmp(p, "nan") == 0) || (std::strcmp(p, "NaN") == 0) || (std::strcmp(p, "NAN") == 0));
0647
0648 if(isnan)
0649 {
0650 eval_divide(value, 0);
0651
0652 if(is_neg)
0653 {
0654 value = -value;
0655 }
0656
0657 return true;
0658 }
0659
0660 const bool isinf = ((std::strcmp(p, "inf") == 0) || (std::strcmp(p, "Inf") == 0) || (std::strcmp(p, "INF") == 0));
0661
0662 if(isinf)
0663 {
0664 value = 1;
0665 eval_divide(value, 0);
0666
0667 if(is_neg)
0668 {
0669 value = -value;
0670 }
0671
0672 return true;
0673 }
0674
0675
0676 while(std::isdigit(*p))
0677 {
0678 eval_multiply(value, ten);
0679 eval_add(value, static_cast<int>(*p - '0'));
0680 ++p;
0681 ++digits_seen;
0682 }
0683
0684 if(*p == '.')
0685 {
0686
0687
0688
0689 ++p;
0690
0691 while(std::isdigit(*p))
0692 {
0693 eval_multiply(value, ten);
0694 eval_add(value, static_cast<int>(*p - '0'));
0695 ++p;
0696 --expon;
0697
0698 if(++digits_seen > max_digits)
0699 {
0700 break;
0701 }
0702 }
0703
0704 while(std::isdigit(*p))
0705 {
0706 ++p;
0707 }
0708 }
0709
0710
0711 if((*p == 'e') || (*p == 'E'))
0712 {
0713 ++p;
0714
0715 if(*p == '+')
0716 {
0717 ++p;
0718 }
0719 else if(*p == '-')
0720 {
0721 is_neg_expon = true;
0722 ++p;
0723 }
0724
0725 int e2 = 0;
0726
0727 while(std::isdigit(*p))
0728 {
0729 e2 *= 10;
0730 e2 += (*p - '0');
0731 ++p;
0732 }
0733
0734 if(is_neg_expon)
0735 {
0736 e2 = -e2;
0737 }
0738
0739 expon += e2;
0740 }
0741
0742 if(expon)
0743 {
0744
0745
0746
0747 float_type t;
0748 t = ten;
0749
0750 if(expon > (std::numeric_limits<float_type>::min_exponent10 + 2))
0751 {
0752 t = boost::math::cstdfloat::detail::pown(t, expon);
0753 eval_multiply(value, t);
0754 }
0755 else
0756 {
0757 t = boost::math::cstdfloat::detail::pown(t, (expon + digits_seen + 1));
0758 eval_multiply(value, t);
0759 t = ten;
0760 t = boost::math::cstdfloat::detail::pown(t, (-digits_seen - 1));
0761 eval_multiply(value, t);
0762 }
0763 }
0764
0765 if(is_neg)
0766 {
0767 value = -value;
0768 }
0769
0770 return (*p == '\0');
0771 }
0772 } } } }
0773
0774 namespace std
0775 {
0776 template<typename char_type, class traits_type>
0777 inline std::basic_ostream<char_type, traits_type>& operator<<(std::basic_ostream<char_type, traits_type>& os, const boost::math::cstdfloat::detail::float_internal128_t& x)
0778 {
0779 boost::math::cstdfloat::detail::float_internal128_t non_const_x = x;
0780
0781 const std::string str = boost::math::cstdfloat::detail::convert_to_string(non_const_x,
0782 os.precision(),
0783 os.flags());
0784
0785 std::basic_ostringstream<char_type, traits_type> ostr;
0786 ostr.flags(os.flags());
0787 ostr.imbue(os.getloc());
0788 ostr.precision(os.precision());
0789
0790 static_cast<void>(ostr << str);
0791
0792 return (os << ostr.str());
0793 }
0794
0795 template<typename char_type, class traits_type>
0796 inline std::basic_istream<char_type, traits_type>& operator>>(std::basic_istream<char_type, traits_type>& is, boost::math::cstdfloat::detail::float_internal128_t& x)
0797 {
0798 std::string str = boost::math::detail::read_string_while(is, "+-eE.0123456789infINFnanNANinfinityINFINITY");
0799
0800 const bool conversion_is_ok = boost::math::cstdfloat::detail::convert_from_string(x, str.c_str());
0801
0802 if(false == conversion_is_ok)
0803 {
0804 for(std::string::const_reverse_iterator it = str.rbegin(); it != str.rend(); ++it)
0805 {
0806 static_cast<void>(is.putback(*it));
0807 }
0808
0809 is.setstate(ios_base::failbit);
0810
0811 BOOST_MATH_THROW_EXCEPTION(std::runtime_error("Unable to interpret input string as a boost::float128_t"));
0812 }
0813
0814 return is;
0815 }
0816 }
0817
0818 #endif
0819
0820 #endif
0821
0822 #endif