cstdfloat_iostream.hpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright Christopher Kormanyos 2014.
  3. // Copyright John Maddock 2014.
  4. // Copyright Paul Bristow 2014.
  5. // Distributed under the Boost Software License,
  6. // Version 1.0. (See accompanying file LICENSE_1_0.txt
  7. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  8. //
  9. // Implement quadruple-precision I/O stream operations.
  10. #ifndef BOOST_MATH_CSTDFLOAT_IOSTREAM_2014_02_15_HPP_
  11. #define BOOST_MATH_CSTDFLOAT_IOSTREAM_2014_02_15_HPP_
  12. #include <boost/math/cstdfloat/cstdfloat_types.hpp>
  13. #include <boost/math/cstdfloat/cstdfloat_limits.hpp>
  14. #include <boost/math/cstdfloat/cstdfloat_cmath.hpp>
  15. #if defined(BOOST_CSTDFLOAT_NO_LIBQUADMATH_CMATH)
  16. #error You can not use <boost/math/cstdfloat/cstdfloat_iostream.hpp> with BOOST_CSTDFLOAT_NO_LIBQUADMATH_CMATH defined.
  17. #endif
  18. #if defined(BOOST_CSTDFLOAT_HAS_INTERNAL_FLOAT128_T) && defined(BOOST_MATH_USE_FLOAT128) && !defined(BOOST_CSTDFLOAT_NO_LIBQUADMATH_SUPPORT)
  19. #include <cstddef>
  20. #include <istream>
  21. #include <ostream>
  22. #include <sstream>
  23. #include <stdexcept>
  24. #include <string>
  25. #include <boost/math/tools/assert.hpp>
  26. #include <boost/math/tools/nothrow.hpp>
  27. #include <boost/math/tools/throw_exception.hpp>
  28. namespace boost {
  29. namespace math {
  30. namespace detail {
  31. //
  32. // What follows is the input streaming code: this is not "proper" iostream code at all
  33. // but that's hard to write.
  34. // For now just pull in all the characters that could possibly form the number
  35. // and let libquadmath's string parser make use of it. This fixes most use cases
  36. // including CSV type formats such as those used by the Random lib.
  37. //
  38. inline std::string read_string_while(std::istream& is, std::string const& permitted_chars)
  39. {
  40. std::ios_base::iostate state = std::ios_base::goodbit;
  41. const std::istream::sentry sentry_check(is);
  42. std::string result;
  43. if (sentry_check)
  44. {
  45. int c = is.rdbuf()->sgetc();
  46. for (;; c = is.rdbuf()->snextc())
  47. if (std::istream::traits_type::eq_int_type(std::istream::traits_type::eof(), c))
  48. { // end of file:
  49. state |= std::ios_base::eofbit;
  50. break;
  51. }
  52. else if (permitted_chars.find_first_of(std::istream::traits_type::to_char_type(c)) == std::string::npos)
  53. {
  54. // Invalid numeric character, stop reading:
  55. //is.rdbuf()->sputbackc(static_cast<char>(c));
  56. break;
  57. }
  58. else
  59. {
  60. result.append(1, std::istream::traits_type::to_char_type(c));
  61. }
  62. }
  63. if (!result.size())
  64. state |= std::ios_base::failbit;
  65. is.setstate(state);
  66. return result;
  67. }
  68. }
  69. }
  70. }
  71. #if defined(__GNUC__) && !defined(BOOST_MATH_TEST_IO_AS_INTEL_QUAD)
  72. // Forward declarations of quadruple-precision string functions.
  73. extern "C" int quadmath_snprintf(char *str, size_t size, const char *format, ...) BOOST_MATH_NOTHROW;
  74. extern "C" boost::math::cstdfloat::detail::float_internal128_t strtoflt128(const char*, char **) BOOST_MATH_NOTHROW;
  75. namespace std
  76. {
  77. template<typename char_type, class traits_type>
  78. 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)
  79. {
  80. std::basic_ostringstream<char_type, traits_type> ostr;
  81. ostr.flags(os.flags());
  82. ostr.imbue(os.getloc());
  83. ostr.precision(os.precision());
  84. char my_buffer[64U];
  85. const int my_prec = static_cast<int>(os.precision());
  86. const int my_digits = ((my_prec == 0) ? 36 : my_prec);
  87. const std::ios_base::fmtflags my_flags = os.flags();
  88. char my_format_string[8U];
  89. std::size_t my_format_string_index = 0U;
  90. my_format_string[my_format_string_index] = '%';
  91. ++my_format_string_index;
  92. if(my_flags & std::ios_base::showpos) { my_format_string[my_format_string_index] = '+'; ++my_format_string_index; }
  93. if(my_flags & std::ios_base::showpoint) { my_format_string[my_format_string_index] = '#'; ++my_format_string_index; }
  94. my_format_string[my_format_string_index + 0U] = '.';
  95. my_format_string[my_format_string_index + 1U] = '*';
  96. my_format_string[my_format_string_index + 2U] = 'Q';
  97. my_format_string_index += 3U;
  98. char the_notation_char;
  99. if (my_flags & std::ios_base::scientific) { the_notation_char = 'e'; }
  100. else if(my_flags & std::ios_base::fixed) { the_notation_char = 'f'; }
  101. else { the_notation_char = 'g'; }
  102. my_format_string[my_format_string_index + 0U] = the_notation_char;
  103. my_format_string[my_format_string_index + 1U] = 0;
  104. const int v = ::quadmath_snprintf(my_buffer,
  105. static_cast<int>(sizeof(my_buffer)),
  106. my_format_string,
  107. my_digits,
  108. x);
  109. if(v < 0) { BOOST_MATH_THROW_EXCEPTION(std::runtime_error("Formatting of boost::float128_t failed internally in quadmath_snprintf().")); }
  110. if(v >= static_cast<int>(sizeof(my_buffer) - 1U))
  111. {
  112. // Evidently there is a really long floating-point string here,
  113. // such as a small decimal representation in non-scientific notation.
  114. // So we have to use dynamic memory allocation for the output
  115. // string buffer.
  116. char* my_buffer2 = nullptr;
  117. #ifndef BOOST_MATH_NO_EXCEPTIONS
  118. try
  119. {
  120. #endif
  121. my_buffer2 = new char[v + 3];
  122. #ifndef BOOST_MATH_NO_EXCEPTIONS
  123. }
  124. catch(const std::bad_alloc&)
  125. {
  126. BOOST_MATH_THROW_EXCEPTION(std::runtime_error("Formatting of boost::float128_t failed while allocating memory."));
  127. }
  128. #endif
  129. const int v2 = ::quadmath_snprintf(my_buffer2,
  130. v + 3,
  131. my_format_string,
  132. my_digits,
  133. x);
  134. if(v2 >= v + 3)
  135. {
  136. BOOST_MATH_THROW_EXCEPTION(std::runtime_error("Formatting of boost::float128_t failed."));
  137. }
  138. static_cast<void>(ostr << my_buffer2);
  139. delete [] my_buffer2;
  140. }
  141. else
  142. {
  143. static_cast<void>(ostr << my_buffer);
  144. }
  145. return (os << ostr.str());
  146. }
  147. template<typename char_type, class traits_type>
  148. 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)
  149. {
  150. std::string str = boost::math::detail::read_string_while(is, "+-eE.0123456789infINFnanNANinfinityINFINITY");
  151. char* p_end;
  152. x = strtoflt128(str.c_str(), &p_end);
  153. if(static_cast<std::ptrdiff_t>(p_end - str.c_str()) != static_cast<std::ptrdiff_t>(str.length()))
  154. {
  155. for(std::string::const_reverse_iterator it = str.rbegin(); it != str.rend(); ++it)
  156. {
  157. static_cast<void>(is.putback(*it));
  158. }
  159. is.setstate(ios_base::failbit);
  160. BOOST_MATH_THROW_EXCEPTION(std::runtime_error("Unable to interpret input string as a boost::float128_t"));
  161. }
  162. return is;
  163. }
  164. }
  165. #elif defined(__INTEL_COMPILER) || defined(BOOST_MATH_TEST_IO_AS_INTEL_QUAD)
  166. // The section for I/O stream support for the ICC compiler is particularly
  167. // long, because these functions must be painstakingly synthesized from
  168. // manually-written routines (ICC does not support I/O stream operations
  169. // for its _Quad type).
  170. // The following string-extraction routines are based on the methodology
  171. // used in Boost.Multiprecision by John Maddock and Christopher Kormanyos.
  172. // This methodology has been slightly modified here for boost::float128_t.
  173. #include <cstring>
  174. #include <cctype>
  175. namespace boost { namespace math { namespace cstdfloat { namespace detail {
  176. template<class string_type>
  177. void format_float_string(string_type& str,
  178. int my_exp,
  179. int digits,
  180. const std::ios_base::fmtflags f,
  181. const bool iszero)
  182. {
  183. typedef typename string_type::size_type size_type;
  184. const bool scientific = ((f & std::ios_base::scientific) == std::ios_base::scientific);
  185. const bool fixed = ((f & std::ios_base::fixed) == std::ios_base::fixed);
  186. const bool showpoint = ((f & std::ios_base::showpoint) == std::ios_base::showpoint);
  187. const bool showpos = ((f & std::ios_base::showpos) == std::ios_base::showpos);
  188. const bool b_neg = ((str.size() != 0U) && (str[0] == '-'));
  189. if(b_neg)
  190. {
  191. str.erase(0, 1);
  192. }
  193. if(digits == 0)
  194. {
  195. digits = static_cast<int>((std::max)(str.size(), size_type(16)));
  196. }
  197. if(iszero || str.empty() || (str.find_first_not_of('0') == string_type::npos))
  198. {
  199. // We will be printing zero, even though the value might not
  200. // actually be zero (it just may have been rounded to zero).
  201. str = "0";
  202. if(scientific || fixed)
  203. {
  204. str.append(1, '.');
  205. str.append(size_type(digits), '0');
  206. if(scientific)
  207. {
  208. str.append("e+00");
  209. }
  210. }
  211. else
  212. {
  213. if(showpoint)
  214. {
  215. str.append(1, '.');
  216. if(digits > 1)
  217. {
  218. str.append(size_type(digits - 1), '0');
  219. }
  220. }
  221. }
  222. if(b_neg)
  223. {
  224. str.insert(0U, 1U, '-');
  225. }
  226. else if(showpos)
  227. {
  228. str.insert(0U, 1U, '+');
  229. }
  230. return;
  231. }
  232. if(!fixed && !scientific && !showpoint)
  233. {
  234. // Suppress trailing zeros.
  235. typename string_type::iterator pos = str.end();
  236. while(pos != str.begin() && *--pos == '0') { ; }
  237. if(pos != str.end())
  238. {
  239. ++pos;
  240. }
  241. str.erase(pos, str.end());
  242. if(str.empty())
  243. {
  244. str = '0';
  245. }
  246. }
  247. else if(!fixed || (my_exp >= 0))
  248. {
  249. // Pad out the end with zero's if we need to.
  250. std::ptrdiff_t chars = static_cast<std::ptrdiff_t>(str.size());
  251. chars = digits - chars;
  252. if(scientific)
  253. {
  254. ++chars;
  255. }
  256. if(chars > 0)
  257. {
  258. str.append(static_cast<size_type>(chars), '0');
  259. }
  260. }
  261. if(fixed || (!scientific && (my_exp >= -4) && (my_exp < digits)))
  262. {
  263. if((1 + my_exp) > static_cast<int>(str.size()))
  264. {
  265. // Just pad out the end with zeros.
  266. str.append(static_cast<size_type>((1 + my_exp) - static_cast<int>(str.size())), '0');
  267. if(showpoint || fixed)
  268. {
  269. str.append(".");
  270. }
  271. }
  272. else if(my_exp + 1 < static_cast<int>(str.size()))
  273. {
  274. if(my_exp < 0)
  275. {
  276. str.insert(0U, static_cast<size_type>(-1 - my_exp), '0');
  277. str.insert(0U, "0.");
  278. }
  279. else
  280. {
  281. // Insert the decimal point:
  282. str.insert(static_cast<size_type>(my_exp + 1), 1, '.');
  283. }
  284. }
  285. else if(showpoint || fixed) // we have exactly the digits we require to left of the point
  286. {
  287. str += ".";
  288. }
  289. if(fixed)
  290. {
  291. // We may need to add trailing zeros.
  292. int l = static_cast<int>(str.find('.') + 1U);
  293. l = digits - (static_cast<int>(str.size()) - l);
  294. if(l > 0)
  295. {
  296. str.append(size_type(l), '0');
  297. }
  298. }
  299. }
  300. else
  301. {
  302. // Scientific format:
  303. if(showpoint || (str.size() > 1))
  304. {
  305. str.insert(1U, 1U, '.');
  306. }
  307. str.append(1U, 'e');
  308. string_type e = std::to_string(std::abs(my_exp));
  309. if(e.size() < 2U)
  310. {
  311. e.insert(0U, 2U - e.size(), '0');
  312. }
  313. if(my_exp < 0)
  314. {
  315. e.insert(0U, 1U, '-');
  316. }
  317. else
  318. {
  319. e.insert(0U, 1U, '+');
  320. }
  321. str.append(e);
  322. }
  323. if(b_neg)
  324. {
  325. str.insert(0U, 1U, '-');
  326. }
  327. else if(showpos)
  328. {
  329. str.insert(0U, 1U, '+');
  330. }
  331. }
  332. 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); }
  333. template<class float_type, class type_a> inline void eval_add (float_type& b, const type_a& a) { b += a; }
  334. template<class float_type, class type_a> inline void eval_subtract (float_type& b, const type_a& a) { b -= a; }
  335. template<class float_type, class type_a> inline void eval_multiply (float_type& b, const type_a& a) { b *= a; }
  336. template<class float_type> inline void eval_multiply (float_type& b, const float_type& cb, const float_type& cb2) { b = (cb * cb2); }
  337. template<class float_type, class type_a> inline void eval_divide (float_type& b, const type_a& a) { b /= a; }
  338. template<class float_type> inline void eval_log10 (float_type& b, const float_type& cb) { b = std::log10(cb); }
  339. template<class float_type> inline void eval_floor (float_type& b, const float_type& cb) { b = std::floor(cb); }
  340. inline void round_string_up_at(std::string& s, int pos, int& expon)
  341. {
  342. // This subroutine rounds up a string representation of a
  343. // number at the given position pos.
  344. if(pos < 0)
  345. {
  346. s.insert(0U, 1U, '1');
  347. s.erase(s.size() - 1U);
  348. ++expon;
  349. }
  350. else if(s[pos] == '9')
  351. {
  352. s[pos] = '0';
  353. round_string_up_at(s, pos - 1, expon);
  354. }
  355. else
  356. {
  357. if((pos == 0) && (s[pos] == '0') && (s.size() == 1))
  358. {
  359. ++expon;
  360. }
  361. ++s[pos];
  362. }
  363. }
  364. template<class float_type>
  365. std::string convert_to_string(float_type& x,
  366. std::streamsize digits,
  367. const std::ios_base::fmtflags f)
  368. {
  369. const bool isneg = (x < 0);
  370. const bool iszero = ((!isneg) ? bool(+x < (std::numeric_limits<float_type>::min)())
  371. : bool(-x < (std::numeric_limits<float_type>::min)()));
  372. const bool isnan = (x != x);
  373. const bool isinf = ((!isneg) ? bool(+x > (std::numeric_limits<float_type>::max)())
  374. : bool(-x > (std::numeric_limits<float_type>::max)()));
  375. int expon = 0;
  376. if(digits <= 0) { digits = std::numeric_limits<float_type>::max_digits10; }
  377. const int org_digits = static_cast<int>(digits);
  378. std::string result;
  379. if(iszero)
  380. {
  381. result = "0";
  382. }
  383. else if(isinf)
  384. {
  385. if(x < 0)
  386. {
  387. return "-inf";
  388. }
  389. else
  390. {
  391. return ((f & std::ios_base::showpos) == std::ios_base::showpos) ? "+inf" : "inf";
  392. }
  393. }
  394. else if(isnan)
  395. {
  396. return "nan";
  397. }
  398. else
  399. {
  400. // Start by figuring out the base-10 exponent.
  401. if(isneg) { x = -x; }
  402. float_type t;
  403. constexpr float_type ten = 10;
  404. eval_log10(t, x);
  405. eval_floor(t, t);
  406. eval_convert_to(&expon, t);
  407. if(-expon > std::numeric_limits<float_type>::max_exponent10 - 3)
  408. {
  409. int e = -expon / 2;
  410. const float_type t2 = boost::math::cstdfloat::detail::pown(ten, e);
  411. eval_multiply(t, t2, x);
  412. eval_multiply(t, t2);
  413. if((expon & 1) != 0)
  414. {
  415. eval_multiply(t, ten);
  416. }
  417. }
  418. else
  419. {
  420. t = boost::math::cstdfloat::detail::pown(ten, -expon);
  421. eval_multiply(t, x);
  422. }
  423. // Make sure that the value lies between [1, 10), and adjust if not.
  424. if(t < 1)
  425. {
  426. eval_multiply(t, 10);
  427. --expon;
  428. }
  429. else if(t >= 10)
  430. {
  431. eval_divide(t, 10);
  432. ++expon;
  433. }
  434. float_type digit;
  435. int cdigit;
  436. // Adjust the number of digits required based on formatting options.
  437. if(((f & std::ios_base::fixed) == std::ios_base::fixed) && (expon != -1))
  438. {
  439. digits += (expon + 1);
  440. }
  441. if((f & std::ios_base::scientific) == std::ios_base::scientific)
  442. {
  443. ++digits;
  444. }
  445. // Extract the base-10 digits one at a time.
  446. for(int i = 0; i < digits; ++i)
  447. {
  448. eval_floor(digit, t);
  449. eval_convert_to(&cdigit, digit);
  450. result += static_cast<char>('0' + cdigit);
  451. eval_subtract(t, digit);
  452. eval_multiply(t, ten);
  453. }
  454. if (result.size() == 0)
  455. result = "0";
  456. // Possibly round the result.
  457. if(digits >= 0)
  458. {
  459. eval_floor(digit, t);
  460. eval_convert_to(&cdigit, digit);
  461. eval_subtract(t, digit);
  462. if((cdigit == 5) && (t == 0))
  463. {
  464. // Use simple bankers rounding.
  465. if((static_cast<int>(*result.rbegin() - '0') & 1) != 0)
  466. {
  467. round_string_up_at(result, static_cast<int>(result.size() - 1U), expon);
  468. if (digits == 0) digits = 1;
  469. }
  470. }
  471. else if(cdigit >= 5)
  472. {
  473. round_string_up_at(result, static_cast<int>(result.size() - 1u), expon);
  474. if (digits == 0) digits = 1;
  475. }
  476. }
  477. }
  478. while((result.size() > static_cast<std::string::size_type>(digits)) && result.size())
  479. {
  480. // We may get here as a result of rounding.
  481. if(result.size() > 1U)
  482. {
  483. result.erase(result.size() - 1U);
  484. }
  485. else
  486. {
  487. if(expon > 0)
  488. {
  489. --expon; // so we put less padding in the result.
  490. }
  491. else
  492. {
  493. ++expon;
  494. }
  495. ++digits;
  496. }
  497. }
  498. if(isneg)
  499. {
  500. result.insert(0U, 1U, '-');
  501. }
  502. format_float_string(result, expon, org_digits, f, iszero);
  503. return result;
  504. }
  505. template <class float_type>
  506. bool convert_from_string(float_type& value, const char* p)
  507. {
  508. value = 0;
  509. if((p == nullptr) || (*p == '\0'))
  510. {
  511. return false;
  512. }
  513. bool is_neg = false;
  514. bool is_neg_expon = false;
  515. constexpr int ten = 10;
  516. int expon = 0;
  517. int digits_seen = 0;
  518. constexpr int max_digits = std::numeric_limits<float_type>::max_digits10 + 1;
  519. if(*p == '+')
  520. {
  521. ++p;
  522. }
  523. else if(*p == '-')
  524. {
  525. is_neg = true;
  526. ++p;
  527. }
  528. const bool isnan = ((std::strcmp(p, "nan") == 0) || (std::strcmp(p, "NaN") == 0) || (std::strcmp(p, "NAN") == 0));
  529. if(isnan)
  530. {
  531. eval_divide(value, 0);
  532. if(is_neg)
  533. {
  534. value = -value;
  535. }
  536. return true;
  537. }
  538. const bool isinf = ((std::strcmp(p, "inf") == 0) || (std::strcmp(p, "Inf") == 0) || (std::strcmp(p, "INF") == 0));
  539. if(isinf)
  540. {
  541. value = 1;
  542. eval_divide(value, 0);
  543. if(is_neg)
  544. {
  545. value = -value;
  546. }
  547. return true;
  548. }
  549. // Grab all the leading digits before the decimal point.
  550. while(std::isdigit(*p))
  551. {
  552. eval_multiply(value, ten);
  553. eval_add(value, static_cast<int>(*p - '0'));
  554. ++p;
  555. ++digits_seen;
  556. }
  557. if(*p == '.')
  558. {
  559. // Grab everything after the point, stop when we've seen
  560. // enough digits, even if there are actually more available.
  561. ++p;
  562. while(std::isdigit(*p))
  563. {
  564. eval_multiply(value, ten);
  565. eval_add(value, static_cast<int>(*p - '0'));
  566. ++p;
  567. --expon;
  568. if(++digits_seen > max_digits)
  569. {
  570. break;
  571. }
  572. }
  573. while(std::isdigit(*p))
  574. {
  575. ++p;
  576. }
  577. }
  578. // Parse the exponent.
  579. if((*p == 'e') || (*p == 'E'))
  580. {
  581. ++p;
  582. if(*p == '+')
  583. {
  584. ++p;
  585. }
  586. else if(*p == '-')
  587. {
  588. is_neg_expon = true;
  589. ++p;
  590. }
  591. int e2 = 0;
  592. while(std::isdigit(*p))
  593. {
  594. e2 *= 10;
  595. e2 += (*p - '0');
  596. ++p;
  597. }
  598. if(is_neg_expon)
  599. {
  600. e2 = -e2;
  601. }
  602. expon += e2;
  603. }
  604. if(expon)
  605. {
  606. // Scale by 10^expon. Note that 10^expon can be outside the range
  607. // of our number type, even though the result is within range.
  608. // If that looks likely, then split the calculation in two parts.
  609. float_type t;
  610. t = ten;
  611. if(expon > (std::numeric_limits<float_type>::min_exponent10 + 2))
  612. {
  613. t = boost::math::cstdfloat::detail::pown(t, expon);
  614. eval_multiply(value, t);
  615. }
  616. else
  617. {
  618. t = boost::math::cstdfloat::detail::pown(t, (expon + digits_seen + 1));
  619. eval_multiply(value, t);
  620. t = ten;
  621. t = boost::math::cstdfloat::detail::pown(t, (-digits_seen - 1));
  622. eval_multiply(value, t);
  623. }
  624. }
  625. if(is_neg)
  626. {
  627. value = -value;
  628. }
  629. return (*p == '\0');
  630. }
  631. } } } } // boost::math::cstdfloat::detail
  632. namespace std
  633. {
  634. template<typename char_type, class traits_type>
  635. 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)
  636. {
  637. boost::math::cstdfloat::detail::float_internal128_t non_const_x = x;
  638. const std::string str = boost::math::cstdfloat::detail::convert_to_string(non_const_x,
  639. os.precision(),
  640. os.flags());
  641. std::basic_ostringstream<char_type, traits_type> ostr;
  642. ostr.flags(os.flags());
  643. ostr.imbue(os.getloc());
  644. ostr.precision(os.precision());
  645. static_cast<void>(ostr << str);
  646. return (os << ostr.str());
  647. }
  648. template<typename char_type, class traits_type>
  649. 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)
  650. {
  651. std::string str = boost::math::detail::read_string_while(is, "+-eE.0123456789infINFnanNANinfinityINFINITY");
  652. const bool conversion_is_ok = boost::math::cstdfloat::detail::convert_from_string(x, str.c_str());
  653. if(false == conversion_is_ok)
  654. {
  655. for(std::string::const_reverse_iterator it = str.rbegin(); it != str.rend(); ++it)
  656. {
  657. static_cast<void>(is.putback(*it));
  658. }
  659. is.setstate(ios_base::failbit);
  660. BOOST_MATH_THROW_EXCEPTION(std::runtime_error("Unable to interpret input string as a boost::float128_t"));
  661. }
  662. return is;
  663. }
  664. }
  665. #endif // Use __GNUC__ or __INTEL_COMPILER libquadmath
  666. #endif // Not BOOST_CSTDFLOAT_NO_LIBQUADMATH_SUPPORT (i.e., the user would like to have libquadmath support)
  667. #endif // BOOST_MATH_CSTDFLOAT_IOSTREAM_2014_02_15_HPP_