/Src/Dependencies/Boost/boost/spirit/home/karma/numeric/detail/real_utils.hpp

http://hadesmem.googlecode.com/ · C++ Header · 185 lines · 131 code · 24 blank · 30 comment · 32 complexity · 0a07f5ee15341ee238986be60305d6e0 MD5 · raw file

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