real_utils.hpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. // Copyright (c) 2001-2020 Hartmut Kaiser
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #if !defined(BOOST_SPIRIT_KARMA_REAL_UTILS_FEB_23_2007_0841PM)
  6. #define BOOST_SPIRIT_KARMA_REAL_UTILS_FEB_23_2007_0841PM
  7. #if defined(_MSC_VER)
  8. #pragma once
  9. #endif
  10. #include <boost/config.hpp>
  11. #include <boost/config/no_tr1/cmath.hpp>
  12. #include <boost/detail/workaround.hpp>
  13. #include <boost/limits.hpp>
  14. #include <boost/spirit/home/support/char_class.hpp>
  15. #include <boost/spirit/home/support/unused.hpp>
  16. #include <boost/spirit/home/support/detail/pow10.hpp>
  17. #include <boost/spirit/home/karma/detail/generate_to.hpp>
  18. #include <boost/spirit/home/karma/detail/string_generate.hpp>
  19. #include <boost/spirit/home/karma/numeric/detail/numeric_utils.hpp>
  20. namespace boost { namespace spirit { namespace karma
  21. {
  22. ///////////////////////////////////////////////////////////////////////////
  23. //
  24. // The real_inserter template takes care of the floating point number to
  25. // string conversion. The Policies template parameter is used to allow
  26. // customization of the formatting process
  27. //
  28. ///////////////////////////////////////////////////////////////////////////
  29. template <typename T>
  30. struct real_policies;
  31. template <typename T
  32. , typename Policies = real_policies<T>
  33. , typename CharEncoding = unused_type
  34. , typename Tag = unused_type>
  35. struct real_inserter
  36. {
  37. template <typename OutputIterator, typename U>
  38. static bool
  39. call (OutputIterator& sink, U n, Policies const& p = Policies())
  40. {
  41. if (traits::test_nan(n)) {
  42. return p.template nan<CharEncoding, Tag>(
  43. sink, n, p.force_sign(n));
  44. }
  45. else if (traits::test_infinite(n)) {
  46. return p.template inf<CharEncoding, Tag>(
  47. sink, n, p.force_sign(n));
  48. }
  49. return p.template call<real_inserter>(sink, n, p);
  50. }
  51. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  52. # pragma warning(push)
  53. # pragma warning(disable: 4100) // 'p': unreferenced formal parameter
  54. # pragma warning(disable: 4127) // conditional expression is constant
  55. # pragma warning(disable: 4267) // conversion from 'size_t' to 'unsigned int', possible loss of data
  56. #endif
  57. ///////////////////////////////////////////////////////////////////////
  58. // This is the workhorse behind the real generator
  59. ///////////////////////////////////////////////////////////////////////
  60. template <typename OutputIterator, typename U>
  61. static bool
  62. call_n (OutputIterator& sink, U n, Policies const& p)
  63. {
  64. // prepare sign and get output format
  65. bool force_sign = p.force_sign(n);
  66. bool sign_val = false;
  67. int flags = p.floatfield(n);
  68. if (traits::test_negative(n))
  69. {
  70. n = -n;
  71. sign_val = true;
  72. }
  73. // The scientific representation requires the normalization of the
  74. // value to convert.
  75. // get correct precision for generated number
  76. unsigned precision = p.precision(n);
  77. // allow for ADL to find the correct overloads for log10 et.al.
  78. using namespace std;
  79. bool precexp_offset = false;
  80. U dim = 0;
  81. if (0 == (Policies::fmtflags::fixed & flags) && !traits::test_zero(n))
  82. {
  83. dim = log10(n);
  84. if (dim > 0)
  85. n /= spirit::traits::pow10<U>(traits::truncate_to_long::call(dim));
  86. else if (n < 1.) {
  87. long exp = traits::truncate_to_long::call(-dim);
  88. dim = static_cast<U>(-exp);
  89. // detect and handle denormalized numbers to prevent overflow in pow10
  90. if (exp > std::numeric_limits<U>::max_exponent10)
  91. {
  92. n *= spirit::traits::pow10<U>(std::numeric_limits<U>::max_exponent10);
  93. n *= spirit::traits::pow10<U>(exp - std::numeric_limits<U>::max_exponent10);
  94. }
  95. else
  96. n *= spirit::traits::pow10<U>(exp);
  97. if (n < 1.)
  98. {
  99. n *= 10.;
  100. --dim;
  101. precexp_offset = true;
  102. }
  103. }
  104. }
  105. // prepare numbers (sign, integer and fraction part)
  106. U integer_part;
  107. U precexp = spirit::traits::pow10<U>(precision);
  108. U fractional_part = modf(n, &integer_part);
  109. if (precexp_offset)
  110. {
  111. fractional_part =
  112. floor((fractional_part * precexp + U(0.5)) * U(10.)) / U(10.);
  113. }
  114. else
  115. {
  116. fractional_part = floor(fractional_part * precexp + U(0.5));
  117. }
  118. if (fractional_part >= precexp)
  119. {
  120. fractional_part = floor(fractional_part - precexp);
  121. integer_part += 1; // handle rounding overflow
  122. if (integer_part >= 10. && 0 == (Policies::fmtflags::fixed & flags))
  123. {
  124. integer_part /= 10.;
  125. ++dim;
  126. }
  127. }
  128. // if trailing zeros are to be omitted, normalize the precision and``
  129. // fractional part
  130. U long_int_part = floor(integer_part);
  131. U long_frac_part = fractional_part;
  132. unsigned prec = precision;
  133. if (!p.trailing_zeros(n))
  134. {
  135. U frac_part_floor = long_frac_part;
  136. if (0 != long_frac_part) {
  137. // remove the trailing zeros
  138. while (0 != prec &&
  139. 0 == traits::remainder<10>::call(long_frac_part))
  140. {
  141. long_frac_part = traits::divide<10>::call(long_frac_part);
  142. --prec;
  143. }
  144. }
  145. else {
  146. // if the fractional part is zero, we don't need to output
  147. // any additional digits
  148. prec = 0;
  149. }
  150. if (precision != prec)
  151. {
  152. long_frac_part = frac_part_floor /
  153. spirit::traits::pow10<U>(precision-prec);
  154. }
  155. }
  156. // call the actual generating functions to output the different parts
  157. if ((force_sign || sign_val) &&
  158. traits::test_zero(long_int_part) &&
  159. traits::test_zero(long_frac_part))
  160. {
  161. sign_val = false; // result is zero, no sign please
  162. force_sign = false;
  163. }
  164. // generate integer part
  165. bool r = p.integer_part(sink, long_int_part, sign_val, force_sign);
  166. // generate decimal point
  167. r = r && p.dot(sink, long_frac_part, precision);
  168. // generate fractional part with the desired precision
  169. r = r && p.fraction_part(sink, long_frac_part, prec, precision);
  170. if (r && 0 == (Policies::fmtflags::fixed & flags)) {
  171. return p.template exponent<CharEncoding, Tag>(sink,
  172. traits::truncate_to_long::call(dim));
  173. }
  174. return r;
  175. }
  176. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  177. # pragma warning(pop)
  178. #endif
  179. };
  180. }}}
  181. #endif