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