简体   繁体   中英

C++ How to avoid floating-point arithmetic error

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!

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

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.

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 .

Let's do your loop, but with increased output precision.

code:

for(float value = -2.0; value <= 2.0; value += 0.2)
    std::cout << std::setprecision(100) << value << std::endl;

output:

-2
-1.7999999523162841796875
-1.599999904632568359375
-1.3999998569488525390625
-1.19999980926513671875
-0.999999821186065673828125
-0.79999983310699462890625
-0.599999845027923583984375
-0.3999998569488525390625
-0.19999985396862030029296875
1.460313825418779742904007434844970703125e-07
0.20000015199184417724609375
0.400000154972076416015625
0.6000001430511474609375
0.800000131130218505859375
1.00000011920928955078125
1.20000016689300537109375
1.40000021457672119140625
1.60000026226043701171875
1.80000030994415283203125

Use integers and divide down:

for(int value = -20; value <= 20; value += 2)
    std::cout << (value/10.0) << std::endl;

Learn about floating point representation with some Algorithms book or using internet. There are lots of resources out there.

For the time, what you want seems to be some way to get zero when its something very very close to zero. and we all know that we call this process "rounding". :) so why don't you use it while printing those numbers. printf function provides good formatting power for these kinds of things. check the tables in the following link if you dont know how to format with printf. ( you can use the formating for rounding and displaying the numbers correctly ) printf ref : http://www.cplusplus.com/reference/cstdio/printf/?kw=printf

-- edit --

maybe some of you know know that according to mathematics 1.99999999.... is the same as 2.0 . Only difference is the representation. But the number is the same.

your floating point problem is a little bit similar to this. ( this is just for your clarification only. your problem is not the same as the 1.9999.... thing. )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM