annotate DEPENDENCIES/generic/include/boost/math/cstdfloat/cstdfloat_iostream.hpp @ 133:4acb5d8d80b6 tip

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