去 float 比较

标签 go floating-point ieee-754

为了在 Go 中比较两个 float (float64) 是否相等,我对 IEEE 754 和 float 二进制表示的肤浅理解让我认为这是一个很好的解决方案:

func Equal(a, b float64) bool {
    ba := math.Float64bits(a)
    bb := math.Float64bits(b)
    diff := ba - bb
    if diff < 0 {
        diff = -diff
    }
    // accept one bit difference
    return diff < 2
}

问题是:与旧的 abs(diff) < epsilon 相比,这是一种更通用、更精确、更有效的比较两个任意大或小的 float “几乎相等”的方法吗?破解?我的理由是,如果在二进制表示中只允许一位差异,那么除了严格相等之外,比较的数字肯定不能再相等了,这显然(如评论中指出的那样)可以用 == 检查。用于花车。

注意:我已经编辑了问题以使其更清楚。

最佳答案

不,这不是比较浮点值的正确方法。

您实际上并没有说明您的真正问题——您尝试比较两个 float 是出于某种原因,但您没有说出它是什么。

浮点运算旨在执行近似运算。浮点运算会有舍入误差的累积是正常的。当以不同方式计算值时,这些误差通常会有所不同,因此不应期望浮点运算产生相同的结果。

在您的示例中,发生了这些操作:

  • 十进制数字“0.1”已转换为 float64(IEEE-754 64 位二进制 float )。这产生了值 0.10000000000000000055511151231257827021181583404541015625,这是最接近 0.1 的 float64 值。

  • 十进制数字“0.2”被转换为float64。这产生了 0.200000000000000011102230246251565404236316680908203125,这是最接近 0.2 的 float64 值。

  • 这些已添加。这产生了 0.3000000000000000444089209850062616169452667236328125。除了在 float64 中将 0.1 和 0.2 舍入到最接近的值时发生的舍入误差外,这还包含一些额外的舍入误差,因为在 float64 中无法表示精确的总和.

  • 十进制数字“0.3”已转换为 float64。这产生了 0.299999999999999988897769753748434595763683319091796875,这是最接近 0.3 的 float64 值。

如您所见,0.10.2相加的结果累积了与0.3不同的舍入误差,因此它们是不相等的。没有正确的相等性测试会报告它们相等。而且,重要的是,这个例子中发生的错误是特定于这个例子的——不同的浮点运算序列会产生不同的错误,并且累积的错误不限于数字的低位 .

有些人尝试通过测试差异是否小于某个小值来进行比较。这在某些应用程序中可能没问题,但在您的应用程序中可以吗?我们不知道您要做什么,所以我们不知道会出现什么问题。允许小错误的测试有时会报告不正确的结果,要么是误报(因为它们接受相等的数字,如果用精确的数学计算则不相等)或假阴性(因为它们拒绝相等的数字,如果用精确的数学)。这些错误中的哪一个对您的应用程序来说更糟糕?其中之一会导致机器损坏或人身伤害吗?在不知道这一点的情况下,没有人可以建议哪个不正确的结果是可以接受的,或者即使其中一个是可以接受的。

此外,错误的容忍度应该有多大?计算中可能出现的总误差取决于执行的操作顺序和涉及的数字。一些应用程序只会有一个小的最终舍入误差,而一些应用程序可能会有很大的误差。在不了解您的特定操作顺序的情况下,没有人可以就公差使用什么值提出建议。此外,解决方案可能不是在比较数字时接受容差,而是重新设计您的计算以避免错误,或至少减少错误。

不存在用于比较浮点值是否“相等”的通用解决方案,因为任何此类解决方案都不可能存在。

关于去 float 比较,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47969385/

相关文章:

firebase - 在 Golang 中仅使用环境变量初始化 Firebase Admin SDK

Android、Golang 和 SSL

floating-point - 在 Cortex M0 上,浮点比较与整数比较的开销有多大?

floating-point - 为什么无穷大 × 0 = NaN?

json - 解码嵌套的 JSON 对象

c - float 数组中的指针

sql - 如何在sqlite中使用 float ?

Java/C : OpenJDK native tanh() implementation wrong?

floating-point - MIPS:除法算法(IEEE-754 格式的有效数除法)对最后 4-5 位 (LSB) 给出了错误的答案

unit-testing - 如何使用结构/接口(interface)来模拟依赖项以进行测试