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