
Boost : 
From: Paul A Bristow (pbristow_at_[hidden])
Date: 20061030 05:50:08
 Original Message
 From: boostbounces_at_[hidden]
 [mailto:boostbounces_at_[hidden]] On Behalf Of Daryle Walker
 Sent: 29 October 2006 20:00
 To: Boost mailing list
 Subject: [boost] Simulating log{10}(2)
<snip>
 The common approximation 0.301 differs from the actual
 expansion at a4 = 2.
 The convergent there is 59/196. The absolute differences
 between those
 values and the actual value are:

 log{10}(2)  0.301 = 2.9995664e5
 log{10}(2)  59/196 = 9.58750072e6

 The convergent is 3.1 times closer to the actual value than
 the common
 approximation. Using 0.30103 versus the convergent
 4004/13301 at the point
 of differing a7 = 6 gives the convergent an improvement
 factor of 2.1. The
 convergents have smaller numerators and denominators than
 their common
 approximations, making them easier to calculate without
 worry of overflow.
 Conversely, if you know that you have more leeway in
 multiplications, then
 using higher convergent fractions instead of the decimal
 expansion are a
 better bet.
Well this is very interesting and I am sure you are right,
but for the purpose of calculating the number of decimal digits,
the approximation seems to me to be 'fit for purpose' (or good enough).
Fred Tydeman put me right on this (especially with regard to overflow and accuracy) with the following, extracted from his comments
incorporated in
http://www.openstd.org/jtc1/sc22/wg14/www/docs/n1171.pdf
<quote>
For base 2 systems, values for these macros are usually conveniently derived from the number of significand (mantissa) binary
digits, significand_digits defined by
FLT_MANT_DIG, DBL_MANT_DIG or LDBL_MANT_DIG
using the formula
max_digits10 = 2 + significand_digits * 301/1000 // if 16bit integers
else
max_digits10 = 2 + significand_digits * 30103UL/100000UL
For example, for systems with 32bit integers:
#define FLT_MAXDIG10 (2+(FLT_MANT_DIG * 30103UL)/100000UL)
#define DBL_MAXDIG10 (2+ (DBL_MANT_DIG * 30103UL)/100000UL)
#define LDBL_MAXDIG10 (2+ (LDBL_MANT_DIG * 30103UL)/100000UL)
which yield the following values on typical implementations:
32bit IEEE 754 float FLT_DIG 6, FLT_MAXDIG10 9
64bit IEEE 754 double DBL_DIG 15, DBL_MAXDIG10 17
80bit IEEE 754 long double LDBL_DIG 19, LDBL_MAXDIG10 21
For 16bit integer systems:
if DBLMANT_DIG is 53 (for IEEE 64bit doubles) then 53 * 301 = 15953, but larger and more accurate approximations, like 3010/10000
or 30103/100000, would overflow 16bit integers.
For 32bit integer systems:
the more accurate ratio 30103UL/100000UL is preferred to give the correct values for well beyond 256 significand bits.
Significand bit values where .3 and .30103 produce different values:
103, 113, 123, 133, 143, 153, 163, 173, 183, 193, 196, 203, 206, 213, 216, 223, 226, 233, 236, 243, 246, 253, 256, 263, 266, 273,
276, 283, 286, 293, 296, 299, ...
showing that using 301/1000 would give an incorrect result for these significand bits but 30103UL/100000UL will be correct. Using
UL further reduces the risk of overflow.
For user defined floatingpoint types, usually to implement very high precision not available in hardware, similar (but of course
nonstandard) macros can be defined.
</quote>
The corresponding C++ document is
http://www2.openstd.org/JTC1/SC22/WG21/docs/papers/2005/n1822.pdf
std::numeric_limits::max_digits10 should become standard in time.
meanwhile you might like to declare macros as above DBL_MAXDIG10 etc when you can use your shiny new improved approximation.
Or should Boost do this as BOOST_FLT_MAXDIG10 BOOST_DBL_MAXDIG10, BOOST_LDBL_MAXDIG10 right now?
Paul
 Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539561830 & SMS, Mobile +44 7714 330204 & SMS pbristow_at_[hidden]
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk