不同语言的浮点精度

Floating point accuracy with different languages

我目前正在计算坐标之间的距离,根据使用的语言,我得到的结果略有不同。

计算的一部分是计算给定 radiancosine。我得到以下结果

// cos(0.8941658257446736)

// 0.6261694290123146 node
// 0.6261694290123146 rust
// 0.6261694290123148 go
// 0.6261694290123148 python
// 0.6261694290123148 swift
// 0.6261694290123146 c++
// 0.6261694290123146 java
// 0.6261694290123147 c

我想尝试了解原因。如果你看过去 16dp c 是唯一“正确”的四舍五入答案。令我惊讶的是 python 结果不同。

这个微小的差异目前正在被放大,超过 000 个位置正在增加一个不小的距离。

不太确定这是怎么重复的。此外,我更多地要求一个整体的答案,而不是特定的语言。我没有计算机科学学位。


更新

我承认这可能是一个太宽泛的问题,我想我很好奇为什么我的背景不是 CS。我很欣赏评论中发布的博客链接。


更新 2

这个问题源于将服务从 nodejs 移植到 goGo 甚至更奇怪,因为我现在无法 运行 测试,因为距离的总和随多个值而变化。

给定坐标列表并计算距离并将它们相加,我得到不同的结果。我不是在问问题,但 go 会产生不同的结果似乎很疯狂。

9605.795975874069
9605.795975874067
9605.79597587407

为完整起见,这里是我使用的距离计算:

func Distance(pointA Coordinate, pointB Coordinate) float64 {
    const R = 6371000 // Earth radius meters
    phi1 := pointA.Lat * math.Pi / 180
    phi2 := pointB.Lat * math.Pi / 180
    lambda1 := pointA.Lon * math.Pi / 180
    lambda2 := pointB.Lon * math.Pi / 180

    deltaPhi := phi2 - phi1
    deltaLambda := lambda2 - lambda1
    a := math.Sin(deltaPhi/2)*math.Sin(deltaPhi/2) + math.Cos(phi1)*math.Cos(phi2)*math.Sin(deltaLambda/2)*math.Sin(deltaLambda/2)
    c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))

    d := R * c
    return d
}

通常,浮点数的表示由标准 IEEE 754 定义,我的假设是所有(主要)编程语言都实现了该标准。

精度和舍入为known issues and may sometimes lead to unexpected results

根据编程语言或使用的数学库,可能对计算结果产生影响的方面:

IEEE-754只要求基本运算(+-*/)和sqrt正确舍入,即误差不得超过0.5ULP。像 sincosexp... 这样的超越函数非常复杂,所以它们只有 recommended to be properly rounded。不同的实现可能会使用不同的算法来计算这些函数的结果,具体取决于 space 和时间要求。因此,像您观察到的变化是完全正常的

There is no standard that requires faithful rounding of transcendental functions. IEEE-754 (2008) recommends, but does not require, that these functions be correctly rounded.

Standard for the sine of very large numbers

另见

  • Math precision requirements of C and C++ standard
  • Does any floating point-intensive code produce bit-exact results in any x86-based architecture?