Is floating point precision mutable or invariant, and why?
Typically, given any numbers in the same power-of-2 range, the floating point precision is invariant - a fixed value. The absolute precision changes with each power-of-2 step. Over the entire FP range, the precision is approximately relative to the magnitude. Relating this relative binary precision in terms of a decimal precision incurs a wobble varying between DBL_DIG
and DBL_DECIMAL_DIG
decimal digits - Typically 15 to 17.
What is precision? With FP, it makes most sense to discuss relative precision.
Floating point numbers have the form of:
Sign * Significand * pow(base,exponent)
They have a logarithmic distribution. There are about as many different floating point numbers between 100.0 and 3000.0 ( a range of 30x) as there are between 2.0 and 60.0. This is true regardless of the underlying storage representation.
1.23456789e100
has about the same relative precision as 1.23456789e-100
.
Most computers implemment double
as binary64. This format has 53 bits of binary precision.
The n
numbers between 1.0 and 2.0 have the same absolute precision of 1 part in ((2.0-1.0)/pow(2,52).
Numbers between 64.0 and 128.0, also n
, have the same absolute precision of 1 part in ((128.0-64.0)/pow(2,52).
Even group of numbers between powers of 2, have the same absolute precision.
Over the entire normal range of FP numbers, this approximates a uniform relative precision.
When these numbers are represented as decimal, the precision wobbles: Numbers 1.0 to 2.0 have 1 more bit of absolute precision than numbers 2.0 to 4.0. 2 more bits than 4.0 to 8.0, etc.
C provides DBL_DIG
, DBL_DECIMAL_DIG
, and their float
and long double
counterparts. DBL_DIG
indicates the minimum relative decimal precision. DBL_DECIMAL_DIG
can be thought of as the maximum relative decimal precision.
Typically this means given double
will have at 15 to 17 decimal digits of precision.
Consider 1.0
and its next representable double
, the digits do not change until the 17th significant decimal digit. Each next double
is pow(2,-52)
or about 2.2204e-16
apart.
/*
1 234567890123456789 */
1.000000000000000000...
1.000000000000000222...
Now consider "8.521812787393891"
and its next representable number as a decimal string using 16 significant decimal digits. Both of these strings, converted to double
are the same 8.521812787393891142073699...
even though they differ in the 16th digit. Saying this double
had 16 digits of precision was over-stated.
/*
1 234567890123456789 */
8.521812787393891
8.521812787393891142073699...
8.521812787393892