【问题标题】:Check if two objects are equal when they have floating point values?检查两个具有浮点值的对象是否相等?
【发布时间】:2016-11-14 00:58:01
【问题描述】:

为我的 Javascript 程序编写一些处理二进制的测试用例,现在我只是使用 stringify 来检查值和预期值是否相等:

JSON.stringify(val) === JSON.stringify(expected)

这很好用,除非我有浮点值。这就是发生的事情:

Given Value:    [10,20,30,32.400001525878906,{"test":3,"asdf":23}]
Expected Value: [10,20,30,32.4,{"test":3,"asdf":23}]

Test Failed!

所以我想我不能再使用 stringify 来检查我的两个对象/数组是否相等。检查两个可能深度嵌套的对象/数组是否相等同时还考虑浮点值的好方法是什么?也就是说,如果两个浮点值 99.99% 相同或其他情况,则应认为它们相等。

【问题讨论】:

  • 你需要写一个递归等价测试器。当它得到一个浮点数时,它需要将它们与容差进行比较,而不是==
  • 使用 JSON.stringify 比较对象不是一个好主意,因为不能保证顺序,所以两个对象可能具有相同的属性和值,但评估结果不“相等”。你需要遍历属性和值,有many, many questions about that already

标签: javascript binary floating-point equality


【解决方案1】:

您需要按顺序测试数组中的每个元素,并且您需要对对象进行递归测试。这通常称为深度比较或深度相等。您应该能够使用检查比较数类型的递归函数来执行此操作。

比较浮点值时,您需要使用容差。为此,您可以取两个数字相减的绝对值,然后将其与您选择的固定容差值或称为 epsilon 的小数字进行比较。

在 JavaScript 中,机器 epsilon 可用 Number.EPSILON,定义为 1 与大于 1 的最小数字之间的差 并且 可以表示为 Number .大多数语言中都有类似的常量,通常用于基于容差的比较。

基于容差的比较将浮点比较从简单的相等转换为减法和比较。如果你平时写

if (a === b) { ... }

您可以使用绝对值和tolerance 来消除浮点怪异:

var tolerance = Number.EPSILON;
if (Math.abs(a - b) < tolerance) { ... }

如果ab 之间的差异小于tolerance,则将它们视为相等。

有关更细致入微(但可能对您的情况而言可能过于矫枉过正)的方法,请参阅The Floating Point Guide's section on comparison。那里提供的实现是用 Java 编写的,但很可能无需太多努力就可以移植到 JavaScript。

【讨论】:

  • 我认为 Number.EPSILON 有点太小了,无法使用。我认为它应该根据实际数字(或它们的差异)按比例缩放。因此,相当大的数字与 1.0 的 ulp 相比差异不大
  • 是的,我在这里尝试过,但不一定成功。 :) 接受有关如何更好地表达答案的建议。
猜你喜欢
  • 2019-11-04
  • 1970-01-01
  • 1970-01-01
  • 2016-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多