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_POLICIES_MAR_02_2007_0936AM) 7 #define BOOST_SPIRIT_KARMA_REAL_POLICIES_MAR_02_2007_0936AM 8 9 #if defined(_MSC_VER) 10 #pragma once 11 #endif 12 13 #include <boost/config/no_tr1/cmath.hpp> 14 #include <boost/type_traits/remove_const.hpp> 15 16 #include <boost/spirit/home/support/char_class.hpp> 17 #include <boost/spirit/home/karma/generator.hpp> 18 #include <boost/spirit/home/karma/char.hpp> 19 #include <boost/spirit/home/karma/numeric/int.hpp> 20 #include <boost/spirit/home/karma/numeric/detail/real_utils.hpp> 21 22 #include <boost/mpl/bool.hpp> 23 24 namespace boost { namespace spirit { namespace karma 25 { 26 /////////////////////////////////////////////////////////////////////////// 27 // 28 // real_policies, if you need special handling of your floating 29 // point numbers, just overload this policy class and use it as a template 30 // parameter to the karma::real_generator floating point specifier: 31 // 32 // template <typename T> 33 // struct scientific_policy : karma::real_policies<T> 34 // { 35 // // we want the numbers always to be in scientific format 36 // static int floatfield(T n) { return fmtflags::scientific; } 37 // }; 38 // 39 // typedef 40 // karma::real_generator<double, scientific_policy<double> > 41 // science_type; 42 // 43 // karma::generate(sink, science_type(), 1.0); // will output: 1.0e00 44 // 45 /////////////////////////////////////////////////////////////////////////// 46 template <typename T> 47 struct real_policies 48 { 49 /////////////////////////////////////////////////////////////////////// 50 // Expose the data type the generator is targeted at 51 /////////////////////////////////////////////////////////////////////// 52 typedef T value_type; 53 54 /////////////////////////////////////////////////////////////////////// 55 // By default the policy doesn't require any special iterator 56 // functionality. The floating point generator exposes its properties 57 // from here, so this needs to be updated in case other properties 58 // need to be implemented. 59 /////////////////////////////////////////////////////////////////////// 60 typedef mpl::int_<generator_properties::no_properties> properties; 61 62 /////////////////////////////////////////////////////////////////////// 63 // Specifies, which representation type to use during output 64 // generation. 65 /////////////////////////////////////////////////////////////////////// 66 struct fmtflags 67 { 68 enum { 69 scientific = 0, // Generate floating-point values in scientific 70 // format (with an exponent field). 71 fixed = 1 // Generate floating-point values in fixed-point 72 // format (with no exponent field). 73 }; 74 }; 75 76 /////////////////////////////////////////////////////////////////////// 77 // This is the main function used to generate the output for a 78 // floating point number. It is called by the real generator in order 79 // to perform the conversion. In theory all of the work can be 80 // implemented here, but it is the easiest to use existing 81 // functionality provided by the type specified by the template 82 // parameter `Inserter`. 83 // 84 // sink: the output iterator to use for generation 85 // n: the floating point number to convert 86 // p: the instance of the policy type used to instantiate this 87 // floating point generator. 88 /////////////////////////////////////////////////////////////////////// 89 template <typename Inserter, typename OutputIterator, typename Policies> 90 static bool callboost::spirit::karma::real_policies91 call (OutputIterator& sink, T n, Policies const& p) 92 { 93 return Inserter::call_n(sink, n, p); 94 } 95 96 /////////////////////////////////////////////////////////////////////// 97 // The default behavior is to not to require generating a sign. If 98 // 'force_sign()' returns true, then all generated numbers will 99 // have a sign ('+' or '-', zeros will have a space instead of a sign) 100 // 101 // n The floating point number to output. This can be used to 102 // adjust the required behavior depending on the value of 103 // this number. 104 /////////////////////////////////////////////////////////////////////// force_signboost::spirit::karma::real_policies105 static bool force_sign(T) 106 { 107 return false; 108 } 109 110 /////////////////////////////////////////////////////////////////////// 111 // Return whether trailing zero digits have to be emitted in the 112 // fractional part of the output. If set, this flag instructs the 113 // floating point generator to emit trailing zeros up to the required 114 // precision digits (as returned by the precision() function). 115 // 116 // n The floating point number to output. This can be used to 117 // adjust the required behavior depending on the value of 118 // this number. 119 /////////////////////////////////////////////////////////////////////// trailing_zerosboost::spirit::karma::real_policies120 static bool trailing_zeros(T) 121 { 122 // the default behavior is not to generate trailing zeros 123 return false; 124 } 125 126 /////////////////////////////////////////////////////////////////////// 127 // Decide, which representation type to use in the generated output. 128 // 129 // By default all numbers having an absolute value of zero or in 130 // between 0.001 and 100000 will be generated using the fixed format, 131 // all others will be generated using the scientific representation. 132 // 133 // The function trailing_zeros() can be used to force the output of 134 // trailing zeros in the fractional part up to the number of digits 135 // returned by the precision() member function. The default is not to 136 // generate the trailing zeros. 137 // 138 // n The floating point number to output. This can be used to 139 // adjust the formatting flags depending on the value of 140 // this number. 141 /////////////////////////////////////////////////////////////////////// floatfieldboost::spirit::karma::real_policies142 static int floatfield(T n) 143 { 144 if (traits::test_zero(n)) 145 return fmtflags::fixed; 146 147 T abs_n = traits::get_absolute_value(n); 148 return (abs_n >= 1e5 || abs_n < 1e-3) 149 ? fmtflags::scientific : fmtflags::fixed; 150 } 151 152 /////////////////////////////////////////////////////////////////////// 153 // Return the maximum number of decimal digits to generate in the 154 // fractional part of the output. 155 // 156 // n The floating point number to output. This can be used to 157 // adjust the required precision depending on the value of 158 // this number. If the trailing zeros flag is specified the 159 // fractional part of the output will be 'filled' with 160 // zeros, if appropriate 161 // 162 // Note: If the trailing_zeros flag is not in effect additional 163 // comments apply. See the comment for the fraction_part() 164 // function below. 165 /////////////////////////////////////////////////////////////////////// precisionboost::spirit::karma::real_policies166 static unsigned precision(T) 167 { 168 // by default, generate max. 3 fractional digits 169 return 3; 170 } 171 172 /////////////////////////////////////////////////////////////////////// 173 // Generate the integer part of the number. 174 // 175 // sink The output iterator to use for generation 176 // n The absolute value of the integer part of the floating 177 // point number to convert (always non-negative). 178 // sign The sign of the overall floating point number to 179 // convert. 180 // force_sign Whether a sign has to be generated even for 181 // non-negative numbers. Note, that force_sign will be 182 // set to false for zero floating point values. 183 /////////////////////////////////////////////////////////////////////// 184 template <typename OutputIterator> integer_partboost::spirit::karma::real_policies185 static bool integer_part (OutputIterator& sink, T n, bool sign 186 , bool force_sign) 187 { 188 return sign_inserter::call( 189 sink, traits::test_zero(n), sign, force_sign, force_sign) && 190 int_inserter<10>::call(sink, n); 191 } 192 193 /////////////////////////////////////////////////////////////////////// 194 // Generate the decimal point. 195 // 196 // sink The output iterator to use for generation 197 // n The fractional part of the floating point number to 198 // convert. Note that this number is scaled such, that 199 // it represents the number of units which correspond 200 // to the value returned from the precision() function 201 // earlier. I.e. a fractional part of 0.01234 is 202 // represented as 1234 when the 'Precision' is 5. 203 // precision The number of digits to emit as returned by the 204 // function 'precision()' above 205 // 206 // This is given to allow to decide, whether a decimal point 207 // has to be generated at all. 208 // 209 // Note: If the trailing_zeros flag is not in effect additional 210 // comments apply. See the comment for the fraction_part() 211 // function below. 212 /////////////////////////////////////////////////////////////////////// 213 template <typename OutputIterator> dotboost::spirit::karma::real_policies214 static bool dot (OutputIterator& sink, T /*n*/, unsigned /*precision*/) 215 { 216 return char_inserter<>::call(sink, '.'); // generate the dot by default 217 } 218 219 /////////////////////////////////////////////////////////////////////// 220 // Generate the fractional part of the number. 221 // 222 // sink The output iterator to use for generation 223 // n The fractional part of the floating point number to 224 // convert. This number is scaled such, that it represents 225 // the number of units which correspond to the 'Precision'. 226 // I.e. a fractional part of 0.01234 is represented as 1234 227 // when the 'precision_' parameter is 5. 228 // precision_ The corrected number of digits to emit (see note 229 // below) 230 // precision The number of digits to emit as returned by the 231 // function 'precision()' above 232 // 233 // Note: If trailing_zeros() does not return true the 'precision_' 234 // parameter will have been corrected from the value the 235 // precision() function returned earlier (defining the maximal 236 // number of fractional digits) in the sense, that it takes into 237 // account trailing zeros. I.e. a floating point number 0.0123 238 // and a value of 5 returned from precision() will result in: 239 // 240 // trailing_zeros is not specified: 241 // n 123 242 // precision_ 4 243 // 244 // trailing_zeros is specified: 245 // n 1230 246 // precision_ 5 247 // 248 /////////////////////////////////////////////////////////////////////// 249 template <typename OutputIterator> fraction_partboost::spirit::karma::real_policies250 static bool fraction_part (OutputIterator& sink, T n 251 , unsigned precision_, unsigned precision) 252 { 253 // allow for ADL to find the correct overload for floor and log10 254 using namespace std; 255 256 // The following is equivalent to: 257 // generate(sink, right_align(precision, '0')[ulong], n); 258 // but it's spelled out to avoid inter-modular dependencies. 259 260 typename remove_const<T>::type digits = 261 (traits::test_zero(n) ? 0 : floor(log10(n))) + 1; 262 bool r = true; 263 for (/**/; r && digits < precision_; digits = digits + 1) 264 r = char_inserter<>::call(sink, '0'); 265 if (precision && r) 266 r = int_inserter<10>::call(sink, n); 267 return r; 268 } 269 270 /////////////////////////////////////////////////////////////////////// 271 // Generate the exponential part of the number (this is called only 272 // if the floatfield() function returned the 'scientific' flag). 273 // 274 // sink The output iterator to use for generation 275 // n The (signed) exponential part of the floating point 276 // number to convert. 277 // 278 // The Tag template parameter is either of the type unused_type or 279 // describes the character class and conversion to be applied to any 280 // output possibly influenced by either the lower[...] or upper[...] 281 // directives. 282 /////////////////////////////////////////////////////////////////////// 283 template <typename CharEncoding, typename Tag, typename OutputIterator> exponentboost::spirit::karma::real_policies284 static bool exponent (OutputIterator& sink, long n) 285 { 286 long abs_n = traits::get_absolute_value(n); 287 bool r = char_inserter<CharEncoding, Tag>::call(sink, 'e') && 288 sign_inserter::call(sink, traits::test_zero(n) 289 , traits::test_negative(n), false); 290 291 // the C99 Standard requires at least two digits in the exponent 292 if (r && abs_n < 10) 293 r = char_inserter<CharEncoding, Tag>::call(sink, '0'); 294 return r && int_inserter<10>::call(sink, abs_n); 295 } 296 297 /////////////////////////////////////////////////////////////////////// 298 // Print the textual representations for non-normal floats (NaN and 299 // Inf) 300 // 301 // sink The output iterator to use for generation 302 // n The (signed) floating point number to convert. 303 // force_sign Whether a sign has to be generated even for 304 // non-negative numbers 305 // 306 // The Tag template parameter is either of the type unused_type or 307 // describes the character class and conversion to be applied to any 308 // output possibly influenced by either the lower[...] or upper[...] 309 // directives. 310 // 311 // Note: These functions get called only if fpclassify() returned 312 // FP_INFINITY or FP_NAN. 313 /////////////////////////////////////////////////////////////////////// 314 template <typename CharEncoding, typename Tag, typename OutputIterator> nanboost::spirit::karma::real_policies315 static bool nan (OutputIterator& sink, T n, bool force_sign) 316 { 317 return sign_inserter::call( 318 sink, false, traits::test_negative(n), force_sign) && 319 string_inserter<CharEncoding, Tag>::call(sink, "nan"); 320 } 321 322 template <typename CharEncoding, typename Tag, typename OutputIterator> infboost::spirit::karma::real_policies323 static bool inf (OutputIterator& sink, T n, bool force_sign) 324 { 325 return sign_inserter::call( 326 sink, false, traits::test_negative(n), force_sign) && 327 string_inserter<CharEncoding, Tag>::call(sink, "inf"); 328 } 329 }; 330 }}} 331 332 #endif // defined(BOOST_SPIRIT_KARMA_REAL_POLICIES_MAR_02_2007_0936AM) 333