浮点精度问题简析

Why don’t my numbers add up?

为什么我的数加起来对不上?

So you’ve written some absurdly simple code, say for example:

你写了一段极其简单的代码,比如:

    0.1 + 0.2

and got a really unexpected result:

然后得到了一个意想不到的结果:

    0.30000000000000004

Why don’t my numbers, like 0.1 + 0.2 add up to a nice round 0.3, and instead I get a weird result like 0.30000000000000004?

为什么0.1 + 0.2不等于0.3,而是等于上面这一大串儿奇怪的数字呢?

Because internally, computers use a format (binary floating-point) that cannot accurately represent a number like 0.1, 0.2 or 0.3 at all.

因为在内部,计算机使用一种非精确的(二进制浮点数)形式表示诸如0.1, 0.2, 0.3之类的小数。

When the code is compiled or interpreted, your “0.1” is already rounded to the nearest number in that format, which results in a small rounding error even before the calculation happens.

当代码被编译或者解释运行时,“0.1”已经被近似转化为这种形式下最接近的一个浮点数,这导致在计算还没有真正开始之前,一个微小的舍入误差就已经存在了。

Why do computers use such a stupid system?

为什么计算机要使用一个这么愚蠢的系统?

It’s not stupid, just different. Decimal numbers cannot accurately represent a number like 1/3, so you have to round to something like 0.33 - and you don’t expect 0.33 + 0.33 + 0.33 to add up to 1, either - do you?

这其实一点也不蠢,只是有所不同而已。十进制数无法精确地表示诸如1/3的数字,因而必须将其近似为0.33之类的数,你也不会期望0.33 + 0.33 + 0.33等于1,对吧?

Computers use binary numbers because they’re faster at dealing with those, and because for most calculations, a tiny error in the 17th decimal place doesn’t matter at all since the numbers you work with aren’t round (or that precise) anyway.

计算机之所以使用二进制数,是因为它们处理这些数字时速度更快,并且对于大部分运算,一个在小数点后第17位出现的微小误差并不会造成任何影响,因为你并不需要这么高的精度。

What can I do to avoid this problem?

我应该怎么做才能避免这个问题?

That depends on what kind of calculations you’re doing.

这取决于你在做什么类型的运算。

If you really need your results to add up exactly, especially when you work with money: use a special decimal datatype.

如果你需要结果非常的精确,尤其是在处理金钱相关的工作时,使用一个特制的小数数据类型。

If you just don’t want to see all those extra decimal places: simply format your result rounded to a fixed number of decimal places when displaying it.

如果你只是不想看到那些额外的小数位数:只需要在显示的时候将结果舍入到一个固定的位数即可。

If you have no decimal datatype available, an alternative is to work with integers, e.g. do money calculations entirely in cents. But this is more work and has some drawbacks.

如果你没有合适的小数数据类型可用,一个替代的方案是使用整数。比如,在计算钱数时把单位转化为分。但这样的工作量更大,并且会有一些缺陷。

Why do other calculations like 0.1 + 0.4 work correctly?

为什么有的运算,比如0.1 + 0.4得到的结果是正确的?

In that case, the result (0.5) can be represented exactly as a floating-point number, and it’s possible for rounding errors in the input numbers to cancel each other out - But that can’t necessarily be relied upon (e.g. when those two numbers were stored in differently sized floating point representations first, the rounding errors might not offset each other).

在这个例子中,结果(0.5)可以使用浮点数精确表示,并且参与运算的输入数字的舍入误差有可能会彼此抵消——但你不能指望这一定会发生(比如,当两个数字使用不同长度的浮点数存储时,舍入误差并不会彼此影响)

In other cases like 0.1 + 0.3, the result actually isn’t really 0.4, but close enough that 0.4 is the shortest number that is closer to the result than to any other floating-point number. Many languages then display that number instead of converting the actual result back to the closest decimal fraction.

另一个例子0.1 + 0.3, 结果实际上并不是真的等于0.4, 而是因为0.4是与结果最为接近并且长度最短的一个浮点数。许多语言会直接显示这个数字,而不将真实结果转换回最接近的十进制小数。

原文链接:http://floating-point-gui.de/basic/

本文链接:http://bookshadow.com/weblog/2015/06/24/floating-point-guide-basic-answer/
请尊重作者的劳动成果,转载请注明出处!书影博客保留对文章的所有权利。

如果您喜欢这篇博文,欢迎您捐赠书影博客: ,查看支付宝二维码

Pingbacks已关闭。

暂无评论

张贴您的评论