rt/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 26 Feb 2013 16:54:16 +0100
changeset 772 d382dacfd73f
parent 737 emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js@b2731af0357d
child 778 6f8683517f1f
permissions -rw-r--r--
Moving modules around so the runtime is under one master pom and can be built without building other modules that are in the repository
     1 // empty line needed here
     2 Number.prototype.add32 = function(x) { return (this + x) | 0; };
     3 Number.prototype.sub32 = function(x) { return (this - x) | 0; };
     4 Number.prototype.mul32 = function(x) { 
     5     return (((this * (x >> 16)) << 16) + this * (x & 0xFFFF)) | 0;
     6 };
     7 Number.prototype.neg32 = function() { return (-this) | 0; };
     8 
     9 Number.prototype.toInt8 = function()  { return (this << 24) >> 24; };
    10 Number.prototype.toInt16 = function() { return (this << 16) >> 16; };
    11 
    12 var __m32 = 0xFFFFFFFF;
    13 
    14 Number.prototype.next32 = function(low) {
    15   if (this === 0) {
    16     return low;
    17   }
    18   var l = new Number(low);
    19   l.hi = this | 0;
    20   return l;
    21 };
    22 
    23 Number.prototype.high32 = function() { 
    24     return this.hi ? this.hi : (Math.floor(this / (__m32+1))) | 0;
    25 };
    26 Number.prototype.toInt32 = function() { return this | 0; };
    27 Number.prototype.toFP = function() {
    28     return this.hi ? this.hi * (__m32+1) + this : this;
    29 };
    30 Number.prototype.toLong = function() {
    31     var hi = (this > __m32) ? (Math.floor(this / (__m32+1))) | 0 : 0;
    32     return hi.next32(Math.floor(this % (__m32+1)));
    33 };
    34 
    35 Number.prototype.toExactString = function() {
    36     if (this.hi) {
    37         // check for Long.MIN_VALUE
    38         if ((this.hi == (0x80000000 | 0)) && (this == 0)) {
    39             return '-9223372036854775808';
    40         }
    41         var res = 0;
    42         var a = [ 6,9,2,7,6,9,4,9,2,4 ];
    43         var s = '';
    44         var digit;
    45         var neg = this.hi < 0;
    46         if (neg) {
    47             var x = this.neg64();
    48             var hi = x.hi;
    49             var low = x;
    50         } else {
    51             var hi = this.hi;
    52             var low = this;
    53         }
    54         for (var i = 0; i < a.length; i++) {
    55             res += hi * a[i];
    56             var low_digit = low % 10;
    57             digit = (res % 10) + low_digit;
    58 
    59             low = Math.floor(low / 10);
    60             res = Math.floor(res / 10);
    61 
    62             if (digit >= 10) {
    63                 digit -= 10;
    64                 res++;
    65             }
    66             s = String(digit).concat(s);
    67         }
    68         s = String(res).concat(s).replace(/^0+/, '');
    69         return (neg ? '-' : '').concat(s);
    70     }
    71     return String(this);
    72 };
    73 
    74 Number.prototype.add64 = function(x) {
    75     var low = this + x;
    76     carry = 0;
    77     if (low > __m32) {
    78         carry = 1;
    79         low -= (__m32+1);
    80     }
    81     var hi = (this.high32() + x.high32() + carry) | 0;
    82     return hi.next32(low);
    83 };
    84 
    85 Number.prototype.sub64 = function(x) {
    86     var low = this - x;
    87     carry = 0;
    88     if (low < 0) {
    89         carry = 1;
    90         low += (__m32+1);
    91     }
    92     var hi = (this.high32() - x.high32() - carry) | 0;
    93     return hi.next32(low);
    94 };
    95 
    96 Number.prototype.mul64 = function(x) {
    97     var low = this.mul32(x);
    98     low += (low < 0) ? (__m32+1) : 0;
    99     // first count upper 32 bits of (this.low * x.low)
   100     var hi_hi = 0;
   101     var hi_low = 0;
   102     var m = 1;
   103     for (var i = 0; i < 32; i++) {
   104         if (x & m) {
   105             hi_hi += this >>> 16;
   106             hi_low += this & 0xFFFF
   107         }
   108         hi_low >>= 1;
   109         hi_low += (hi_hi & 1) ? 0x8000 : 0;
   110         hi_hi >>= 1;
   111         m <<= 1;
   112     }
   113     var hi = (hi_hi << 16) + hi_low;
   114     
   115     var m1 = this.high32().mul32(x);
   116     var m2 = this.mul32(x.high32());
   117     hi = hi.add32(m1).add32(m2);
   118     
   119     return hi.next32(low);
   120 };
   121 
   122 Number.prototype.and64 = function(x) {
   123     var low = this & x;
   124     low += (low < 0) ? (__m32+1) : 0;
   125     if (this.hi && x.hi) {
   126         var hi = this.hi & x.hi;
   127         return hi.next32(low);
   128     };
   129     return low;
   130 };
   131 
   132 Number.prototype.or64 = function(x) {
   133     var low = this | x;
   134     low += (low < 0) ? (__m32+1) : 0;
   135     if (this.hi || x.hi) {
   136         var hi = this.hi | x.hi;
   137         return hi.next32(low);
   138     };
   139     return low;
   140 };
   141 
   142 Number.prototype.xor64 = function(x) {
   143     var low = this ^ x;
   144     low += (low < 0) ? (__m32+1) : 0;
   145     if (this.hi || x.hi) {
   146         var hi = this.hi ^ x.hi;
   147         return hi.next32(low);
   148     };
   149     return low;
   150 };
   151 
   152 Number.prototype.shl64 = function(x) {
   153     if (x >= 32) {
   154         var hi = this << (x - 32);
   155         return hi.next32(0);
   156     } else {
   157         var hi = this.high32() << x;
   158         var low_reminder = this >> (32 - x);
   159         hi |= low_reminder;
   160         var low = this << x;
   161         low += (low < 0) ? (__m32+1) : 0;
   162         return hi.next32(low);
   163     }
   164 };
   165 
   166 Number.prototype.shr64 = function(x) {
   167     if (x >= 32) {
   168         var low = this.high32() >> (x - 32);
   169         low += (low < 0) ? (__m32+1) : 0;
   170         return low;
   171     } else {
   172         var low = this >> x;
   173         var hi_reminder = this.high32() << (32 - x);
   174         low |= hi_reminder;
   175         low += (low < 0) ? (__m32+1) : 0;
   176         var hi = this.high32() >> x;
   177         return hi.next32(low);
   178     }
   179 };
   180 
   181 Number.prototype.ushr64 = function(x) {
   182     if (x >= 32) {
   183         var low = this.high32() >>> (x - 32);
   184         low += (low < 0) ? (__m32+1) : 0;
   185         return low;
   186     } else {
   187         var low = this >>> x;
   188         var hi_reminder = this.high32() << (32 - x);
   189         low |= hi_reminder;
   190         low += (low < 0) ? (__m32+1) : 0;
   191         var hi = this.high32() >>> x;
   192         return hi.next32(low);
   193     }
   194 };
   195 
   196 Number.prototype.compare64 = function(x) {
   197     if (this.high32() === x.high32()) {
   198         return (this < x) ? -1 : ((this > x) ? 1 : 0);
   199     }
   200     return (this.high32() < x.high32()) ? -1 : 1;
   201 };
   202 
   203 Number.prototype.neg64 = function() {
   204     var hi = this.high32();
   205     var low = this;
   206     if ((hi === 0) && (low < 0)) { return -low; }
   207     hi = ~hi;
   208     low = ~low;
   209     low += (low < 0) ? (__m32+1) : 0;
   210     var ret = hi.next32(low);
   211     return ret.add64(1);
   212 };
   213 
   214 (function(numberPrototype) {
   215     function __handleDivByZero() {
   216         var exception = new vm.java_lang_ArithmeticException;
   217         vm.java_lang_ArithmeticException(false).constructor
   218           .cons__VLjava_lang_String_2.call(exception, "/ by zero");
   219 
   220         throw exception;
   221     }
   222 
   223     function __Int64(hi32, lo32) {
   224         this.hi32 = hi32 | 0;
   225         this.lo32 = lo32 | 0;
   226 
   227         this.get32 = function(bitIndex) {
   228             var v0;
   229             var v1;
   230             bitIndex += 32;
   231             var selector = bitIndex >>> 5;
   232             switch (selector) {
   233                 case 0:
   234                     v0 = 0;
   235                     v1 = this.lo32;
   236                     break;
   237                 case 1:
   238                     v0 = this.lo32;
   239                     v1 = this.hi32;
   240                     break;
   241                 case 2:
   242                     v0 = this.hi32;
   243                     v1 = 0;
   244                     break
   245                 default:
   246                     return 0;
   247             }
   248 
   249             var shift = bitIndex & 31;
   250             if (shift === 0) {
   251                 return v0;
   252             }
   253 
   254             return (v1 << (32 - shift)) | (v0 >>> shift);
   255         }
   256 
   257         this.get16 = function(bitIndex) {
   258             return this.get32(bitIndex) & 0xffff;
   259         }
   260 
   261         this.set16 = function(bitIndex, value) {
   262             bitIndex += 32;
   263             var shift = bitIndex & 15;
   264             var svalue = (value & 0xffff) << shift; 
   265             var smask = 0xffff << shift;
   266             var selector = bitIndex >>> 4;
   267             switch (selector) {
   268                 case 0:
   269                     break;
   270                 case 1:
   271                     this.lo32 = (this.lo32 & ~(smask >>> 16))
   272                                     | (svalue >>> 16);
   273                     break;
   274                 case 2:
   275                     this.lo32 = (this.lo32 & ~smask) | svalue;
   276                     break;
   277                 case 3:
   278                     this.lo32 = (this.lo32 & ~(smask << 16))
   279                                     | (svalue << 16);
   280                     this.hi32 = (this.hi32 & ~(smask >>> 16))
   281                                     | (svalue >>> 16);
   282                     break;
   283                 case 4:
   284                     this.hi32 = (this.hi32 & ~smask) | svalue;
   285                     break;
   286                 case 5:
   287                     this.hi32 = (this.hi32 & ~(smask << 16))
   288                                     | (svalue << 16);
   289                     break;
   290             }
   291         }
   292 
   293         this.getDigit = function(index, shift) {
   294             return this.get16((index << 4) - shift);
   295         }
   296 
   297         this.getTwoDigits = function(index, shift) {
   298             return this.get32(((index - 1) << 4) - shift);
   299         }
   300 
   301         this.setDigit = function(index, shift, value) {
   302             this.set16((index << 4) - shift, value);
   303         }
   304 
   305         this.countSignificantDigits = function() {
   306             var sd;
   307             var remaining;
   308 
   309             if (this.hi32 === 0) {
   310                 if (this.lo32 === 0) {
   311                     return 0;
   312                 }
   313 
   314                 sd = 2;
   315                 remaining = this.lo32;
   316             } else {
   317                 sd = 4;
   318                 remaining = this.hi32;
   319             }
   320 
   321             if (remaining < 0) {
   322                 return sd;
   323             }
   324 
   325             return (remaining < 65536) ? sd - 1 : sd;
   326         }
   327         
   328         this.toNumber = function() {
   329             var lo32 = this.lo32;
   330             if (lo32 < 0) {
   331                 lo32 += 0x100000000;
   332             }
   333 
   334             return this.hi32.next32(lo32);
   335         }
   336     }
   337 
   338     function __countLeadingZeroes16(number) {
   339         var nlz = 0;
   340 
   341         if (number < 256) {
   342             nlz += 8;
   343             number <<= 8;
   344         }
   345 
   346         if (number < 4096) {
   347             nlz += 4;
   348             number <<= 4;
   349         }
   350 
   351         if (number < 16384) {
   352             nlz += 2;
   353             number <<= 2;
   354         }
   355 
   356         return (number < 32768) ? nlz + 1 : nlz;
   357     }
   358     
   359     // q = u / v; r = u - q * v;
   360     // v != 0
   361     function __div64(q, r, u, v) {
   362         var m = u.countSignificantDigits();
   363         var n = v.countSignificantDigits();
   364 
   365         q.hi32 = q.lo32 = 0;
   366 
   367         if (n === 1) {
   368             // v has single digit
   369             var vd = v.getDigit(0, 0);
   370             var carry = 0;
   371             for (var i = m - 1; i >= 0; --i) {
   372                 var ui = (carry << 16) | u.getDigit(i, 0);
   373                 if (ui < 0) {
   374                     ui += 0x100000000;
   375                 }
   376                 var qi = (ui / vd) | 0;
   377                 q.setDigit(i, 0, qi);
   378                 carry = ui - qi * vd;
   379             }
   380 
   381             r.hi32 = 0;
   382             r.lo32 = carry;
   383             return;
   384         }
   385 
   386         r.hi32 = u.hi32;  
   387         r.lo32 = u.lo32;
   388 
   389         if (m < n) {
   390             return;
   391         }
   392 
   393         // Normalize
   394         var nrm = __countLeadingZeroes16(v.getDigit(n - 1, 0));
   395 
   396         var vd1 = v.getDigit(n - 1, nrm);                
   397         var vd0 = v.getDigit(n - 2, nrm);
   398         for (var j = m - n; j >= 0; --j) {
   399             // Calculate qj estimate
   400             var ud21 = r.getTwoDigits(j + n, nrm);
   401             var ud2 = ud21 >>> 16;
   402             if (ud21 < 0) {
   403                 ud21 += 0x100000000;
   404             }
   405 
   406             var qest = (ud2 === vd1) ? 0xFFFF : ((ud21 / vd1) | 0);
   407             var rest = ud21 - qest * vd1;
   408 
   409             // 0 <= (qest - qj) <= 2
   410 
   411             // Refine qj estimate
   412             var ud0 = r.getDigit(j + n - 2, nrm);
   413             while ((qest * vd0) > ((rest * 0x10000) + ud0)) {
   414                 --qest;
   415                 rest += vd1;
   416             }
   417 
   418             // 0 <= (qest - qj) <= 1
   419             
   420             // Multiply and subtract
   421             var carry = 0;
   422             for (var i = 0; i < n; ++i) {
   423                 var vi = qest * v.getDigit(i, nrm);
   424                 var ui = r.getDigit(i + j, nrm) - carry - (vi & 0xffff);
   425                 r.setDigit(i + j, nrm, ui);
   426                 carry = (vi >>> 16) - (ui >> 16);
   427             }
   428             var uj = ud2 - carry;
   429 
   430             if (uj < 0) {
   431                 // qest - qj = 1
   432 
   433                 // Add back
   434                 --qest;
   435                 var carry = 0;
   436                 for (var i = 0; i < n; ++i) {
   437                     var ui = r.getDigit(i + j, nrm) + v.getDigit(i, nrm)
   438                                  + carry;
   439                     r.setDigit(i + j, nrm, ui);
   440                     carry = ui >> 16;
   441                 }
   442                 uj += carry;
   443             }
   444 
   445             q.setDigit(j, 0, qest);
   446             r.setDigit(j + n, nrm, uj);
   447         }
   448     }
   449 
   450     numberPrototype.div32 = function(x) {
   451         if (x === 0) {
   452             __handleDivByZero();
   453         }
   454 
   455         return (this / x) | 0;
   456     }
   457 
   458     numberPrototype.mod32 = function(x) {
   459         if (x === 0) {
   460             __handleDivByZero();
   461         }
   462 
   463         return (this % x);
   464     }
   465 
   466     numberPrototype.div64 = function(x) {
   467         var negateResult = false;
   468         var u, v;
   469 
   470         if ((this.high32() & 0x80000000) != 0) {
   471             u = this.neg64();
   472             negateResult = !negateResult;
   473         } else {
   474             u = this;        
   475         }
   476 
   477         if ((x.high32() & 0x80000000) != 0) {
   478             v = x.neg64();
   479             negateResult = !negateResult;
   480         } else {
   481             v = x;
   482         }
   483 
   484         if ((v === 0) && (v.high32() === 0)) {
   485             __handleDivByZero();
   486         }
   487 
   488         if (u.high32() === 0) {
   489             if (v.high32() === 0) {
   490                 var result = (u / v) | 0;
   491                 return negateResult ? result.neg64() : result; 
   492             }
   493 
   494             return 0;
   495         }
   496 
   497         var u64 = new __Int64(u.high32(), u);
   498         var v64 = new __Int64(v.high32(), v);
   499         var q64 = new __Int64(0, 0);
   500         var r64 = new __Int64(0, 0);
   501 
   502         __div64(q64, r64, u64, v64);
   503 
   504         var result = q64.toNumber();
   505         return negateResult ? result.neg64() : result; 
   506     }
   507 
   508     numberPrototype.mod64 = function(x) {
   509         var negateResult = false;
   510         var u, v;
   511         
   512         if ((this.high32() & 0x80000000) != 0) {
   513             u = this.neg64();
   514             negateResult = !negateResult;
   515         } else {
   516             u = this;        
   517         }
   518 
   519         if ((x.high32() & 0x80000000) != 0) {
   520             v = x.neg64();
   521         } else {
   522             v = x;
   523         }
   524 
   525         if ((v === 0) && (v.high32() === 0)) {
   526             __handleDivByZero();
   527         }
   528 
   529         if (u.high32() === 0) {
   530             var result = (v.high32() === 0) ? (u % v) : u;
   531             return negateResult ? result.neg64() : result; 
   532         }
   533 
   534         var u64 = new __Int64(u.high32(), u);
   535         var v64 = new __Int64(v.high32(), v);
   536         var q64 = new __Int64(0, 0);
   537         var r64 = new __Int64(0, 0);
   538 
   539         __div64(q64, r64, u64, v64);
   540 
   541         var result = r64.toNumber();
   542         return negateResult ? result.neg64() : result; 
   543     }
   544 })(Number.prototype);