MS VC10 std::numeric_limits<float>::max_digits10 is wrong for float

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-numer... 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@hetp.u-net.com

[Paul A. Bristow]
https://connect.microsoft.com/VisualStudio/feedback/details/668921/ std-numeric-limits-float-max-digits10-value-of-8-is-wrong-and-should-be-9
I trust this mistake will be corrected pronto - but I'm not holding my breath :-(
This bug is currently assigned to me. I'll need to verify it, but it looks like you're right. I can't promise anything, but I expect that we'll be able to fix it this month. However, the fix will be in VC11, and NOT released as a hotfix for VC10. Stephan T. Lavavej Visual C++ Libraries Developer

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Stephan T. Lavavej Sent: Monday, June 06, 2011 7:03 PM To: boost@lists.boost.org Subject: Re: [boost] MS VC10 std::numeric_limits<float>::max_digits10 is wrong for float
[Paul A. Bristow]
https://connect.microsoft.com/VisualStudio/feedback/details/668921/ std-numeric-limits-float-max-digits10-value-of-8-is-wrong-and-should-be-9
I trust this mistake will be corrected pronto - but I'm not holding my breath :-(
This bug is currently assigned to me. I'll need to verify it, but it looks like you're right. I can't promise anything, but I expect that we'll be able to fix it this month. However, the fix will be in VC11, and NOT released as a hotfix for VC10.
:-) But tell me if I can help - I initially used a brute force loopback method to check - took overnight & kept my office warm ;-) Paul --- Paul A. Bristow, Prizet Farmhouse, Kendal LA8 8AB UK +44 1539 561830 07714330204 pbristow@hetp.u-net.com

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Stephan T. Lavavej Sent: Monday, June 06, 2011 7:03 PM To: boost@lists.boost.org Subject: Re: [boost] MS VC10 std::numeric_limits<float>::max_digits10 is wrong for float
[Paul A. Bristow]
https://connect.microsoft.com/VisualStudio/feedback/details/668921/ std-numeric-limits-float-max-digits10-value-of-8-is-wrong-and-should-be-9
I trust this mistake will be corrected pronto - but I'm not holding my breath :-(
This bug is currently assigned to me. I'll need to verify it, but it looks like you're right. I can't promise anything, but I expect that we'll be able to fix it this month. However, the fix will be in VC11, and NOT released as a hotfix for VC10.
Assuming I am right, I think this means that we need yet another macro (Groans and Cries of Oh No, not another!) because BOOST_NO_NUMERIC_LIMITS_LOWEST not defined is no longer an indicator that max_digits10 is available (and its values correct). So do we need BOOST_NO_NUMERIC_LIMITS_MAX_DIGITS10 which should be defined by default, and only undefined for those libraries supporting C++0X std::numeric_limits with correct values like recent GCC - and others (but not <= VC10)? Views? Paul --- Paul A. Bristow, Prizet Farmhouse, Kendal LA8 8AB UK +44 1539 561830 07714330204 pbristow@hetp.u-net.com

