浮动比较 [英] Go float comparison

查看:103
本文介绍了浮动比较的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In order to compare two floats (float64) for equality in Go, my superficial understanding of IEEE 754 and binary representation of floats makes me think that this is a good solution:

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相比,这是一种比较通用的,更精确,更有效的方式来比较两个任意大或小的浮点数以几乎相等"吗?我的推理是,如果一个二进制表示形式只允许一位差异,那么除了严格的相等性(当然,如注释中所指出的),可以使用==进行检查,因此比较的数字当然不能再相等了.用于浮法.

The question is: Is this a more generic, more precise, and more efficient, way to compare two arbitrarily large or small floats for "almost equalness", than the old abs(diff) < epsilon hack? My reasoning being that if one allows only one bit difference in the binary representation, then the compared numbers certainly could not be any more equal, apart from strict equality, which obviously (as pointed out in the comments) can be checked with == for floats.

注意:我已经对问题进行了编辑,以使其更加清楚.

Note: I have edited the question to make it more clear.

推荐答案

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

No, this is not the correct way compare floating-point values.

您实际上并没有说出真正的问题-出于某些原因,您试图比较两个浮点数,但是您没有说出它是什么.

You have not actually stated your real problem—there is some reason you are trying to compare two floating-point numbers, but you have not said what it is.

浮点算术被设计为执行近似算术.在浮点运算中会出现舍入误差,这是正常现象.当以不同方式计算值时,这些误差通常会有所不同,因此不应期望浮点运算会产生相同的结果.

Floating-point arithmetic is designed to perform approximate arithmetic. It is normal that there will be an accumulation of rounding errors in floating-point operations. These errors will generally be different when values are calculated in different ways, so floating-point arithmetic should not be expected to produce equal results.

在您的示例中,发生了以下操作:

In your example, these operations occurred:

  • 十进制数字"0.1"被转换为float64(IEEE-754 64位二进制浮点数).这样便产生了值0.1000000000000000055511151231257827021181583404541015625,它是最接近float64值0.1的值.

  • The decimal numeral "0.1" was converted to float64 (IEEE-754 64-bit binary floating-point). This produced the value 0.1000000000000000055511151231257827021181583404541015625, which is the closest float64 value to 0.1.

十进制数字"0.2"被转换为float64.这产生了0.200000000000000011102230246251565404236316680908203125,这是最接近float64值0.2的值.

The decimal numeral "0.2" was converted to float64. This produced 0.200000000000000011102230246251565404236316680908203125, which is the closest float64 value to 0.2.

这些已添加.这产生了0.3000000000000000444089209850062616169452667236328125.除了将0.1和0.2舍入到float64中最接近的值时发生的舍入误差外,这还包含一些其他舍入误差,因为不能在float64中表示确切的总和.

These were added. This produced 0.3000000000000000444089209850062616169452667236328125. In addition to the rounding errors that occurred when 0.1 and 0.2 were rounded to the nearest values in float64, this contains some additional rounding error because the exact sum cannot be represented in float64.

十进制数字"0.3"被转换为float64.这样就产生了0.299999999999999988888869769753748434595763683319091796875,这是最接近float64值0.3的值.

The decimal numeral "0.3" was converted to float64. This produced 0.299999999999999988897769753748434595763683319091796875, which is the closest float64 value to 0.3.

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

As you can see, the result of adding 0.1 and 0.2 has accumulated different rounding errors from 0.3, so they are unequal. No correct test for equality will report they are equal. And, importantly, the errors that occurred in this example are specific to this example—different sequences of floating-point operations will have different errors, and the accumulated errors are not limited to the low bits of the numbers.

有些人试图通过测试差异是否小于某个小值来进行比较.在某些应用程序中可以这样做,但是在您的应用程序中可以吗?我们不知道您要做什么,因此我们不知道会发生什么问题.允许出现小错误的测试有时会报告错误的结果,要么是误报(因为接受的是相等的数值,如果使用精确的数学计算将是不相等的),或者是误报负的(因为接受的是相等的数值,如果使用精确的数学计算将是不相等的)精确数学).以下哪个错误对您的应用程序最不利?其中之一会导致机器损坏或对人造成伤害吗?在不知不觉中,没有人能建议哪个错误的结果是可以接受的,甚至可以接受.

Some people try to compare by testing whether the difference is less than some small value. This is can be okay in some applications, but is it okay in your application? We do not know what you are trying to do, so we do not know what problems will occur. Tests that allow for a small error sometimes report incorrect results, either false positives (because they accept as equal numbers that would not be equal if computed with exact mathematics) or false negatives (because they reject equality for numbers that would be equal if computed with exact mathematics). Which of these errors is worse for your application? Will one of them cause a machine to break or a person to be harmed? Without knowing that, nobody can advise which incorrect result is acceptable, or even if either is.

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

Additionally, how large should the tolerance for error be? The total error that can occur in a calculation depends on the sequence of operations performed and the numbers involved. Some applications will have only a small final rounding error, and some applications can have massive errors. Nobody can give a recommendation about what value to use for the tolerance without knowing more about your specific sequence of operations. Also, the solution might not be to accept a tolerance in comparing numbers but to redesign your calculations to avoid error, or at least to reduce it.

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

No general solution for comparing floating-point values for "equality" exists because it is impossible for any such solution to exist.

这篇关于浮动比较的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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