Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ How to avoid floating-point arithmetic error [duplicate]

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!

like image 629
Barney Avatar asked Feb 13 '13 17:02

Barney


People also ask

How can you prevent arithmetic floating?

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.

Is floating-point arithmetic calculations prone for errors?

(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.

Why is floating-point arithmetic inaccurate?

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.


3 Answers

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 ints 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
like image 166
Joseph Mansfield Avatar answered Sep 20 '22 09:09

Joseph Mansfield


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.

like image 24
bstamour Avatar answered Sep 23 '22 09:09

bstamour


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.

like image 23
Srikant Krishna Avatar answered Sep 21 '22 09:09

Srikant Krishna