I am writing a loop that increments with a float, but I have come across a floating-point arithmetic issue illustrated in the following example:
for(float value = -2.0; value <= 2.0; value += 0.2)
std::cout << value << std::endl;
Here is the output:
-2
-1.8
-1.6
-1.4
-1.2
-1
-0.8
-0.6
-0.4
-0.2
1.46031e-07
0.2
0.4
0.6
0.8
1
1.2
1.4
1.6
1.8
Why exactly am I getting 1.46031e-07
instead of 0
? I know this has something to do with floating-point errors, but I can't grasp why it is happening and what I should do to prevent this from happening (if there is a way). Can someone explain (or point me to a link) that will help me understand? Any input is appreciated. Thanks!
bring all my ADSR envelope values into the positive SInt16 range. multiply with the current value from the wavetable (store intermediates as SInt32 ) shift the result by 16 to the right.
(1) Floating point numbers do not have error. Every floating point value is exactly what it is. Most (but not all) floating point operations give inexact results. For example, there is no binary floating point value that is exactly equal to 1.0/10.0.
Because often-times, they are approximating rationals that cannot be represented finitely in base 2 (the digits repeat), and in general they are approximating real (possibly irrational) numbers which may not be representable in finitely many digits in any base.
As everybody else has said, this is do to the fact that the real numbers are an infinite and uncountable set, while floating point representations use a finite number of bits. Floating point numbers can only approximate real numbers and even in many simple cases are not precise, due to their definition. As you have now seen, 0.2
is not actually 0.2
but is instead a number very close to it. As you add these to value
, you accumulate the error at each step.
As an alternative, try using int
s for your iteration and dividing the result to get it back in the domain you require:
for (int value = -20; value <= 20; value += 2) {
std::cout << (value / 10.f) << std::endl;
}
For me this gives:
-2
-1.8
-1.6
-1.4
-1.2
-1
-0.8
-0.6
-0.4
-0.2
0
0.2
0.4
0.6
0.8
1
1.2
1.4
1.6
1.8
2
There's no clear-cut solution for avoid floating point precision loss. I would suggest having a look through the following paper: What every computer scientist should know about floating point arithmetic.
This is because floating point numbers have only a certain discrete precision.
The 0.2 is not really a 0.2, but is internally represented as a slightly different number.
That is why you are seeing a difference.
This is common in all floating point calculations, and you really can't avoid it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With