Assuming I am right, I think this means that we need yet another macro (Groans and Cries of Oh No, not another!)
because
BOOST_NO_NUMERIC_LIMITS_LOWEST
not defined is no longer an indicator that
max_digits10 is available (and its values correct).
So do we need
BOOST_NO_NUMERIC_LIMITS_MAX_DIGITS10
which should be defined by default, and only undefined for those libraries supporting C++0X std::numeric_limits with correct values like recent GCC - and others (but not <= VC10)?
Views?
Sigh.... I guess so. Care to submit a patch? John.

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of John Maddock Sent: Wednesday, June 08, 2011 5:05 PM To: boost@lists.boost.org Subject: Re: [boost] MS VC10 std::numeric_limits<float>::max_digits10 iswrong for float
Assuming I am right, I think this means that we need yet another macro (Groans and Cries of Oh No, not another!)
because
BOOST_NO_NUMERIC_LIMITS_LOWEST
not defined is no longer an indicator that
max_digits10 is available (and its values correct).
So do we need
BOOST_NO_NUMERIC_LIMITS_MAX_DIGITS10
which should be defined by default, and only undefined for those libraries supporting C++0X std::numeric_limits with correct values like recent GCC - and others (but not <= VC10)?
Views?
Sigh.... I guess so. Care to submit a patch?
in dinkumware.hpp I think it should be // C++0x headers implemented in 520 (as shipped by Microsoft) (assuming 520 is the version shipped with VC10 and that VC11 will correct and bump _CPPLIB_VER ?) Note _CPPLIB_VER <= rather than < 520 for other similar macros #if !defined(_CPPLIB_VER) || _CPPLIB_VER <= 520 # define BOOST_NO_NUMERIC_LIMITS_ MAX_DIGITS10 #endif but there are many other compilers' config files and I'm not clear which versions implement C++0X and thus presumably max_digits10 - and if anyone else has had a mental aberration/fat finger? What I'm expecting people to be able to write is something like int max_digits10; #ifdef BOOST_NO_NUMERIC_LIMITS_ MAX_DIGITS10 max_digits10 = 2 + std::numeric_limits<FPT>::digits * 3010/10000; #else max_digits10 = std::numeric_limits<FPT>::max_digits10; #endif Paul --- Paul A. Bristow, Prizet Farmhouse, Kendal LA8 8AB UK +44 1539 561830 07714330204 pbristow@hetp.u-net.com

[Paul A. Bristow]
in dinkumware.hpp I think it should be // C++0x headers implemented in 520 (as shipped by Microsoft) (assuming 520 is the version shipped with VC10 and that VC11 will correct and bump _CPPLIB_VER ?) Note _CPPLIB_VER <= rather than < 520 for other similar macros #if !defined(_CPPLIB_VER) || _CPPLIB_VER <= 520 # define BOOST_NO_NUMERIC_LIMITS_ MAX_DIGITS10 #endif
I can't speak for other compilers using Standard Library implementations licensed from Dinkumware, but for VC you should never look at _CPPLIB_VER. Instead, you should check _MSC_VER, which corresponds to VC's major version number. (VC8 is 1400, VC9 is 1500, VC10 is 1600, VC11 is 1700.) Especially don't look at _HAS_TR1 (already removed!) or _HAS_CPP0X (will be removed as soon as I can claw it out of our build system and tests). Separately, Dinkumware has told me that 8 really is the right answer here, not 9. I know exactly one thing about floating point - to treat it with respect and fear, mostly fear - so I'll need to ask for more info. Thanks, STL

