c#和javascript中的IEEE 754浮点运算舍入错误

我刚读了一本关于javascript的书。 作者在IEEE 754标准中提到了浮点算术舍入误差。

例如,添加0.1和0.2会产生0.30000000000000004而不是0.3。

所以(0.1 + 0.2) == 0.3返回false。

我也在c#中重现了这个错误。

所以这些是我的问题是:

发生这种错误的频率如何? 什么是C#和JavaScript中的最佳实践解决方法? 哪些其他语言有相同的错误?


这不是语言错误。 这在IEEE 754中并不是错误的。这是对二进制浮点数的期望和使用的错误。 一旦你理解了二进制浮点数的真正含义,它就非常合理。

在C#中的最佳实践是使用System.Decimal (又称decimal ),它是一种十进制浮点类型,无论何时处理的数量自然都是以小数表示 - 通常是货币值。

有关.NET二进制浮点数和十进制浮点数的更多信息,请参阅我的文章。


这个错误不是一个舍入误差,只是有些值不能完全由IEEE 754标准表示。 请参阅Jon Skeet有关.net中二进制浮点数的文章以供进一步阅读。

为了处理像你的例子(base-10)这样的数字,你应该在C#中使用decimal数据类型,因为它可以精确地表示这些数字,所以你可以得到你所期望的值。

一个典型的方法是定义一些epsilon值,并检查结果是否在targetvalue + - epsilon:

double const epsilon = 0.000001; // or whatever

if(valueA >= valueB - epsilon && valueA <= valueB + epsilon)
{
    // treat as valueA = valueB
}

这三个数字在双精度浮点上的最接近的表示是:

  • 0.1 - > 0.10000000000000001 = D(3FB99999 9999999A)
  • 0.2 - > 0.20000000000000001 = D(3FC99999 9999999A)
  • 0.3 - > 0.29999999999999999 = D(3FD33333 33333333)
  • 下一个大于0.29999999999999999的可表示数字是:

  • 0.30000000000000004 = D(3FD33333 33333334)
  • 最接近的表示

  • 0.10000000000000001 + 0.20000000000000001是0.30000000000000004
  • 所以你比较0.29999999999999999和0.30000000000000004。 这是否能让你更深入地了解正在发生的事情?

    就使用小数而不是二进制表示而言,这也不起作用。 举例来说,有三分之一:

  • 1/3 = 0.3333333333333333333333333333333 ...
  • 即使使用十进制数字也没有确切的表示。 任何计算都应考虑到表示错误。

    链接地址: http://www.djcxy.com/p/27499.html

    上一篇: IEEE 754 floating point arithmetic rounding error in c# and javascript

    下一篇: Sum of 3 variables: strange behavior