为什么JavaScript的Math.floor是JavaScript中计算floor最慢的方式?

29

我通常不喜欢微基准测试,但这个测试结果非常有趣。
http://ernestdelgado.com/archive/benchmark-on-the-floor/

它表明,在Javascript中计算floor时,Math.floor是最慢的。而~~nn|nn&n都更快。
这似乎很惊人,因为我期望在今天的现代浏览器中实现JavaScript的人应该是相当聪明的人。

Math.floor是否执行其他方法无法完成的重要操作?使用它是否有任何理由?


4
~~n, n|nn&n的结果与Math.floor不同。前三个只能返回32位的整数。试试将n设置为50000000000.4 - kennytm
在我的浏览器(FF 3.6某个版本),它们在结果中的速度都是相同的(大约为“3”,不管那意味着什么)。尝试在不同的浏览器上进行测试(小测试提供在底部),而不是仅仅接受表面价值的结果。实际上,没有任何理由使它明显变慢。 - user166390
4
实际上,在Firefox 3.6中运行他的基准测试表明Math.floor是最快的。 - Justin Johnson
1
它们的行为与 Math.floor 不同 - 它们与 Math.trunc 相同,对于负非整数有所不同。 - Grumdrig
1
链接无法使用,这是更新后的基准测试:https://jsperf.app/js-floors/3 - MarcellPerger
2个回答

37
主要原因是Math.floor较慢(在一些测试中它更快)是因为它涉及到函数调用。旧版JavaScript实现不能内联函数调用。更新的引擎可以内联调用,或者至少使属性查找更快,但它们仍然需要一个保护条件以防您(或其他脚本)覆盖了Math.floor函数。然而,开销很小,因此速度差异不大。 更重要的是,正如几条评论中提到的那样,其他方法并不等价。它们都通过位运算来工作。位运算符通过截断数字自动将其操作数转换为32位整数。如果数字适合32位,则没有问题,但JavaScript数字是64位浮点数,可能比2147483647大得多。 它们还会针对负数给出不同的结果,因为将其转换为整数会截断,而Math.floor总是向下舍入。例如,Math.floor(-2.1) === -3,但(-2.1)|(-2.1) === -2。 如果您知道自己只处理小于2147483648的正数,并且需要在旧版浏览器中从代码中挤出每一位性能(首先确保它确实是瓶颈。它可能不是。),我会使用更简单的方法:x|0。它不会评估两次变量,即使x是一个表达式也可以工作(只需确保将其置于括号中,以避免运算优先级问题)。

JavaScript无法内联函数,因为它是动态的,你可以用不同的函数替换Math.floor。这是一个不合逻辑的观点。JIT编译器可以并且确实会内联动态函数调用。跟踪JIT在这方面尤其擅长。动态性通过保护检查或添加失效触发器来处理。具体实现可能会或可能不会进行内联。所以像所有微观优化一样,如果它真的很重要,在目标平台上对其进行测量。 - Ants Aasma
@Ants:好观点。这就是我在缓存函数值方面考虑的,但是我的措辞不太正确。 - Matthew Crumley
6
我知道这个答案已经有几年了,但是现在V8可以内联函数调用,这导致Math.floor的性能与位运算方法一样好 - josh3736

27

这与现代浏览器无关,与实施ECMA标准有关。 即使有更快的方法,您也不能只改变某个函数的执行方式。 这可能会破坏现有的代码。

Math.Floor必须考虑处理不同类型的许多不同情况。 他们是否可以通过采取您所描述的捷径来使不同的场景更快? 也许他们可以,但那可能会破坏其他场景。 表面上看起来很小的东西,下面可能有一座冰山。


7
慢或者不慢,这很可能是唯一正确地完成它的方式。+1 - Josh Stodola
1
好的观点。Math.floor("foo") 返回 NaN。但如果这是唯一的好处,我会尝试使用另一种方法。至少在 JavaScript 支持整数除法之前是这样的。 - Mark Bolusmjak
我并不是说你应该总是使用Math.Floor,因为它很慢。只是当他们设计一个函数时,他们必须考虑到人们可能会做很多不同的情况。关于JS的一件事是,它旨在易于编程,这意味着在构建它时他们必须采取额外的预防措施,在某些情况下使它们走了远路。 - kemiller2002
@z5h - 另一个好处是Math.floor()可以正确地将负数向下舍入,而大多数位运算符则向0舍入(尽管>>>完全超出了范围)。 - Ted Hopp

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