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