// Copyright (c) 2001-2010 Hartmut Kaiser // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #if !defined(BOOST_SPIRIT_KARMA_REAL_UTILS_FEB_23_2007_0841PM) #define BOOST_SPIRIT_KARMA_REAL_UTILS_FEB_23_2007_0841PM #if defined(_MSC_VER) #pragma once #endif #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace spirit { namespace karma { /////////////////////////////////////////////////////////////////////////// // // The real_inserter template takes care of the floating point number to // string conversion. The Policies template parameter is used to allow // customization of the formatting process // /////////////////////////////////////////////////////////////////////////// template struct real_policies; template , typename CharEncoding = unused_type , typename Tag = unused_type> struct real_inserter { template static bool call (OutputIterator& sink, float n, Policies const& p = Policies()) { int fpclass = (math::fpclassify)(n); if ((int)FP_NAN == fpclass) { return Policies::template nan( sink, n, p.force_sign(n)); } else if ((int)FP_INFINITE == fpclass) { return Policies::template inf( sink, n, p.force_sign(n)); } return p.template call(sink, n, p); } template static bool call (OutputIterator& sink, double n, Policies const& p = Policies()) { int fpclass = (math::fpclassify)(n); if ((int)FP_NAN == fpclass) { return Policies::template nan( sink, n, p.force_sign(n)); } else if ((int)FP_INFINITE == fpclass) { return Policies::template inf( sink, n, p.force_sign(n)); } return p.template call(sink, n, p); } template static bool call (OutputIterator& sink, long double n, Policies const& p = Policies()) { int fpclass = (math::fpclassify)(n); if ((int)FP_NAN == fpclass) { return Policies::template nan( sink, n, p.force_sign(n)); } else if ((int)FP_INFINITE == fpclass) { return Policies::template inf( sink, n, p.force_sign(n)); } return p.template call(sink, n, p); } template static bool call (OutputIterator& sink, U n, Policies const& p = Policies()) { // we have no means of testing whether the number is normalized if // the type is not float, double or long double return p.template call(sink, T(n), p); } #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) # pragma warning(push) # pragma warning(disable: 4100) // 'p': unreferenced formal parameter # pragma warning(disable: 4127) // conditional expression is constant # pragma warning(disable: 4267) // conversion from 'size_t' to 'unsigned int', possible loss of data #endif /////////////////////////////////////////////////////////////////////// // This is the workhorse behind the real generator /////////////////////////////////////////////////////////////////////// template static bool call_n (OutputIterator& sink, U n, Policies const& p) { // prepare sign and get output format bool force_sign = p.force_sign(n); bool sign_val = false; int flags = p.floatfield(n); if (detail::is_negative(n)) { n = -n; sign_val = true; } // The scientific representation requires the normalization of the // value to convert. // get correct precision for generated number unsigned precision = p.precision(n); if (std::numeric_limits::digits10) { // limit generated precision to digits10, if defined precision = (std::min)(precision, (unsigned)std::numeric_limits::digits10 + 1); } // allow for ADL to find the correct overloads for log10 et.al. using namespace std; U dim = 0; if (0 == (Policies::fmtflags::fixed & flags) && !detail::is_zero(n)) { dim = log10(n); if (dim > 0) n /= spirit::detail::pow10(detail::truncate_to_long::call(dim)); else if (n < 1.) n *= spirit::detail::pow10(detail::truncate_to_long::call(-dim) + 1); } // prepare numbers (sign, integer and fraction part) U integer_part; U precexp = spirit::detail::pow10(precision); U fractional_part = modf(n, &integer_part); fractional_part = floor(fractional_part * precexp + U(0.5)); if (fractional_part >= precexp) { fractional_part = floor(fractional_part - precexp); integer_part += 1; // handle rounding overflow } // if trailing zeros are to be omitted, normalize the precision and // fractional part U long_int_part = floor(integer_part); U long_frac_part = fractional_part; unsigned prec = precision; if (!p.trailing_zeros(n)) { U frac_part_floor = long_frac_part; if (0 != long_frac_part) { // remove the trailing zeros while (0 != prec && 0 == detail::remainder<10>::call(long_frac_part)) { long_frac_part = detail::divide<10>::call(long_frac_part); --prec; } } else { // if the fractional part is zero, we don't need to output // any additional digits prec = 0; } if (precision != prec) { long_frac_part = frac_part_floor / spirit::detail::pow10(precision-prec); } } // call the actual generating functions to output the different parts if (sign_val && detail::is_zero(long_int_part) && detail::is_zero(long_frac_part)) { sign_val = false; // result is zero, no sign please } // generate integer part bool r = p.integer_part(sink, long_int_part, sign_val, force_sign); // generate decimal point r = r && p.dot(sink, long_frac_part, precision); // generate fractional part with the desired precision r = r && p.fraction_part(sink, long_frac_part, prec, precision); if (r && 0 == (Policies::fmtflags::fixed & flags)) { return p.template exponent(sink, detail::truncate_to_long::call(dim >= 0 ? dim : dim - 1)); } return r; } #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) # pragma warning(pop) #endif }; }}} #endif