【问题标题】:Javascript Math.ceil(Math.abs()) optimizationJavascript Math.ceil(Math.abs()) 优化
【发布时间】:2013-05-29 23:30:12
【问题描述】:

我在循环中使用Math.ceil( Math.abs( x ) )

任何人都可以对此操作进行任何优化吗? (按位还是什么?)

欢迎您在jsperf.com 进行基准测试

【问题讨论】:

  • ps:我需要的是操作的返回值,而不是条件是的东西
  • 恐怕没有比你做的更简单了。
  • 我已将测试值更改为负浮点数而不是整数,因此代码实际上必须做一些事情。
  • 从我在 WebKit 源代码中可以看到,JavaScript 方法 Math.abs()Math.ceil() 使用 C++ cmath 函数 fabs()ceil()。我真的不认为你可以优化它。你确定这是一个问题吗?你能发布你正在使用的代码吗?
  • @Crozin:有开销是查找和调用函数(动态调度),你可以通过仅使用运算符(静态调度)摆脱这些开销

标签: javascript performance optimization bit-manipulation


【解决方案1】:

根据 webkit JavaScriptCore,Math.abs 并没有变得更简单

case MathObjectImp::Abs:
result = ( arg < 0 || arg == -0) ? (-arg) : arg;

但是ceil使用C的ceil函数

 case MathObjectImp::Ceil:
    result = ::ceil(arg);

所以在 JSpref 上进行测试 http://jsperf.com/math-ceil-vs-bitwise 按位更快
测试@orangedog 的答案http://jsperf.com/math-ceil-vs-bitwise/2 Math.ceil 更快

所以我猜你最好的选择是:

var n = Math.abs(x);
var f = (n << 0),
f = f == n ? f : f + 1;

【讨论】:

  • 竖起大拇指,您对 Webkit 源代码进行了很好的调查!
【解决方案2】:

x &lt; 0 ? Math.ceil(-x) : Math.ceil(x) 在 Firefox 3.6 中产生 40% 的加速(其他版本差别不大),同时保持相对可读性。

这里是jsPerf page。忽略“一些位运算符”标签;上面的表达式没有使用任何。

【讨论】:

  • found with jsperf 在这种情况下,做一些按位运算比上限函数更快。
【解决方案3】:

Javascript 不像 C 那样是一种编译语言,因此可以在此类语言中创造奇迹的按位运算在 JS 中并不那么出色,因为数字存储为 64 位浮点数。看看这个SO post

即便如此,您在 JS 中编写的内容也会通过底层浏览器以某种方式转换为原生代码,并且可能更快或更慢,具体取决于实现。

由于Math.ceilMath.abs是内置的;我猜它们已经过大量优化,所以我怀疑您是否能够通过自己的一些技巧获得更好的性能。

底线:三件事阻碍您更快地完成:

  1. JS 中的数字表示
  2. 事实上它是一种解释型语言
  3. 您使用的函数是“原生”的,因此它们本身应该足够快

【讨论】:

  • 您忘记了调度开销 - 使用运算符而不是方法很可能会加快代码速度
  • 虽然看起来 JS 中的数字都是双精度数,但所有 JS 引擎实际上都尽可能将值存储为整数,因此按位运算符仍然很快,因为当数字已经是整数时不需要转换。
【解决方案4】:

根据 jsperf,parseInt(Math.abs(x)) + 1 在 Firefox 上的速度提高了约 30%

由于参数总是正数,因此 Math.ceil() 中的分支是不必要的。

【讨论】:

  • 它可能会或可能不会更快,但它也是错误的 - 任何具有零值小数部分的数字都会错误地比 ceil'd 值大 1。
  • 啊,好点子。毫不奇怪,检查这一点会使它再次变慢。
【解决方案5】:

这是另一个,不需要做任何查找:

((x >= 0 ? x : -x) + 0.5) >> 0

【讨论】:

  • 这里的四舍五入是Math.round 而不是Math.ceil
【解决方案6】:

两种最快的计算方式(在现代浏览器中提供几乎相同的速度):

function f (n) {
   return (~~n) + 1;
}

// or 

function f1 (n) {
   return (n | 0) + 1;
}

// some tests, ~~ operator seems to work identicaly on numbers:

( 3.3 | 0 ) === 3;   
( 3.8 | 0 ) === 3;   
( -3.3 | 0 ) === -3; 
( -3.8 | 0 ) === -3;  

不同于Math.floor(-3.3) == Math.floor(-3.8) == -4

【讨论】:

  • f1(1); // 2. 这些函数不遵循Math.ceil 的行为。也许您应该接受评价最高的答案,而不是您自己的。
猜你喜欢
  • 1970-01-01
  • 2020-01-18
  • 2018-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-11
  • 1970-01-01
  • 2019-01-27
相关资源
最近更新 更多