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