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