Chris@16: // Copyright (c) 2001-2011 Hartmut Kaiser Chris@16: // Chris@16: // Distributed under the Boost Software License, Version 1.0. (See accompanying Chris@16: // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: #if !defined(BOOST_SPIRIT_KARMA_REAL_POLICIES_MAR_02_2007_0936AM) Chris@16: #define BOOST_SPIRIT_KARMA_REAL_POLICIES_MAR_02_2007_0936AM Chris@16: Chris@16: #if defined(_MSC_VER) Chris@16: #pragma once Chris@16: #endif Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: Chris@16: namespace boost { namespace spirit { namespace karma Chris@16: { Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // real_policies, if you need special handling of your floating Chris@16: // point numbers, just overload this policy class and use it as a template Chris@16: // parameter to the karma::real_generator floating point specifier: Chris@16: // Chris@16: // template Chris@16: // struct scientific_policy : karma::real_policies Chris@16: // { Chris@16: // // we want the numbers always to be in scientific format Chris@16: // static int floatfield(T n) { return fmtflags::scientific; } Chris@16: // }; Chris@16: // Chris@16: // typedef Chris@16: // karma::real_generator > Chris@16: // science_type; Chris@16: // Chris@16: // karma::generate(sink, science_type(), 1.0); // will output: 1.0e00 Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct real_policies Chris@16: { Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: // Expose the data type the generator is targeted at Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: typedef T value_type; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: // By default the policy doesn't require any special iterator Chris@16: // functionality. The floating point generator exposes its properties Chris@16: // from here, so this needs to be updated in case other properties Chris@16: // need to be implemented. Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: typedef mpl::int_ properties; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: // Specifies, which representation type to use during output Chris@16: // generation. Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: struct fmtflags Chris@16: { Chris@16: enum { Chris@16: scientific = 0, // Generate floating-point values in scientific Chris@16: // format (with an exponent field). Chris@16: fixed = 1 // Generate floating-point values in fixed-point Chris@16: // format (with no exponent field). Chris@16: }; Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: // This is the main function used to generate the output for a Chris@16: // floating point number. It is called by the real generator in order Chris@16: // to perform the conversion. In theory all of the work can be Chris@16: // implemented here, but it is the easiest to use existing Chris@16: // functionality provided by the type specified by the template Chris@16: // parameter `Inserter`. Chris@16: // Chris@16: // sink: the output iterator to use for generation Chris@16: // n: the floating point number to convert Chris@16: // p: the instance of the policy type used to instantiate this Chris@16: // floating point generator. Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: static bool Chris@16: call (OutputIterator& sink, T n, Policies const& p) Chris@16: { Chris@16: return Inserter::call_n(sink, n, p); Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: // The default behavior is to not to require generating a sign. If Chris@16: // 'force_sign()' returns true, then all generated numbers will Chris@16: // have a sign ('+' or '-', zeros will have a space instead of a sign) Chris@16: // Chris@16: // n The floating point number to output. This can be used to Chris@16: // adjust the required behavior depending on the value of Chris@16: // this number. Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: static bool force_sign(T) Chris@16: { Chris@16: return false; Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: // Return whether trailing zero digits have to be emitted in the Chris@16: // fractional part of the output. If set, this flag instructs the Chris@16: // floating point generator to emit trailing zeros up to the required Chris@16: // precision digits (as returned by the precision() function). Chris@16: // Chris@16: // n The floating point number to output. This can be used to Chris@16: // adjust the required behavior depending on the value of Chris@16: // this number. Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: static bool trailing_zeros(T) Chris@16: { Chris@16: // the default behavior is not to generate trailing zeros Chris@16: return false; Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: // Decide, which representation type to use in the generated output. Chris@16: // Chris@16: // By default all numbers having an absolute value of zero or in Chris@16: // between 0.001 and 100000 will be generated using the fixed format, Chris@16: // all others will be generated using the scientific representation. Chris@16: // Chris@16: // The function trailing_zeros() can be used to force the output of Chris@16: // trailing zeros in the fractional part up to the number of digits Chris@16: // returned by the precision() member function. The default is not to Chris@16: // generate the trailing zeros. Chris@16: // Chris@16: // n The floating point number to output. This can be used to Chris@16: // adjust the formatting flags depending on the value of Chris@16: // this number. Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: static int floatfield(T n) Chris@16: { Chris@16: if (traits::test_zero(n)) Chris@16: return fmtflags::fixed; Chris@16: Chris@16: T abs_n = traits::get_absolute_value(n); Chris@16: return (abs_n >= 1e5 || abs_n < 1e-3) Chris@16: ? fmtflags::scientific : fmtflags::fixed; Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: // Return the maximum number of decimal digits to generate in the Chris@16: // fractional part of the output. Chris@16: // Chris@16: // n The floating point number to output. This can be used to Chris@16: // adjust the required precision depending on the value of Chris@16: // this number. If the trailing zeros flag is specified the Chris@16: // fractional part of the output will be 'filled' with Chris@16: // zeros, if appropriate Chris@16: // Chris@16: // Note: If the trailing_zeros flag is not in effect additional Chris@16: // comments apply. See the comment for the fraction_part() Chris@16: // function below. Moreover, this precision will be limited Chris@16: // to the value of std::numeric_limits::digits10 + 1 Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: static unsigned precision(T) Chris@16: { Chris@16: // by default, generate max. 3 fractional digits Chris@16: return 3; Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: // Generate the integer part of the number. Chris@16: // Chris@16: // sink The output iterator to use for generation Chris@16: // n The absolute value of the integer part of the floating Chris@16: // point number to convert (always non-negative). Chris@16: // sign The sign of the overall floating point number to Chris@16: // convert. Chris@16: // force_sign Whether a sign has to be generated even for Chris@16: // non-negative numbers. Note, that force_sign will be Chris@16: // set to false for zero floating point values. Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: static bool integer_part (OutputIterator& sink, T n, bool sign Chris@16: , bool force_sign) Chris@16: { Chris@16: return sign_inserter::call( Chris@16: sink, traits::test_zero(n), sign, force_sign, force_sign) && Chris@16: int_inserter<10>::call(sink, n); Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: // Generate the decimal point. Chris@16: // Chris@16: // sink The output iterator to use for generation Chris@16: // n The fractional part of the floating point number to Chris@16: // convert. Note that this number is scaled such, that Chris@16: // it represents the number of units which correspond Chris@16: // to the value returned from the precision() function Chris@16: // earlier. I.e. a fractional part of 0.01234 is Chris@16: // represented as 1234 when the 'Precision' is 5. Chris@16: // precision The number of digits to emit as returned by the Chris@16: // function 'precision()' above Chris@16: // Chris@16: // This is given to allow to decide, whether a decimal point Chris@16: // has to be generated at all. Chris@16: // Chris@16: // Note: If the trailing_zeros flag is not in effect additional Chris@16: // comments apply. See the comment for the fraction_part() Chris@16: // function below. Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: static bool dot (OutputIterator& sink, T /*n*/, unsigned /*precision*/) Chris@16: { Chris@16: return char_inserter<>::call(sink, '.'); // generate the dot by default Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: // Generate the fractional part of the number. Chris@16: // Chris@16: // sink The output iterator to use for generation Chris@16: // n The fractional part of the floating point number to Chris@16: // convert. This number is scaled such, that it represents Chris@16: // the number of units which correspond to the 'Precision'. Chris@16: // I.e. a fractional part of 0.01234 is represented as 1234 Chris@16: // when the 'precision_' parameter is 5. Chris@16: // precision_ The corrected number of digits to emit (see note Chris@16: // below) Chris@16: // precision The number of digits to emit as returned by the Chris@16: // function 'precision()' above Chris@16: // Chris@16: // Note: If trailing_zeros() does not return true the 'precision_' Chris@16: // parameter will have been corrected from the value the Chris@16: // precision() function returned earlier (defining the maximal Chris@16: // number of fractional digits) in the sense, that it takes into Chris@16: // account trailing zeros. I.e. a floating point number 0.0123 Chris@16: // and a value of 5 returned from precision() will result in: Chris@16: // Chris@16: // trailing_zeros is not specified: Chris@16: // n 123 Chris@16: // precision_ 4 Chris@16: // Chris@16: // trailing_zeros is specified: Chris@16: // n 1230 Chris@16: // precision_ 5 Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: static bool fraction_part (OutputIterator& sink, T n Chris@16: , unsigned precision_, unsigned precision) Chris@16: { Chris@16: // allow for ADL to find the correct overload for floor and log10 Chris@16: using namespace std; Chris@16: Chris@16: // The following is equivalent to: Chris@16: // generate(sink, right_align(precision, '0')[ulong], n); Chris@16: // but it's spelled out to avoid inter-modular dependencies. Chris@16: Chris@16: typename remove_const::type digits = Chris@16: (traits::test_zero(n) ? 0 : floor(log10(n))) + 1; Chris@16: bool r = true; Chris@16: for (/**/; r && digits < precision_; digits = digits + 1) Chris@16: r = char_inserter<>::call(sink, '0'); Chris@16: if (precision && r) Chris@16: r = int_inserter<10>::call(sink, n); Chris@16: return r; Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: // Generate the exponential part of the number (this is called only Chris@16: // if the floatfield() function returned the 'scientific' flag). Chris@16: // Chris@16: // sink The output iterator to use for generation Chris@16: // n The (signed) exponential part of the floating point Chris@16: // number to convert. Chris@16: // Chris@16: // The Tag template parameter is either of the type unused_type or Chris@16: // describes the character class and conversion to be applied to any Chris@16: // output possibly influenced by either the lower[...] or upper[...] Chris@16: // directives. Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: static bool exponent (OutputIterator& sink, long n) Chris@16: { Chris@16: long abs_n = traits::get_absolute_value(n); Chris@16: bool r = char_inserter::call(sink, 'e') && Chris@16: sign_inserter::call(sink, traits::test_zero(n) Chris@16: , traits::test_negative(n), false); Chris@16: Chris@16: // the C99 Standard requires at least two digits in the exponent Chris@16: if (r && abs_n < 10) Chris@16: r = char_inserter::call(sink, '0'); Chris@16: return r && int_inserter<10>::call(sink, abs_n); Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: // Print the textual representations for non-normal floats (NaN and Chris@16: // Inf) Chris@16: // Chris@16: // sink The output iterator to use for generation Chris@16: // n The (signed) floating point number to convert. Chris@16: // force_sign Whether a sign has to be generated even for Chris@16: // non-negative numbers Chris@16: // Chris@16: // The Tag template parameter is either of the type unused_type or Chris@16: // describes the character class and conversion to be applied to any Chris@16: // output possibly influenced by either the lower[...] or upper[...] Chris@16: // directives. Chris@16: // Chris@16: // Note: These functions get called only if fpclassify() returned Chris@16: // FP_INFINITY or FP_NAN. Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: static bool nan (OutputIterator& sink, T n, bool force_sign) Chris@16: { Chris@16: return sign_inserter::call( Chris@16: sink, false, traits::test_negative(n), force_sign) && Chris@16: string_inserter::call(sink, "nan"); Chris@16: } Chris@16: Chris@16: template Chris@16: static bool inf (OutputIterator& sink, T n, bool force_sign) Chris@16: { Chris@16: return sign_inserter::call( Chris@16: sink, false, traits::test_negative(n), force_sign) && Chris@16: string_inserter::call(sink, "inf"); Chris@16: } Chris@16: }; Chris@16: }}} Chris@16: Chris@16: #endif // defined(BOOST_SPIRIT_KARMA_REAL_POLICIES_MAR_02_2007_0936AM)