不同编程语言中的浮点数学 [英] Floating point math in different programming languages

查看:24
本文介绍了不同编程语言中的浮点数学的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道浮点数学充其量是丑陋的,但我想知道是否有人可以解释以下怪癖.在我测试的大多数编程语言中,将 0.4 添加到 0.2 会产生轻微的错误,而 0.4 + 0.1 + 0.1 会产生非.

I know that floating point math can be ugly at best but I am wondering if somebody can explain the following quirk. In most of the programing languages I tested the addition of 0.4 to 0.2 gave a slight error, where as 0.4 + 0.1 + 0.1 gave non.

计算不等的原因是什么,在各自的编程语言中可以采取什么措施来获得正确的结果.

What is the reason for the inequality of both calculation and what measures can one undertake in the respective programing languages to obtain correct results.

在python2/3中

In python2/3

.4 + .2
0.6000000000000001
.4 + .1 + .1
0.6

同样的情况发生在 Julia 0.3

The same happens in Julia 0.3

julia> .4 + .2
0.6000000000000001

julia> .4 + .1 + .1
0.6

和斯卡拉:

scala> 0.4 + 0.2
res0: Double = 0.6000000000000001

scala> 0.4 + 0.1 + 0.1
res1: Double = 0.6

和 Haskell:

Prelude> 0.4 + 0.2
0.6000000000000001    
Prelude> 0.4 + 0.1 + 0.1
0.6

但 R v3 做对了:

but R v3 gets it right:

> .4 + .2
[1] 0.6
> .4 + .1 + .1
[1] 0.6

推荐答案

所有这些语言都使用系统提供的浮点格式,它以二进制而不是十进制表示值.0.20.4 之类的值无法以该格式准确表示,因此会存储最接近的可表示值,从而导致小错误.例如,数字文字 0.2 产生一个浮点数,其准确值为 0.200000000000000011102230246251565404236316680908203125.类似地,对浮点数的任何给定算术运算都可能导致无法准确表示的值,因此真正的数学结果会替换为最接近的可表示值.这些是您所看到的错误的根本原因.

All these languages are using the system-provided floating-point format, which represents values in binary rather than in decimal. Values like 0.2 and 0.4 can't be represented exactly in that format, so instead the closest representable value is stored, resulting in a small error. For example, the numeric literal 0.2 results in a floating-point number whose exact value is 0.200000000000000011102230246251565404236316680908203125. Similarly, any given arithmetic operation on floating-point numbers may result in a value that's not exactly representable, so the true mathematical result is replaced with the closest representable value. These are the fundamental reasons for the errors you're seeing.

然而,这并不能解释语言之间的差异:在您的所有示例中,都在进行完全相同的计算并得出完全相同的结果.不同之处在于各种语言选择显示结果的方式.

However, this doesn't explain the differences between languages: in all of your examples, the exact same computations are being made and the exact same results are being arrived at. The difference then lies in the way that the various languages choose to display the results.

严格来说,您显示的答案没有是正确的.使用舍入到最近舍入模式对 IEEE 754 二进制 64 算术进行(相当安全的)假设,第一个和的确切值是:

Strictly speaking, none of the answers you show is correct. Making the (fairly safe) assumption of IEEE 754 binary 64 arithmetic with a round-to-nearest rounding mode, the exact value of the first sum is:

0.600000000000000088817841970012523233890533447265625

而第二个和的确切值是:

while the exact value of the second sum is:

0.59999999999999997779553950749686919152736663818359375

然而,这些输出都不是特别用户友好,而且很明显,您测试的所有语言都做出了在打印时缩写输出的明智决定.但是,它们并非都采用相同的输出格式设置策略,这就是您看到差异的原因.

However, neither of those outputs is particularly user-friendly, and clearly all of the languages you tested made the sensible decision to abbreviate the output when printing. However, they don't all adopt the same strategy for formatting the output, which is why you're seeing differences.

有许多可能的格式化策略,但三种特别常见的策略是:

There are many possible strategies for formatting, but three particularly common ones are:

  1. 计算并显示 17 个正确舍入的有效数字,可能会在它们出现的地方去除尾随零.17 位的输出保证了不同的 binary64 浮点数将有不同的表示,因此可以从其表示中明确地恢复浮点值;17 是具有此属性的最小整数.例如,这是 Python 2.6 使用的策略.

  1. Compute and display 17 correctly-rounded significant digits, possibly stripping trailing zeros where they appear. The output of 17 digits guarantees that distinct binary64 floats will have distinct representations, so that a floating-point value can be unambiguously recovered from its representation; 17 is the smallest integer with this property. This is the strategy that Python 2.6 uses, for example.

计算并显示在通常的舍入到偶数舍入模式下舍入到给定 binary64 值的最短十进制字符串.这比策略 1 实现起来要复杂得多,但保留了不同浮点数具有不同表示的特性,并且往往会产生更愉快的输出.这似乎是您测试的所有语言(除 R 外)都在使用的策略.

Compute and display the shortest decimal string that rounds back to the given binary64 value under the usual round-ties-to-even rounding mode. This is rather more complicated to implement than strategy 1, but preserves the property that distinct floats have distinct representations, and tends to make for pleasanter output. This appears to be the strategy that all of the languages you tested (besides R) are using.

计算并显示 15 个(或更少)正确舍入的有效数字.这具有隐藏十进制到二进制转换中涉及的错误的效果,给人一种精确十进制算术的错觉.它的缺点是不同的浮点数可以具有相同的表示.这似乎是 R 正在做的事情.(感谢@hadley 在评论中指出有一个 R 设置 控制用于显示的位数;默认使用 7 位有效数字.)

Compute and display 15 (or fewer) correctly-rounded significant digits. This has the effect of hiding the errors involved in the decimal-to-binary conversions, giving the illusion of exact decimal arithmetic. It has the drawback that distinct floats can have the same representation. This appears to be what R is doing. (Thanks to @hadley for pointing out in the comments that there's an R setting which controls the number of digits used for display; the default is to use 7 significant digits.)

这篇关于不同编程语言中的浮点数学的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