【问题标题】:Math.floor VS Math.trunc JavaScriptMath.floor VS Math.trunc JavaScript
【发布时间】:2016-12-06 18:18:20
【问题描述】:

背景

我正在制作一个函数,它接收一个正数,然后将该数字四舍五入到它下面最接近的整数。

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

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

问题

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

【问题讨论】:

  • 它们不是一回事,速度无关紧要,它确实取决于浏览器:查看您提供的链接的浏览器兼容性表。
  • 所有浏览器都支持它,我知道这一点。我只是想知道使用每一个有多大影响。这就是我创建这个问题的原因,但社区似乎不喜欢它:S
  • 如果“它”是指Math.trunc,那你就错了。 Math.trunc 非常新,并非所有浏览器都支持。
  • @Xufox:你是对的。我从我的评估中丢弃了 IE,但我又一次不在乎它,我也不认为任何人在他们的完美意义上会:p
  • 我做了一个快速的性能测试,在我的电脑上每次操作的差异大约是0.00001毫秒。换句话说,这种差异几乎总是毫无意义。

标签: javascript performance math


【解决方案1】:

如果参数是正数,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);

结果是 生成耗时 0.0300 毫秒:3 生成耗时 0.0200 毫秒:3

因此,如果参数只是正数,您可以使用最快的。

【讨论】:

  • @StevenHansen 看起来对我来说是一个有趣的挑战!你会说多少是一个合理的价值?百万?也许是 2 个?
  • 这里的基准测试只会使答案复杂化,而答案本身非常简单。
  • 绝对应该是这个问题的选择答案!
【解决方案2】:

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

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

数学库

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

var v = 3.14; [Math.trunc(v), Math.round(v), Math.floor(v), Math.ceil(v)]
// prints results

对于不同的输入值,您会得到这些结果

 v        t   r   f   c
 3.87 : [ 3,  4,  3,  4]
 3.14 : [ 3,  3,  3,  4]
-3.14 : [-3, -3, -4, -3]
-3.87 : [-3, -4, -4, -3]

Math.trunc() 删去 (截断)小数位。
Math.round() 四舍五入最近的 strong> 整数。
Math.floor() 四舍五入向最接近的较低整数。 3.5 -> 3-3.5 -> -4
Math.ceil()四舍五入向最接近的更高整数。 3.5 -> 4-3.5 -> -3


但这更有趣:)

二元运算和bitwise operators

如果您在代码中查看它们,乍一看它们的作用可能并不明显,因此不要在普通代码中使用它们。尽管在某些情况下,它们可能很有用。例如计算<canvas/> 中的坐标。它们速度更快,但也有局限性。

从概念上讲,它们是这样工作的:

  • 操作数被转换为 32 位有符号整数,因此会丢失所有小数。

注意:
超过 32 位的数字得到它们的最高有效(最左边)位discarded,最左边的位成为新的符号位。

[
  0b011100110111110100000000000000110000000000001, //  15872588537857
~~0b011100110111110100000000000000110000000000001, // -1610588159
             ~~0b10100000000000000110000000000001, // -1610588159
]

位逻辑运算符

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

位移运算符

  • 这些运算符采用要移位的value 和位位置的numbervalue 移位。

截断

但是,在截断时,我们总是使用0、零、false 作为第二个操作数,这对原始值没有任何作用,除了转换为整数,在这些情况下:

~    不是    ~~v

|    或    v | 0

<<   左班    v << 0

>>  签名右移    v >> 0

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

var v = 3.78;
[ ~~v ,  v | 0 ,  v << 0 ,  v >> 0 ,  v >>> 0 ]
// prints these results

 3.78 : [ 3,  3,  3,  3, 3]
 3.14 : [ 3,  3,  3,  3, 3]
-3.74 : [-3, -3, -3, -3, 4294967293]
-3.14 : [-3, -3, -3, -3, 4294967293]

性能

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

【讨论】:

  • 非常糟糕的主意。大数不会像您想象的那样通过位运算符。试试 (Date.now()+0.5)>>>0。没有给你正确的答案。不要使用按位运算符来计算值,除非您正在执行对性能至关重要的工作并且您知道数字总是很小。图形作品就是一个例子。
  • @JasonMitchell 这实际上是写在答案中的,但我已经强调了它,以防更多人像你一样错过它。不过感谢您的提示。
【解决方案3】:

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

Math.trunc0 向下舍入为整数,而Math.floor-Infinity 向下舍入为整数。如以下数轴所示,正数方向相同,负数方向相反。

trunc: towards 0    
floor: towards -Infinity


                   -3      -2     -1      0      1      2      3
-Infinity ... ------+----|--+------+------+------+------+--|----+------ .... Infinity
                         b                                 a    

演示:

var a = 2.3, b = -2.3;
console.log(Math.trunc(a) + "\t" + Math.floor(a) + "\t" + Math.trunc(b) + "\t" + Math.floor(b));

输出:

2   2   -2  -3

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-07-04
    • 1970-01-01
    • 2014-10-15
    • 1970-01-01
    • 2021-12-20
    • 2021-10-20
    • 2017-01-07
    • 2021-05-17
    相关资源
    最近更新 更多