Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-19 09:47:37

0001 //  Copyright (c) 2001-2020 Hartmut Kaiser
0002 // 
0003 //  Distributed under the Boost Software License, Version 1.0. (See accompanying 
0004 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0005 
0006 #if !defined(BOOST_SPIRIT_KARMA_REAL_UTILS_FEB_23_2007_0841PM)
0007 #define BOOST_SPIRIT_KARMA_REAL_UTILS_FEB_23_2007_0841PM
0008 
0009 #if defined(_MSC_VER)
0010 #pragma once
0011 #endif
0012 
0013 #include <boost/config.hpp>
0014 #include <boost/config/no_tr1/cmath.hpp>
0015 #include <boost/detail/workaround.hpp>
0016 #include <boost/limits.hpp>
0017 
0018 #include <boost/spirit/home/support/char_class.hpp>
0019 #include <boost/spirit/home/support/unused.hpp>
0020 #include <boost/spirit/home/support/detail/pow10.hpp>
0021 #include <boost/spirit/home/karma/detail/generate_to.hpp>
0022 #include <boost/spirit/home/karma/detail/string_generate.hpp>
0023 #include <boost/spirit/home/karma/numeric/detail/numeric_utils.hpp>
0024 
0025 namespace boost { namespace spirit { namespace karma 
0026 { 
0027     ///////////////////////////////////////////////////////////////////////////
0028     //
0029     //  The real_inserter template takes care of the floating point number to 
0030     //  string conversion. The Policies template parameter is used to allow
0031     //  customization of the formatting process
0032     //
0033     ///////////////////////////////////////////////////////////////////////////
0034     template <typename T>
0035     struct real_policies;
0036 
0037     template <typename T
0038       , typename Policies = real_policies<T>
0039       , typename CharEncoding = unused_type
0040       , typename Tag = unused_type>
0041     struct real_inserter
0042     {
0043         template <typename OutputIterator, typename U>
0044         static bool
0045         call (OutputIterator& sink, U n, Policies const& p = Policies())
0046         {
0047             if (traits::test_nan(n)) {
0048                 return p.template nan<CharEncoding, Tag>(
0049                     sink, n, p.force_sign(n));
0050             }
0051             else if (traits::test_infinite(n)) {
0052                 return p.template inf<CharEncoding, Tag>(
0053                     sink, n, p.force_sign(n));
0054             }
0055             return p.template call<real_inserter>(sink, n, p);
0056         }
0057 
0058 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)  
0059 # pragma warning(push)
0060 # pragma warning(disable: 4100)   // 'p': unreferenced formal parameter  
0061 # pragma warning(disable: 4127)   // conditional expression is constant
0062 # pragma warning(disable: 4267)   // conversion from 'size_t' to 'unsigned int', possible loss of data
0063 #endif 
0064         ///////////////////////////////////////////////////////////////////////
0065         //  This is the workhorse behind the real generator
0066         ///////////////////////////////////////////////////////////////////////
0067         template <typename OutputIterator, typename U>
0068         static bool
0069         call_n (OutputIterator& sink, U n, Policies const& p)
0070         {
0071         // prepare sign and get output format
0072             bool force_sign = p.force_sign(n);
0073             bool sign_val = false;
0074             int flags = p.floatfield(n);
0075             if (traits::test_negative(n)) 
0076             {
0077                 n = -n;
0078                 sign_val = true;
0079             }
0080 
0081         // The scientific representation requires the normalization of the 
0082         // value to convert.
0083 
0084             // get correct precision for generated number
0085             unsigned precision = p.precision(n);
0086 
0087             // allow for ADL to find the correct overloads for log10 et.al.
0088             using namespace std;
0089 
0090             bool precexp_offset = false;
0091             U dim = 0;
0092             if (0 == (Policies::fmtflags::fixed & flags) && !traits::test_zero(n))
0093             {
0094                 dim = log10(n);
0095                 if (dim > 0)
0096                     n /= spirit::traits::pow10<U>(traits::truncate_to_long::call(dim));
0097                 else if (n < 1.) {
0098                     long exp = traits::truncate_to_long::call(-dim);
0099 
0100                     dim = static_cast<U>(-exp);
0101 
0102                     // detect and handle denormalized numbers to prevent overflow in pow10
0103                     if (exp > std::numeric_limits<U>::max_exponent10)
0104                     {
0105                         n *= spirit::traits::pow10<U>(std::numeric_limits<U>::max_exponent10);
0106                         n *= spirit::traits::pow10<U>(exp - std::numeric_limits<U>::max_exponent10);
0107                     }
0108                     else
0109                         n *= spirit::traits::pow10<U>(exp);
0110 
0111                     if (n < 1.)
0112                     {
0113                         n *= 10.;
0114                         --dim;
0115                         precexp_offset = true;
0116                     }
0117                 }
0118             }
0119 
0120         // prepare numbers (sign, integer and fraction part)
0121             U integer_part;
0122             U precexp = spirit::traits::pow10<U>(precision);
0123             U fractional_part = modf(n, &integer_part);
0124 
0125             if (precexp_offset)
0126             {
0127                 fractional_part =
0128                     floor((fractional_part * precexp + U(0.5)) * U(10.)) / U(10.);
0129             }
0130             else
0131             {
0132                 fractional_part = floor(fractional_part * precexp + U(0.5));
0133             }
0134 
0135             if (fractional_part >= precexp)
0136             {
0137                 fractional_part = floor(fractional_part - precexp);
0138                 integer_part += 1;    // handle rounding overflow
0139                 if (integer_part >= 10. && 0 == (Policies::fmtflags::fixed & flags))
0140                 {
0141                     integer_part /= 10.;
0142                     ++dim;
0143                 }
0144             }
0145 
0146         // if trailing zeros are to be omitted, normalize the precision and``
0147         // fractional part
0148             U long_int_part = floor(integer_part);
0149             U long_frac_part = fractional_part;
0150             unsigned prec = precision;
0151             if (!p.trailing_zeros(n))
0152             {
0153                 U frac_part_floor = long_frac_part;
0154                 if (0 != long_frac_part) {
0155                     // remove the trailing zeros
0156                     while (0 != prec && 
0157                            0 == traits::remainder<10>::call(long_frac_part)) 
0158                     {
0159                         long_frac_part = traits::divide<10>::call(long_frac_part);
0160                         --prec;
0161                     }
0162                 }
0163                 else {
0164                     // if the fractional part is zero, we don't need to output 
0165                     // any additional digits
0166                     prec = 0;
0167                 }
0168 
0169                 if (precision != prec)
0170                 {
0171                     long_frac_part = frac_part_floor / 
0172                         spirit::traits::pow10<U>(precision-prec);
0173                 }
0174             }
0175 
0176         // call the actual generating functions to output the different parts
0177             if ((force_sign || sign_val) &&
0178                 traits::test_zero(long_int_part) &&
0179                 traits::test_zero(long_frac_part))
0180             {
0181                 sign_val = false;     // result is zero, no sign please
0182                 force_sign = false;
0183             }
0184 
0185         // generate integer part
0186             bool r = p.integer_part(sink, long_int_part, sign_val, force_sign);
0187 
0188         // generate decimal point
0189             r = r && p.dot(sink, long_frac_part, precision);
0190 
0191         // generate fractional part with the desired precision
0192             r = r && p.fraction_part(sink, long_frac_part, prec, precision);
0193 
0194             if (r && 0 == (Policies::fmtflags::fixed & flags)) {
0195                 return p.template exponent<CharEncoding, Tag>(sink, 
0196                     traits::truncate_to_long::call(dim));
0197             }
0198             return r;
0199         }
0200 
0201 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0202 # pragma warning(pop)
0203 #endif 
0204 
0205     };
0206 }}}
0207 
0208 #endif
0209