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_
|