cstdfloat_iostream.hpp 21 KB

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