Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ `digits10` is 6 for IEEE float, but the first non-representable integer already has 8 digits?

C++'s std::numeric_limits<float>::digits10, is described on cppref as such:

The value of std::numeric_limits<T>::digits10 is the number of base-10 digits that can be represented by the type T without change, that is, any number with this many decimal digits can be converted to a value of type T and back to decimal form, without change due to rounding or overflow.

A similar description exists for the C cousin FLT_DIG.

The value given is:

float     FLT_DIG /* 6 for IEEE float */

However, it is shown here on S.O. that all integers up to 16,777,216 (224) are exactly representable in a 32 bit IEEE float type. And if I can count, that number has 8 digits, so the value for digits10 should actually be 7, now shouldn't it?

Rather obviously, I misunderstand something about digits10 here, so what does this actually tell me?


Practical applicability:

I was asked if we could store all numbers from 0.00 - 86,400.00 exactly in an IEEE 32 bit float.

Now, I'm very confident that we could store all numbers from 0 - 8,640,000 in an IEEE 32 bit float, but does this hold for the same "integer" range shifted by 2 digits to the left?

like image 987
Martin Ba Avatar asked Dec 03 '22 21:12

Martin Ba


1 Answers

(Restricting this answer to IEEE754 float).

8.589973e9 and 8.589974e9 both map to 8589973504. That's a counter-example for an assertion that the 7th significant figure is preserved.

Since no such counter-example exists on the 6th significant figure, std::numeric_limits<float>::digits10 and FLT_DIG are 6.

Indeed integers can be represented exactly up to the 24th power of 2. (16,777,216 and 16,777,217 both map to 16,777,216). That's because a float has a 24 bit significand.

like image 135
Bathsheba Avatar answered Apr 27 '23 17:04

Bathsheba