为什么Math.imul()比使用少量输入的常规乘法(*)更快,而使用批量更慢?

时间:2017-02-20 20:26:30

标签: javascript

我正在使用Math.imul()方法,我发现输入很少,速度较慢。那是为什么?

(也许它与Math.imul()无关,但这没关系,我仍然有兴趣理解我得到的结果!)

代码:

var base = 40;
var input = [base, base * 10, base * 100, base * 1000];
for (j = 0; j < input.length; ++j) {
  var arrayX = [];
  var arrayY = [];
  for (i = 0; i < input[j]; ++i) {
    arrayX.push(parseInt(Math.random() * 100));
    arrayY.push(parseInt(Math.random() * 100));
  }
  var length = arrayX.length;

  var sm = [];
  console.time(input[j] + ' inputs | Standart multiplication');
  for (i = 0; i < length; ++i) {
    sm[i] = arrayX[i] * arrayY[i];
  }
  console.timeEnd(input[j] + ' inputs | Standart multiplication');


  var im = [];
  console.time(input[j] + ' inputs | Imul multiplication');
  for (i = 0; i < length; ++i) {
    im[i] = Math.imul(arrayX[i], arrayY[i]);
  }
  console.timeEnd(input[j] + ' inputs | Imul multiplication');
}

Chrome控制台的输出:

40 inputs | Standart multiplication: 0.048ms
40 inputs | Imul multiplication: 0.043ms
400 inputs | Standart multiplication: 0.031ms
400 inputs | Imul multiplication: 0.063ms
4000 inputs | Standart multiplication: 0.826ms
4000 inputs | Imul multiplication: 3.604ms
40000 inputs | Standart multiplication: 0.834ms
40000 inputs | Imul multiplication: 0.898ms

Node的输出:

40 inputs | Standart multiplication: 0.510ms
40 inputs | Imul multiplication: 0.064ms
400 inputs | Standart multiplication: 0.569ms
400 inputs | Imul multiplication: 0.108ms
4000 inputs | Standart multiplication: 0.172ms
4000 inputs | Imul multiplication: 3.253ms
40000 inputs | Standart multiplication: 0.502ms
40000 inputs | Imul multiplication: 0.762ms

1 个答案:

答案 0 :(得分:3)

基本答案是Math.imul*相乘并不相同,因此不应该像这样进行比较。 Math.imul执行32位整数乘法,但仍必须接受java脚本数作为输入。因此,它必须执行其他操作来转换和/或确保输入是整数。 (见https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul

这意味着Math.imul(a,b)接受Js浮点数并产生类似于Math.floor(a) * Math.floor(b)的结果

为了使测试更正确,我们可以尝试使用Uint32数组,舍入Math.random结果,确保所有分配都在循环开始时发生,并在结束时计算总和以防止mul由编译器优化的操作。

结果仍然不明确,我怀疑它归结为这样一个事实,即对整数运算的imul速度增益与转换和函数调用的损失相平衡。而这种平​​衡取决于尺寸。

var base = 40;
var input = [base, base * 10, base * 100, base * 1000];
for (var j = 0; j < input.length; ++j) {
  var length = input[j];
  var arrayX = new Uint32Array(length);
  var arrayY = new Uint32Array(length);
  var im = new Uint32Array(length);
  var sm = new Uint32Array(length);

  for (var i = 0; i < input[j]; ++i) {
    arrayX[i] = Math.round(Math.random() * 100);
    arrayY[i] = Math.round(Math.random() * 100)
  }

  console.time(input[j] + ' inputs | Standard multiplication');
  for (var i = 0; i < length; ++i) {
    sm[i] = arrayX[i] * arrayY[i];
  }
  console.timeEnd(input[j] + ' inputs | Standard multiplication');

  console.time(input[j] + ' inputs | Imul multiplication');
  for (var i = 0; i < length; ++i) {
    im[i] = Math.imul(arrayX[i], arrayY[i]);
  }
  console.timeEnd(input[j] + ' inputs | Imul multiplication');

  // Prevent multiplication from being optimized away
  var sum = 0;
  for (var i = 0; i < length; ++i) {
    sum += sm[i];
    sum += im[i];
  }
  console.log(sum);
}

在我的计算机上的Chrome中,对于40000及以上的输入大小,imul现在比标准*乘法略快。而4000尺寸的情况对于imul仍然很慢。但是,如果基数变为35,则它们大致相等。如果基数更改为55 *变得比imul慢得多。

40 inputs | Standard multiplication: 0.120ms
40 inputs | Imul multiplication: 0.035ms
203634
400 inputs | Standard multiplication: 0.045ms
400 inputs | Imul multiplication: 0.050ms
1967184
4000 inputs | Standard multiplication: 0.290ms
4000 inputs | Imul multiplication: 2.935ms
20062298
40000 inputs | Standard multiplication: 0.605ms
40000 inputs | Imul multiplication: 0.450ms
199130538


55 inputs | Standard multiplication: 0.130ms
55 inputs | Imul multiplication: 0.040ms
237716
550 inputs | Standard multiplication: 0.070ms
550 inputs | Imul multiplication: 0.060ms
2638770
5500 inputs | Standard multiplication: 3.175ms
5500 inputs | Imul multiplication: 0.095ms
27218460
55000 inputs | Standard multiplication: 0.850ms
55000 inputs | Imul multiplication: 0.575ms
277160962