]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | |
46 | 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 | |
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 = static_cast<U>(-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 ((force_sign || sign_val) && | |
156 | traits::test_zero(long_int_part) && | |
157 | traits::test_zero(long_frac_part)) | |
158 | { | |
159 | sign_val = false; // result is zero, no sign please | |
160 | force_sign = false; | |
161 | } | |
162 | ||
163 | // generate integer part | |
164 | bool r = p.integer_part(sink, long_int_part, sign_val, force_sign); | |
165 | ||
166 | // generate decimal point | |
167 | r = r && p.dot(sink, long_frac_part, precision); | |
168 | ||
169 | // generate fractional part with the desired precision | |
170 | r = r && p.fraction_part(sink, long_frac_part, prec, precision); | |
171 | ||
172 | if (r && 0 == (Policies::fmtflags::fixed & flags)) { | |
173 | return p.template exponent<CharEncoding, Tag>(sink, | |
174 | traits::truncate_to_long::call(dim)); | |
175 | } | |
176 | return r; | |
177 | } | |
178 | ||
179 | #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) | |
180 | # pragma warning(pop) | |
181 | #endif | |
182 | ||
183 | }; | |
184 | }}} | |
185 | ||
186 | #endif | |
187 |