Search

std::numeric_limits<float>::max_digits10 value of 8 is wrong and should be 9 by Paul A Bristow

Closed
as Fixed Help for as Fixed

2
0
Sign in
to vote
Type: Bug
ID: 668921
Opened: 5/17/2011 9:48:09 AM
Access Restriction: Public
Moderator Decision: Sent to Engineering Team for consideration
0
Workaround(s)
1
User(s) can reproduce this bug
std::numeric_limits<float>::max_digits10 value of 8 is wrong and should be 9.

max_digits10 is the number of decimal digits that is required to ensure that a 1 least significant bit change in the floating point value produces a change in the decimal digits string representation.

// See for details: http://www2.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1822.pdf

The long accepted formula for this was given by Kahan

2 + std::numeric_limits<float>::digits * 3010/10000

and for float this gives a value of 9.

VC 10 returns only 8, and this is not sufficient for a significant number of float values.

One example (and only one is necessary for the choice of 8 to be wrong, but about 1/3 show this problem)

1.10000006e-032f or as a binary pattern in hex a647609 is displayed using max_digits 10 as

1.1000001e-032

but the next binary value, a64760a is also displayed as the *same* value 1.1000001e-032.

Using the accepted value of 9 for max_digits10,

a647609 is displayed as 1.10000006e-032

a64760a is displayed as 1.10000014e-032

which is as expected.

This has some serious effects on programs that rely on max_digits value being sufficient to reflect a one digit change. It will cause dificult to diagnose apparently random faults (only for about 1/3 of values) in Boost lexical_cast and Boost.serialisation and archive and Boost.Test, and many other user programs.












Details (expand)

Visual Studio/Team Foundation Server/.NET Framework Tooling version

Visual Studio 2010

Steps to reproduce

union ful
{ // Used to enable output of float in hex.
// Assume unsigned long long is big enough to hold a float.
// How to check this is true? Better than nothing is:
// assert(numeric_limits<double>::digits <= numeric_limits<unsigned long long>::digits);
float f;
unsigned long u;
};


float output_value = 1.1e-32f;
cout << "std::numeric_limits<float>::max_digits10 = " << std::numeric_limits<float>::max_digits10 << endl;
cout << "2 + std::numeric_limits<float>::digits * 3010/10000 = " << 2 + std::numeric_limits<float>::digits * 3010/10000 << endl;

//cout.precision(2 + std::numeric_limits<float>::digits * 3010/10000); // 9
cout.precision(std::numeric_limits<float>::max_digits10); // 8

int max_digits10 = std::numeric_limits<float>::max_digits10;
max_digits10 = 2 + std::numeric_limits<float>::digits * 3010/10000;

ful of;
of.f = 1.10000006e-032f;

cout << showpoint << of.f << endl;
cout << hex << of.u << endl;

std::ostringstream os;
    // stream.precision(2 + std::numeric_limits<float>::digits * 301/1000);
    // Kahan formula says 9 digits the maximum number that are significant for 32 bit float.

os.precision(max_digits10); // MS says 8
os << showpoint << of.f; // Show trailing zeros.

string previous = os.str(); // Save current float as string.
unsigned int prevu = of.u; // and save as binary pattern as hex,
float prevf = of.f; // and as float.

ful nf;
//nf.f = nextafterf(of.f, +1.F); // Increment binary pattern by 1 least significant bit.
nf = of;
nf.u++;

std::ostringstream os2; // Nextafter as string.
os2.precision(max_digits10); // MS says 8, Kahan says 9.
os2 << showpoint << nf.f; // Show trailing zeros.

if (previous == os2.str())
{
    cout << "float string unchanged!" << endl;
}
cout << "Previous == " << previous << ' ' << of.f << " == " << hex << of.u << std::endl;
cout << "Now     == " << os2.str() << ' ' << nf.f << " == " << hex << nf.u << std::endl;

return 0;

Product Language

English

Operating System

Windows 7

Operating System Language

English

Actual results

std::numeric_limits<float>::max_digits10 == 8 // MS choice


1.10000006e-032f or as a binary pattern in hex a647609 is displayed using max_digits 10 as

1.1000001e-032

but the next binary value, a64760a is also displayed as the *same* value 1.1000001e-032.

Expected results

std::numeric_limits<float>::max_digits10 ==9 // using Kahan formula

a647609 display as 1.10000006e-032
a64760a displays as 1.10000014e-032

If this is not sufficient, I can provide a program file, but the fault should be quite clear.
File Attachments
0 attachments
Sign in to post a comment.
Posted by Microsoft on 6/28/2011 at 5:02 PM
Hi,

Thanks for reporting this bug. We've fixed it, and the fix will be available in VC11.

If you have any further questions, feel free to E-mail me at stl@microsoft.com .

Stephan T. Lavavej
Visual C++ Libraries Developer
Posted by Paul A Bristow on 6/6/2011 at 4:50 AM
FWIW, gcc provides the accepted value of 9 for std::numeric_limits<float>::max_digits10;
Posted by MS-Moderator09 [Feedback Moderator] on 5/17/2011 at 7:50 PM
Thank you for submitting feedback on Visual Studio 2010 and .NET Framework. Your issue has been routed to the appropriate VS development team for review. We will contact you if we require any additional information.
Posted by MS-Moderator09 on 5/17/2011 at 6:36 PM
Thank you for your feedback, We are currently reviewing the issue you have submitted. If this issue is urgent, please contact support directly(http://support.microsoft.com)
Sign in to post a workaround.