PageRenderTime 95ms CodeModel.GetById 59ms app.highlight 27ms RepoModel.GetById 5ms app.codeStats 0ms

/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
  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
 26namespace 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
 46        call (OutputIterator& sink, U n, Policies const& p = Policies())
 47        {
 48            if (traits::test_nan(n)) {
 49                return Policies::template nan<CharEncoding, Tag>(
 50                    sink, n, p.force_sign(n));
 51            }
 52            else if (traits::test_infinite(n)) {
 53                return Policies::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
 70        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 = -exp;
108                    n *= spirit::traits::pow10<U>(exp);
109                }
110            }
111
112        // prepare numbers (sign, integer and fraction part)
113            U integer_part;
114            U precexp = spirit::traits::pow10<U>(precision);
115            U fractional_part = modf(n, &integer_part);
116
117            fractional_part = floor(fractional_part * precexp + U(0.5));
118            if (fractional_part >= precexp) 
119            {
120                fractional_part = floor(fractional_part - precexp);
121                integer_part += 1;    // handle rounding overflow
122            }
123
124        // if trailing zeros are to be omitted, normalize the precision and
125        // fractional part
126            U long_int_part = floor(integer_part);
127            U long_frac_part = fractional_part;
128            unsigned prec = precision;
129            if (!p.trailing_zeros(n))
130            {
131                U frac_part_floor = long_frac_part;
132                if (0 != long_frac_part) {
133                    // remove the trailing zeros
134                    while (0 != prec && 
135                           0 == traits::remainder<10>::call(long_frac_part)) 
136                    {
137                        long_frac_part = traits::divide<10>::call(long_frac_part);
138                        --prec;
139                    }
140                }
141                else {
142                    // if the fractional part is zero, we don't need to output 
143                    // any additional digits
144                    prec = 0;
145                }
146
147                if (precision != prec)
148                {
149                    long_frac_part = frac_part_floor / 
150                        spirit::traits::pow10<U>(precision-prec);
151                }
152            }
153
154        // call the actual generating functions to output the different parts
155            if (sign_val && traits::test_zero(long_int_part) && 
156                traits::test_zero(long_frac_part))
157            {
158                sign_val = false;     // result is zero, no sign please
159            }
160
161        // generate integer part
162            bool r = p.integer_part(sink, long_int_part, sign_val, force_sign);
163
164        // generate decimal point
165            r = r && p.dot(sink, long_frac_part, precision);
166
167        // generate fractional part with the desired precision
168            r = r && p.fraction_part(sink, long_frac_part, prec, precision);
169
170            if (r && 0 == (Policies::fmtflags::fixed & flags)) {
171                return p.template exponent<CharEncoding, Tag>(sink, 
172                    traits::truncate_to_long::call(dim));
173            }
174            return r;
175        }
176
177#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
178# pragma warning(pop)
179#endif 
180
181    };
182}}}
183
184#endif
185