Math.imul shims

JavaScript performance comparison

Revision 9 of this test case created by Francis Avila

Preparation code

 
<script>
Benchmark.prototype.setup = function() {
    function imul(a, b) {
      var ah = a >>> 16 & 0xFFFF;
      var al = a & 0xFFFF;
      var bh = b >>> 16 & 0xFFFF;
      var bl = b & 0xFFFF;
      // the shift by 0 fixes the sign on the high part
      // the final |0 converts the unsigned value into a signed value
      return al * bl + (ah * bl + al * bh << 16 >>> 0) | 0;
    }
   
    function imul2(x, y) {
      x = x | 0;
      y = y | 0;
     
      var ah = 0.0;
      var al = 0.0;
      var bh = 0.0;
      var bl = 0.0;
      var a = 0.0;
      var b = 0.0;
     
      ah = +(x >>> 16 & 0xFFFF);
      al = +(x & 0xFFFF);
      bh = +(y >>> 16 & 0xFFFF);
      bl = +(y & 0xFFFF);
     
      a = al * bl;
      // convert to uint32 to fix the sign on the high part
      b = +(~~(ah * bl + al * bh) << 16 >>> 0);
      return ~~(a + b) | 0;
    }
   
    var imul3 = (function () {
          'use asm';
          // jshint bitwise:false
          function imul(x, y) {
            x = x | 0;
            y = y | 0;
           
            var ah = 0.0;
            var al = 0.0;
            var bh = 0.0;
            var bl = 0.0;
            var a = 0.0;
            var b = 0.0;
           
            ah = +(x >>> 16 & 0xFFFF);
            al = +(x & 0xFFFF);
            bh = +(y >>> 16 & 0xFFFF);
            bl = +(y & 0xFFFF);
           
            a = al * bl;
            // convert to uint32 to fix the sign on the high part
            b = +(~~(ah * bl + al * bh) << 16 >>> 0);
            return ~~(a + b) | 0;
          }
          // jshint bitwise:true
          return imul;
        })();
   
    var imul4 = (function () {
      'use asm';
     
      // jshint bitwise:false
      function imul(x, y) {
        x = x | 0;
        y = y | 0;
       
        var al = 0;
        var bl = 0;
       
        al = x & 0xFFFF;
        bl = y & 0xFFFF;
       
        // convert to uint32 to fix the sign on the high part
        return add(
          multiply(al, bl) | 0,
          (add(multiply(x >>> 16 & 0xFFFF, bl) | 0, multiply(al, y >>> 16 & 0xFFFF) | 0) | 0) << 16 >>> 0
        ) | 0;
      }
     
      // integer multiplication, as we know that values will not exceed 2^32-1
      // and asm.js throws an error if both the lhs and rhs are not literals +/- 2^20
      function multiply(a, b) {
        a = a | 0;
        b = b | 0;
       
        var result = 0;
        var carry = 0;
        var shiftedCarry = 0;
       
        if ((a >>> 0) < (b >>> 0)) {
          // XOR swap
          a = a ^ b;
          b = b ^ a;
          a = a ^ b;
        }
        while ((b >>> 0) != 0) {
          if (b & 1) {
            carry = result & a;
            result = result ^ a;
            while ((carry >>> 0) != 0) {
              shiftedCarry = carry << 1;
              carry = result & shiftedCarry;
              result = result ^ shiftedCarry;
            }
          }
          a = a << 1;
          b = b >> 1;
        }
        return result | 0;
      }
     
      function add(a, b) {
        a = a | 0;
        b = b | 0;
       
        var carry = 0;
        var result = 0;
        var shiftedCarry = 0;
       
        carry = a & b;
        result = a ^ b;
        while ((carry >>> 0) != 0) {
          shiftedCarry = carry << 1;
          carry = result & shiftedCarry;
          result = result ^ shiftedCarry;
        }
        return result | 0;
      }
      return imul;
      // jshint bitwise:true
    })();
   
    NativeImul = Math.imul;
   
    function use_result(result){}
};

Benchmark.prototype.teardown = function() {
    use_result(result);
};
</script>

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
Mozilla polyfill
result = imul((Math.random()*1000000)|0,(Math.random()*1000000)|0);
pending…
Asm-style
result = imul2((Math.random()*1000000)|0,(Math.random()*1000000)|0);
pending…
asm.js
result = imul3((Math.random()*1000000)|0,(Math.random()*1000000)|0);
pending…
bitwise only
result = imul4((Math.random()*1000000)|0,(Math.random()*1000000)|0);
pending…
Native Math.imul
result = NativeImul((Math.random()*1000000)|0,(Math.random()*1000000)|0);
pending…

Compare results of other browsers

Revisions

You can edit these tests or add even more tests to this page by appending /edit to the URL. Here’s a list of current revisions for this page:

0 comments

Add a comment