Boost logo

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