On 08-Jun-11 9:32 PM, Stephan T. Lavavej wrote:
Separately, Dinkumware has told me that 8 really is the right answer here, not 9.
Hmmm... then if they are right, we're all wrong, because 9 is the number I've always seen as correct. OTOH, we *could* have been all wrong, all alone, since this is the sort of thing that just gets perpetuated from publication to publication and mouth to mouth. Do they explained why? [Are P.J. and Pete still the ones behind these things?] -- --- Fernando Cacciola SciSoft Consulting, Founder http://www.scisoft-consulting.com

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Fernando Cacciola Sent: Thursday, June 09, 2011 4:35 AM To: boost@lists.boost.org Subject: Re: [boost] MS VC10 std::numeric_limits<float>::max_digits10 iswrong for float
On 08-Jun-11 9:32 PM, Stephan T. Lavavej wrote:
Separately, Dinkumware has told me that 8 really is the right answer here, not 9.
Hmmm... then if they are right, we're all wrong, because 9 is the number I've always seen as correct.
OTOH, we *could* have been all wrong, all alone, since this is the sort of thing that just gets perpetuated from publication to publication and mouth to mouth.
Do they explained why? [Are P.J. and Pete still the ones behind these things?]
Well I was surprised to notice the value 8 and so I re-ran my existing loopback test (that had previously worked OK for float, but not for double). (This test was purely for convenience - takes all night to run, brute force is possible for float whereas for double test all possible values would take 35 years at current processor speeds! (though a random test did reveal loopback fails with doubles with the Dinkumware library, allegedly a feature, not a bug). It was devised to check if loopback (output to a string and reading back in) works OK (a separate issue, but if max_digits10 is wrong, loopback will fail). This issue is NOT about loopback (which is NOT guaranteed by the C++ Standard) but about max_digits10. So I ran a much simple test and found quite a few values of float that give the same decimal digit string for 1-bit different binary patterns. But it only takes one value that 'fails' for 8 to be wrong, and a simple example is below: union ful { // Used to enable output of float in hex. float f; unsigned long u; }; int main() { ful f1; f1.f= 1.10000006e-032f; ful f2; f2.f = 1.10000014e-032f; // 1 bit greater in FP binary pattern, see hex display below cout << "f1 " << setprecision(8) << "precision 8 " << f1.f << endl; cout << "f1 "<< setprecision(9) << "precision 9 " << f1.f << endl; cout << "f1 " << hex << f1.u << endl; cout << "f2 " << setprecision(8) << "precision 8 " << f2.f << endl; cout << "f2 " << setprecision(9) << "precision 9 " << f2.f << endl; cout << "f2 " << hex << f2.u << endl; return 0; } f1 precision 8 1.1000001e-032 f1 precision 9 1.10000006e-032 f1 a647609 f2 precision 8 1.1000001e-032 <<<<<<<<<< note this is the same as f1 above using 8. f2 precision 9 1.10000014e-032 <<<< but f1 and f2 are different using 9. f2 a64760a <<<<<<<<<< note f2 really is one bit greater and so should have a different decimal digits string representation. I hope this is convincing - I conclude that Kahan was right, and is still is ;-) Paul --- Paul A. Bristow, Prizet Farmhouse, Kendal LA8 8AB UK +44 1539 561830 07714330204 pbristow@hetp.u-net.com

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Stephan T. Lavavej Sent: Saturday, June 11, 2011 3:36 AM To: boost@lists.boost.org Subject: Re: [boost] MS VC10 std::numeric_limits<float>::max_digits10 is wrong for float
[Paul A. Bristow]
I hope this is convincing - I conclude that Kahan was right, and is still is ;-)
Dinkumware (i.e. PJP) agrees with you, and we'll fix VC11.
Thanks :-) Paul PS I hope people realise how much trouble this causes for those trying to write clear code, and be portable. What happened to QA and testing? We either need a specific BOOST macro to deal with this (since we can't just test for a C++0X library) , or we have to stick to the Kahan formula for yet another year :-( (Reluctantly, I'm coming to be view that the latter is the easiest thing to do, since there are so many compilers/libraries to deal with, making config a rats nest.) --- Paul A. Bristow, Prizet Farmhouse, Kendal LA8 8AB UK +44 1539 561830 07714330204 pbristow@hetp.u-net.com

On 12/06/2011 17:38, Paul A. Bristow wrote:
or we have to stick to the Kahan formula for yet another year :-( (Reluctantly, I'm coming to be view that the latter is the easiest thing to do, since there are so many compilers/libraries to deal with, making config a rats nest.)
Exactly what are the advantages of not doing so?

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Mathias Gaunard Sent: Tuesday, June 14, 2011 10:46 PM To: boost@lists.boost.org Subject: Re: [boost] MS VC10 std::numeric_limits<float>::max_digits10 iswrong for float
On 12/06/2011 17:38, Paul A. Bristow wrote:
or we have to stick to the Kahan formula for yet another year :-( (Reluctantly, I'm coming to be view that the latter is the easiest thing to do, since there are so many compilers/libraries to deal with, making config a rats nest.)
Exactly what are the advantages of not doing so?
Using the constant numeric_limits<FPT>::max_digits10 is absolutely clear to the reader, and may be more efficient. Using the Kahan formula is obscure to the non-cognoscenti, and may not be compiled so efficiently. Defining yet another Boost macro in config files is quite a bit of trouble, carries some risk of a mistake. Using a Boost macro that tests for a C++0X library and uses Kahan formula if not, is messy, but at least the meaning of the code is clear because the C++0X path specifies max_digits10. The bottom line is that digits10 was never what most people want and should have been max_digits10 to start with :-) The line of least effort is to wait for MS to correct the value. Paul --- Paul A. Bristow, Prizet Farmhouse, Kendal LA8 8AB UK +44 1539 561830 07714330204 pbristow@hetp.u-net.com
participants (5)
-
Fernando Cacciola
-
John Maddock
-
Mathias Gaunard
-
Paul A. Bristow
-
Stephan T. Lavavej