I was trying to loop through all possible values of a float like this:
float i = 0.0F;
float epsilon = float.Epsilon;
while (i != float.MaxValue) {
i += epsilon;
}
but after reaching the value 2.3509887E-38F it stops increasing.
float init = 2.3509887E-38F;
float f = (init + float.Epsilon);
Console.WriteLine(f == init);
I’m just curious, can anyone explain exactly why?
So, I can add epsilon to a float 16777216 times before the rounding error, and that number looks awfully familiar (2^24).
There’s a lot of very wooly thinking here. Floating point numbers are not “imprecise”. There is no “may”. It’s a deterministic system, like anything else on a computer.
Don’t to analyze what’s going on by looking at decimal representations. The source of this behavior is completely obvious if you look at these numbers in binary or hexadecimal. Let’s use binary:
If we add these two numbers together, the infinitely precise (unrounded) sum is:
Note that the significand of this sum is 25 bits wide (I’ve grouped the binary digits into sets of four to make them easier to count). This means that it cannot be represented in single-precision, so the result of this sum is not this value, but instead this value rounded to the closes representable
float. The two closest representable numbers are:Our number is exactly halfway in between them. Since you haven’t set the rounding mode in your program, we are in the default rounding mode, which is called “round to nearest, ties to even”. Because the two options are equally close, the tie is broken by choosing the one whose lowest-order bit is zero. Thus, 2^-125 + 2^-149 is rounded to 2^-125, which is why “it stops increasing”.