Enumerable#sum 如何避免浮点舍入错误?

Posted

技术标签:

【中文标题】Enumerable#sum 如何避免浮点舍入错误?【英文标题】:How does Enumerable#sum avoid floating point rounding errors? 【发布时间】:2019-12-15 02:18:42 【问题描述】:

我正在玩一些 Ruby 中浮点舍入错误的玩具示例,我注意到以下行为让我感到惊讶。

首先,一个不足为奇的例子,发生舍入误差:

numbers = Array.new(10, 0.1)
#=> [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]

numbers.inject(0, :+)
#=> 0.9999999999999999

现在用Enumerable#sum试试同样的方法:

numbers.sum
#=> 1.0

我能在文档中找到的唯一提示解释是

sum 方法可能不尊重 Integer#+ 等“+”方法的方法重定义。

所以我认为有某种本机代码实现可以加快速度,但我认为 C 浮点数也受 IEEE-754 相关的不精确算术约束。

第二个示例中的行为的原因是什么? sum 方法如何避免舍入误差?

【问题讨论】:

sum source 中的一条评论指向A Generalized Kahan-Babuška-Summation-Algorithm,这就解释了为什么sum 更准确。 这一定是答案。谢谢!试图搜索这个词,我找到了en.wikipedia.org/wiki/Kahan_summation_algorithm,它很好地解释了一般原则。 【参考方案1】:

Amadan 在comment 中给出了答案。

对于浮点值Enumerable#sum 使用一种算法,在求和过程中补偿误差的累积。

正如评论中提到的,源代码链接到 this paper,而 Wikipedia 上有一篇关于所描述算法的变体的文章,称为 Kahan Summation Algorithm。

【讨论】:

以上是关于Enumerable#sum 如何避免浮点舍入错误?的主要内容,如果未能解决你的问题,请参考以下文章

如何阻止 mysql 舍入浮点值?

如何在 extjs4.1 中舍入浮点值

如何在包含浮点数和 Nan 或 None 值的同一列中舍入浮点值?

Braintree PHP 设置数量和避免舍入错误

C是不是舍入浮点常量

vbscript MS Access VBA查询功能将CDec()应用于数字字段(有助于避免舍入错误)