在前端测试时,Chai 是一个非常流行的断言库。但在处理浮点数比较时,会经常遇到误差问题。这篇文章将介绍这些问题的原因,以及如何避免它们,使 Chai 在处理浮点数比较时更加准确可靠。
浮点数比较问题的原因
JavaScript 中的浮点数类型采用 IEEE 754 标准的双精度格式。虽然这种格式支持表示非常大和非常小的数字,但它在存储小数时会产生舍入误差。
例如:
0.1 + 0.2 // 0.30000000000000004
这个问题由于浮点数采用二进制表示,而在二进制中很难准确表示某些十进制小数产生的误差导致。而在进行比较时,这种误差可能会导致测试失败。
Chai 中的大部分比较方法都是使用 JavaScript ==
和 ===
操作符来实现的。再次看到刚才的示例:
expect(0.1 + 0.2).to.equal(0.3); // AssertionError: expected 0.30000000000000004 to equal 0.3
这个测试失败了,尽管我们期望的结果是 0.3。
解决浮点数比较问题
为了解决这个问题,我们需要在进行比较之前,使用一些方式来规避这些舍入误差的可能性。下面是一些解决浮点数比较的方法。
方法一:四舍五入
四舍五入是最常用的方法之一。通过保留所需小数位数,再对其进行四舍五入处理,可以使两个数在比较时更加准确。
function round(number, precision) { const factor = Math.pow(10, precision); return Math.round(number * factor) / factor; } expect(round(0.1 + 0.2, 1)).to.equal(0.3); // success
round
函数将输入的数字乘以指定的精度,再使用 Math.round
对结果进行四舍五入。则在四舍五入不同的时候,将舍入方向考虑在内的处理方法便能降低原始数字带来的误差。
这种方法同样也适合于其他数字的处理,而精度的参数也能根据应用情况来自由设定。
方法二:比较相对误差
如果两个数相差很小,则可以通过比较它们之间的相对误差来比较它们。相对误差是两个数之间的差与这两个数的平均值之比。
function approximatelyEqual(actual, expected, relativeErrorMargin = 1e-9) { const diff = Math.abs(actual - expected); const average = (Math.abs(actual) + Math.abs(expected)) / 2; return diff <= average * relativeErrorMargin; } expect(approximatelyEqual(0.1 + 0.2, 0.3)).to.be.true; // success
approximatelyEqual
函数接受两个数字以及相对误差的参数,并将它们之间的差与它们的平均值进行比较。如果它们之间的相对误差小于相对误差的阈值,函数将返回 true
。
无论数字的精度如何高,如果这些数字真正接近,则若使用某个固定数字来初始化误差值,可以获得更好的准确性。
方法三:使用 Chai 的数值比较插件
Chai 有一个插件,叫 chai-numeric
,它包含一些方法,可以在比较浮点数时使用相对误差或绝对误差来处理舍入误差的问题。
const chai = require('chai'); const chaiNumeric = require('chai-numeric'); chai.use(chaiNumeric); expect(0.1 + 0.2).to.equal(0.3); // AssertionError: expected 0.30000000000000004 to equal 0.3 expect(0.1 + 0.2).to.equal(0.3, 1e-9); // success
上面的代码通过 chaiNumeric
插件安装了一些新的 “数值比较” 方法。它们在 equalTo、above、below 之类的 Chai 断言中添加了误差值的参数。
与我们手动编写的其他方法相比,这些方法更加简洁易用。
结论
在测试前端应用程序时,浮点数比较的问题是非常常见的。通过了解这些问题的原因以及采用特定的处理方法,我们可以避免这些问题。使用以上提到的这些方法,我们可以更加准确地测试前端应用程序,并提高测试的可靠性,避免追日误差从而浪费开发时间。
——End——
【代码示例】:
-- -------------------- ---- ------- ----- ------ - ----------------------- -------------- ------- ------- -------- -- - ---------- --- -------- -- - -------- ------------- ---------- - ----- ------ - ------------ ----------- ------ ----------------- - ------- - ------- - ---------------- - ---- ------------------ --------------------- -------------------- --------------------- -------------------- ------------------- ----------------- --- ---------- --- -------- -- - -------- -------------------------- --------- ------------------- - ----- - ----- ---- - --------------- - ---------- ----- ------- - ----------------- - ------------------- - -- ------ ---- -- ------- - -------------------- - ----------------------------- - ---- ----------------- ---------------------------------- -- --------------------- ---------------------------------- -- ------------------- -------------------------------- --- ------------------ --- ---------- --- -------- -- - ----- ---- - ---------------- ----------- - ------------------------ ---------------------- ---------- - ------------------ ------ ---------------------------- --------- --------------------------- ------- -------------------------- ----- --- ---
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/66f5346fc5c563ced5707b17