saneman wrote:

After a few hours of messing with my brains I found a website where they say

that comparing floats in C++ is not guranteed to return an expected result.

There are a few flaws in that statement:

- This is not related to C++ in particular, but computers in general.

All programming languages which perform direct floating point

comparisons will present the same issue. (Some programming languages

might perform an automatic range comparison behind the scenes, but C++

only does exactly what you tell it to do, nothing more.)

- Whether the result you are seeing is "expected" or not is a question

of definition. For example, assume that I expect this comparison to

return true:

0.3333333 + 0.3333333 + 0.3333333 == 1.0

but instead, it returns false. My expectation was wrong. In fact, the

comparison returning false is what should be expected. Why? Because if

you calculate that sum, you get 0.9999999, which is different from 1.0.

Thus they should obviously compare unequal.

In your example program you are summing 0.001 to itself. However,

computers do not calculate with decimal numbers. They calculate with

base-2 numbers with a limited amount of bits. Base-2 floating point

values with a limited amount of bits cannot represent 0.001 accurately

(for the exact same reason that decimal numbers cannot represent 1/3

accurately).

Thus when you write 0.001, internally the actual value will be just a

tiny bit smaller than that (exactly like 0.333333333333333 is a tiny bit

smaller than 1/3). When you sum that with itself a thousand times, what

you get is 1000 times that a-bit-smaller value, which ends up being

a-bit-smaller than 1.0, which obviously compares unequal to 1.0.

Thus summing 0.001 to itself 1000 times is *expected* to give a result

which is smaller than 1.0 because 0.001 is actually a bit smaller than

what it looks.

(This doesn't mean that no decimal number can be represented

accurately with base-2 floating point numbers. For example 1.0 and 0.5

can be represented accurately, without any rounding off.)

The result of long calculations can accumulate these types of rounding

errors, and thus the result may differ from what an infinitely-accurate

mathematical formula would tell you. Thus you have to make ranged

comparisons.

Another option is to avoid floating point numbers altogether. In many

situations they are just not needed. For example, if you just need all

the values between 0.0 and 1.0, you can do this:

for(int i = 0; i <= 1000; ++i)

someFunctionTakingADouble(i/1000.0);

Now, surprisingly, the last value given to the function will be

exactly 1.0.