|
Boost : |
Subject: [boost] MS VC10 std::numeric_limits<float>::max_digits10 is wrong for float
From: Paul A. Bristow (pbristow_at_[hidden])
Date: 2011-06-06 10:45:53
Inexplicably, MS for VS 10 have chosen std::numeric_limits<float>::max_digits10 == 8 for VS 10
rather than 9, when the formula
max_digits10 = 2 + std::numeric_limits<FPT>::digits * 3010/10000;
and values have been known for 30 years.
std::numeric_limits<T>:: max_digits10; is 'new for C++0X'.
Briefly, max_digits10 is the number of decimal digits that you need to output to make sure that a
one least significant bit (ULP) change produces a different decimal digit string. Any more digits
are just noise with no useful information.
Using max_digits10 rather than the formula above may be more efficient, and is certainly very much
clearer.
"Executive Summary"
================
Don't use max_digits10 for float or floating-point template types for MS VS - yet!
You can safely (and very usefully) use
cout.precision(std::numeric_limits<double>::max_digits10);
when you want to be sure that all significant decimal digits are output.
GCC provides the correct values of 9 for float (and 17 for double).
The Fuller Story
===========
This might affect anyone planning to use VS10 and this new (and very useful numeric_limits value)
with built-in *type float, or a floating-point template type*, potentially, for example, with Boost
Lexical_cast, Serialization. Round tripping would be 1 bit wrong in perhaps 1/3 of cases! If
max_digits10 was used, Boost.Test might detect values that are different, but are reported to be the
same, for example. As far as I know, none of these utilities yet try to use max_digits10.
Mercifully, this fault only affects type T = float (not the most popular double or long double), and
only in new code that uses the 'new for C++0X' numeric_limits<T>:: max_digits10. Other types like
double and long double (and possibly user defined types that specialize numeric_limits) are, I
believe, correct.
So you can safely (and very usefully) use
cout.precision(std::numeric_limits<double>::max_digits10);
when you want to be sure that all significant decimal digits are output.
(If you want this to be 'Boost portable' you will have to use the inscrutably named
BOOST_NO_NUMERIC_LIMITS_LOWEST
as a proxy for "C++0x numeric_limits before using new-for-C++0X max_digits10. Unless we add yet
another macro for max_digits10? Groan.).
The workaround is to continue to use the well-tried and test Kahan formula
max_digits10 = 2 + std::numeric_limits<FPT>::digits * 3010/10000;
Reported and confirmed as
https://connect.microsoft.com/VisualStudio/feedback/details/668921/std-numeric-limits-float-max-digi
ts10-value-of-8-is-wrong-and-should-be-9
(It might help if, you could confirm you can 'reproduce' this too).
I trust this mistake will be corrected pronto - but I'm not holding my breath :-(
I will post again if it is resolved.
Paul
--- Paul A. Bristow, Prizet Farmhouse, Kendal LA8 8AB UK +44 1539 561830 07714330204 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