在C++中,
我使用一个函数(搜索
nearly_equal()
)在Go中看起来像这样:
func nearlyEqual(a, b, epsilon float64) {
if(a == b) {
return true
}
diff := math.Abs(a - b)
if a == 0.0 || b == 0.0 || diff < math.SmallestNonzeroFloat64 {
return diff < epsilon * math.SmallestNonzeroFloat64
}
return diff / (math.Abs(a) + math.Abs(b)) < epsilon
}
这将计算输入 a
和 b
之间的差异,然后确保差异在给定的 epsilon 范围内。除法运算移除了量纲,使比较变得简单。
问题在于浮点数使用其尾数中定义的位数。尾数所代表的内容取决于指数。因此,如果您只是比较位,您首先需要“适当地移位”。上面的操作在最后一行完成了这个过程。除法等同于移位。
假设我们有非常大的整数,我们可以使用大约700位的定点数,其中小数点左侧有大约350位,小数点右侧有另外350位:
700 350 0
XXX ... XXXXXXX '.' XXXXXXX ... XXX
float64的尾数有56位,因此在上述数字表示中,除了那56位之外,大多数位都将是零。如果一个数字在最左边有这56位,而另一个数字在最右边也有56位,那么这两个数字非常不同,上述代码可以检测到这一点。
使用这些定点数,我们可以做更多或更少像这样的事情:
// assume "fp" numbers are fixed point numbers and the shift works on those
fp_a := a << (350 + a.exponent)
fp_b := b << (350 + b.exponent)
fp_diff := math.Abs(fp_a - fp_b)
return fp_diff < fp_epsilon
问题在于实现700位数值是不切实际的。
a == b
吗?请注意,固定大小的浮点数值很容易无法准确表示您想要表示的值,例如值0.1
或0.3
。您最好的选择可能是像大多数编程语言一样,从一个数中减去另一个数,进行ABS
操作并将其与您认为“足够接近以便于我的目的相等”的阈值进行比较。 - Lasse V. Karlsena == b
不对?请解释一下为什么这对您不是一个选项。 - Lasse V. Karlsena == b
有什么问题呢? - Lasse V. Karlsen