cstdfloat_iostream.hpp 22 KB

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