Does it perform better than * expressions? Why?
This article describes it as being useful for projects like Emscripten. Why is that?
Thanks
Does it perform better than * expressions? Why?
This article describes it as being useful for projects like Emscripten. Why is that?
Thanks
Short version
Math.imul(a,b)
multiplies a and b as though they were 32 bit signed integers. (a*b)|0
does the same, but may give incorrect results for large numbers.
Long version
You would use Math.imul
whenever you want to multiply two numbers, and you want the multiplication to act as though the two numbers were 32 bit signed integers. That is, you want integer multiplication modulo 2^32.
Normally, you can get this effect by using a bitwise operator on the result. For instance, (0xffffffff + 1)|0
quite correctly gives you 0
. However, this doesn't work for multiplication. (0x7fffffff * 0x7fffffff)|0
gives us 0
, when 32 bit multiplication of the two numbers would give us 1
. The reason for this failure is precision. The Number
type is a IEEE754 double precision floating point number, which has 53 bits of mantissa. When you try to use numbers larger than 2^53, you start losing precision. You can test this by running Math.pow(2,53) == Math.pow(2,53)+1
in your browser.
When you multiply two 32 bit numbers in Javascript and truncate the result using a bitwise operator the intermediate result may be larger than 2^53 and may thus be incorrect, which means that the end result of course will also be incorrect.
I just did a quick benchmark in Chrome, on a Windows 10 computer.
First, I ran this code a bunch of times :
var result;
for(var i = 0; i < 100000000; i++) {
result = 2 * 4;
}
(see also this Fiddle)
Then, I ran this code a bunch of times :
var result;
for(var i = 0; i < 100000000; i++) {
result = Math.imul(2, 4);
}
(see also this Fiddle)
In both cases, execution time averages around 60ms. So, at least in Chrome, there's no performance gained or lost from using just Math.imul()
.
So why use it? Well, there's probably few to no use cases where you'll ever want to use it in handwritten JavaScript. You will, however, see it a lot in asm.js code that's generated by emscripten.
Asm.js is a very strict subset of JavaScript that's practically impossible to handcode by any human developer, but that can be generated relatively easily when compiling from C/C++ to JavaScript. Asm.js code is much closer to machine code than ordinary JavaScript code, which allowed browsers to heavily optimise for any code written in asm.js. In browsers that implemented those optimizations, your code will typically run about 50% of the speed of a C/C++ program that is compiled to machine code. That may seem slow, but it's a hell of a lot faster than any ordinary JavaScript.
Anyway, what I'm saying, is that there is literally no reason to use Math.imul()
in your handwritten code unless, perhaps, if you're a C/C++ programmer still trying to get used to JavaScript. Using Math.imul()
really has no benefits, except when you're writing asm.js code, and that's something you're not supposed to do as a human developer in the first place, because asm.js is both very hard to read and has very strict syntax rules!
For more info on asm.js, see eg. John Resig's article from 2013 or the official specs.
I think it performs better because it's more low level, its implementation may go "down to the metal". With the 32-bit restriction the multiplication could be done directly with the processor with less intermediate abstractions/conversions.
Cheers