Definition of FLT_EPSILON
Pascal Cuoq - 9th May 2013Correct and wrong definitions for the constant FLT_EPSILON
If I google “FLT_EPSILON”, the topmost result is this page with this definition:
FLT_EPSILON the minimum positive number such that 1.0 + FLT_EPSILON != 1.0.
No no no no no.
I don't know where this definition originates from but it is obviously from some sort of standard C library and it is wrong wrong wrong wrong wrong. The definition of the C99 standard is:
the difference between 1 and the least value greater than 1 that is representable in the given floating point type b^(1−p)
The GNU C library gets it right:
FLT_EPSILON: This is the difference between 1 and the smallest floating point number of type float that is greater than 1.
The difference
On any usual architecture with the correct definition FLT_EPSILON is 0x0.000002p0
the difference between 0x1.000000p0
and the smallest float above it 0x1.000002p0
.
The notation 0x1.000002p0
is a convenient hexadecimal input format introduced in C99 for floating-point numbers. The last digit is a 2
where one might have expected a 1
because single-precision floats have 23 explicit bits of mantissa and 23 is not a multiple of 4. So the 2
in 0x1.000002p0
represents the last bit that can be set in a single-precision floating-point number in the interval [1…2).
If one adds FLT_EPSILON to 1.0f
one does obtain 0x1.000002p0
. But is it the smallest float
with this property?
#include <stdio.h> void pr_candidate(float f) { printf("candidate: %.6a\tcandidate+1.0f: %.6a" f 1.0f + f); } int main(){ pr_candidate(0x0.000002p0); pr_candidate(0x0.000001fffffep0); pr_candidate(0x0.0000018p0); pr_candidate(0x0.000001000002p0); pr_candidate(0x0.000001p0); }
This program compiled and executed produces:
candidate: 0x1.000000p-23 candidate+1.0f: 0x1.000002p+0 candidate: 0x1.fffffep-24 candidate+1.0f: 0x1.000002p+0 candidate: 0x1.800000p-24 candidate+1.0f: 0x1.000002p+0 candidate: 0x1.000002p-24 candidate+1.0f: 0x1.000002p+0 candidate: 0x1.000000p-24 candidate+1.0f: 0x1.000000p+0
No 0x0.000002p0
is not the smallest number that added to 1.0f
causes the result to be above 1.0f
. This honor goes to 0x0.000001000002p0
the smallest float above half FLT_EPSILON.
Exactly half FLT_EPSILON the number 0x0.000001p0
or 0x1.0p-24
as you might prefer to call it causes the result of the addition to be exactly midway between 1.0f
and its successor. The rule says that the “even” one has to be picked in this case. The “even” one is 1.0f
.
Conclusion
Fortunately in the file that initiated this rant the value for FLT_EPSILON is correct:
#define FLT_EPSILON 1.19209290E-07F // decimal constant
This is the decimal representation of 0x0.000002p0
. Code compiled against this header will work. It is only the comment that's wrong.