性能:toFixed() vs. Math.floor(x * 10000)

4
我需要将两个浮点数值进行比较,精确到4位小数:
var float1 = 0.0025132741228718345;
var float2 = 0.0025132812393818293;

我看到的两个选项是:
Math.floor(float1 * 10000) === Math.floor(float2 * 10000); // 25 === 25

...或者:

float1.toFixed(4) === float2.toFixed(4) // "0.0025" === "0.0025"

由于操作将每秒发生60次,我自问:

  1. 哪个选项具有更高的性能?
  2. 其中一个选项是否更广泛接受?
  3. 是否存在第三种选择?

5
第三种选项是abs(float1 - float2)<0.00001。这被广泛接受。 - Alex
3个回答

6
function floor(f1, f2) {
    return Math.floor(f1 * 10000) === Math.floor(f2 * 10000);
}
function toFixed(f1, f2) {
    return f1.toFixed(4) === f2.toFixed(4);
}
function subtract(f1, f2) {
    return Math.abs(f1 - f2) < 0.00001;
}
function test(fn) {
     console.time(fn.name);
     for (let i = 0; i < 1000000; ++i) {
         fn(Math.random(), Math.random());
     }
     console.timeEnd(fn.name);
}
for (const fn of [floor, toFixed, subtract]) {
    test(fn);
}

引擎基准测试

v8 (基于Chromium的浏览器)

  • floor: 204.911 毫秒
  • toFixed: 4145.529 毫秒
  • subtract: 292.390 毫秒

SpiderMonkey (基于Firefox的浏览器)

  • floor: 566.81 毫秒
  • toFixed: 683.56 毫秒
  • subtract: 423.76 毫秒

在你给出的两个选项中,Math.floor方法是更快的。

尽管如此,选择subtract可能会是一个明智的选择。

(如果你不相信我,请自己运行这个基准测试。)


非常感谢!为什么选择“substract”可能是一个明智的选择? - kraftwer1
1
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Chiru
1
@kraftwer1,使用floor函数后,0.00250等于0.00259,但不等于0.00249,尽管0.00249更接近0.00250。这就是为什么您应该使用epsilon comparison(在此答案中被称为“subtract”)的原因。 - Alex
1
(另一个常用的研究名称是“模糊相等”) - Chiru
我也更喜欢使用 subtract()。它基于两个数字之间的距离。而其他方法则将数字分成类别。因此,对于非常接近的数字(例如差值为1e-10),结果可能是FALSE,但差值为1e-6时则为TRUE。 - Wiimm

4

1
Math.round(142.89 * 100) / 100 // 142.89
Math.floor(142.89 * 100) / 100 // 142.88

似乎toFixed基于round函数,因此最好使用round函数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接