为什么Javascript';s Math.floor在Javascript中计算floor的最慢方法是什么?

为什么Javascript';s Math.floor在Javascript中计算floor的最慢方法是什么?,javascript,optimization,Javascript,Optimization,我一般不喜欢微基准。但是这个有一个非常有趣的结果。 这表明Math.floor是Javascript中计算floor的最慢方法~~n,n | n,n&n都快了。 这似乎相当令人震惊,因为我预计在今天的现代浏览器中实现Javascript的人将是一些非常聪明的人 地板是否做了其他方法做不到的重要事情?有什么理由使用它吗?它与现代浏览器无关。它与实施ECMA标准有关。即使有更快的方法,也不能仅仅改变某个函数的执行方式。它可能会破坏现有的代码 数学地板必须考虑处理不同类型数据的许多不同场景。他们能像

我一般不喜欢微基准。但是这个有一个非常有趣的结果。


这表明
Math.floor
是Javascript中计算floor的最慢方法<代码>~~n,
n | n
n&n
都快了。
这似乎相当令人震惊,因为我预计在今天的现代浏览器中实现Javascript的人将是一些非常聪明的人


地板是否做了其他方法做不到的重要事情?有什么理由使用它吗?

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


数学地板必须考虑处理不同类型数据的许多不同场景。他们能像你描述的那样走捷径,让不同的场景变得更快吗?也许他们可以,但这可能打破了其他的局面。仅仅因为表面上的东西看起来很小,并不意味着下面没有冰山。

主要原因是
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
是一个表达式,它也会工作(请确保将它放在括号中,以免遇到优先级问题)。

+1无论是否慢,它可能是唯一正确执行它的方法
Math.floor(“foo”)
返回
NaN
。但如果这是唯一的好处,我会尝试使用另一种方法。至少在Javascript支持整数除法之前,我并不是说你应该一直使用Math.Floor,它很慢。只是当他们设计一个函数时,他们必须考虑到人们可能会做的许多不同的场景。JS的一个优点是易于编程,这意味着他们在构建JS时必须采取额外的预防措施,在某些情况下,这会让他们走很长的路。@z5h-另一个好处是
Math.floor()
正确地向下舍入负数,而大多数位运算符向0舍入(虽然
>>
完全偏离了图表)。
~~n
n | n
n&n
不会产生与
Math.floor
相同的结果。前三个只能返回32位整数。请尝试
n=50000000000.4
。在我的浏览器(FF 3.6.something)中,它们的结果速度都相同(大约为“3”在不同的浏览器上试用(底部提供了一个小测试)事实上,在FF 3.6中运行他的基准测试表明,
Math.floor
是最快的。它们的行为与
Math.floor
不一样-它们与
Math.trunc
相同,这与负非inte不同JavaScript不能内联函数,因为它是动态的,您可以用不同的函数替换Math.floor这是一个非序列。JIT编译器可以并执行内联动态函数调用。跟踪JIT在这方面尤其擅长。动态性可以通过保护检查或添加无效触发器来处理。特定的实现可能是内联的,也可能不是内联的。因此,与所有微优化一样,如果确实重要,请在目标平台上测量它orms@Ants:这一点很好。这就是我对缓存函数值的理解,但我的措辞不正确。我知道这个答案已经有几年了,但是V8现在内联函数调用,这导致了。太棒了@josh3736!谢谢你的链接。+1