问题
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!
回答1:
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.
回答2:
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
回答3:
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.
回答4:
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
回答5:
Use integers and divide down:
for(int value = -20; value <= 20; value += 2)
std::cout << (value/10.0) << std::endl;
回答6:
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. )
来源:https://stackoverflow.com/questions/14859875/c-how-to-avoid-floating-point-arithmetic-error