Math.floor VS Math.trunc JavaScript

Fla*_*nix 17 javascript math performance

背景

我正在创建一个接收正数的函数,然后将数字四舍五入到它下面最接近的整数.

我一直在使用Math.floor,但最近我发现了Math.trunc.

我知道两者都将返回相同的值,给定一个正数,并且它们以完全不同的方式工作.我有兴趣探索这种行为.

问题

  1. 哪一个更快?
  2. 我应该使用哪一个?

Qwe*_*rty 41

实际上,还有更多的替代方法可以从数字中删除小数.但这是可读性和速度的权衡.

选择合适的产品取决于您的需求.如果您只需要删除小数,请始终使用trunc()或按位运算符.
floor(),ceil()并且round()在概念上非常不同于trunc().

数学库

你已经知道了.始终在标准的非关键代码中使用它们.

var v = 3.14;
[Math.trunc(v), Math.floor(v), Math.ceil(v), Math.round(v)]
// prints results
Run Code Online (Sandbox Code Playgroud)

对于不同的输入值,您将获得这些结果

          t   f   c   r
 3.87 : [ 3,  3,  4,  4]
 3.14 : [ 3,  3,  4,  3]
-3.14 : [-3, -4, -3, -3]
-3.87 : [-3, -4, -3, -4]
Run Code Online (Sandbox Code Playgroud)

但这更有趣:)

二进制运算和按位运算符

如果你在代码中查看它们,乍一看它们的作用可能并不明显,所以不要使用它们.虽然在某些情况下,它们可能有用.例如,计算a中的坐标<canvas/>.它们更快,但有限制.

从概念上讲,他们以这种方式工作:

  • 操作数转换为32位整数.(超过32位的数字会丢弃其最重要的位.)

按位逻辑运算符

  • 第一个操作数中的每个位与第二个操作数中的相应位配对.(第一位到第一位,第二位到第二位,依此类推.)
  • 运算符应用于每对位,结果按位构造.

按位移位运算符

  • 这些运算符采用a value移位和number位位移来移位value.

但是,在这些情况下,我们总是使用a 0,zero,a false作为第二个操作数,它对原始值没有任何作用:

~    不    ~~v

|    要么    v | 0

<<   左移    v << 0

>>   签署右移    v >> 0

>>>  零填充右移    v >>> 0

[
  0b011100110111110100000000000000110000000000001, //  15872588537857
~~0b011100110111110100000000000000110000000000001, // -1610588159
             ~~0b10100000000000000110000000000001, // -1610588159
]
Run Code Online (Sandbox Code Playgroud)

性能

https://jsperf.com/number-truncating-methods/1

在此输入图像描述

  • @JasonMitchell 这实际上是写在答案中的,但我已经突出显示了它,以防更多人像你一样错过这一点。不过还是谢谢你的提示。 (6认同)
  • 非常糟糕的主意。大数字不会按照您想象的方式进行按位运算符。尝试 (Date.now()+0.5)&gt;&gt;&gt;0。没有给你正确的答案。不要使用按位运算符来对值进行下限,除非您正在执行对性能至关重要的工作并且您知道数字始终很小。图形工作就是一个例子。 (2认同)

Arv*_*ash 23

现有的答案已经很好地解释了性能。然而,我无法理解问题或答案之间的功能差异,因此我将我的发现放在这个答案中Math.trunc。Math.floor

Math.trunc将数字向下舍入为整数0,同时Math.floor将数字向下舍入为整数-Infinity。如下面的数轴所示,正数的方向相同,负数的方向相反。

trunc: towards 0    
floor: towards -Infinity


                   -3      -2     -1      0      1      2      3
-Infinity ... ------+----|--+------+------+------+------+--|----+------ .... Infinity
                         b                                 a    
Run Code Online (Sandbox Code Playgroud)

演示:

trunc: towards 0    
floor: towards -Infinity


                   -3      -2     -1      0      1      2      3
-Infinity ... ------+----|--+------+------+------+------+--|----+------ .... Infinity
                         b                                 a    
Run Code Online (Sandbox Code Playgroud)

输出:

            2.3     -2.3
Math.trunc: 2       -2
Math.floor: 2       -3
Run Code Online (Sandbox Code Playgroud)


Kal*_*eab 6

如果参数为正数,则 Math.trunc() 等效于 Math.floor(),否则 Math.trunc() 等效于 Math.ceil()。

对于性能检查这个和最快的一个是 Math.trunc

var t0 = performance.now();
var result = Math.floor(3.5);
var t1 = performance.now();
console.log('Took', (t1 - t0).toFixed(4), 'milliseconds to generate:', result);
var t0 = performance.now();
var result = Math.trunc(3.5);
var t1 = performance.now();
console.log('Took', (t1 - t0).toFixed(4), 'milliseconds to generate:', result);
Run Code Online (Sandbox Code Playgroud)

结果是用了 0.0300 毫秒来生成:3 用了 0.0200 毫秒来生成:3

所以如果参数只是正数,你可以使用最快的一个。