rt/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 02 Apr 2013 12:46:03 +0200
changeset 912 11d3145097dc
parent 832 70c409def6ad
child 1352 7bc78045adfd
permissions -rw-r--r--
Hide helper objects in enclosing 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         if (x >= 32) {
   180             var hi = this << (x - 32);
   181             return hi.next32(0);
   182         } else {
   183             var hi = this.high32() << x;
   184             var low_reminder = this >> (32 - x);
   185             hi |= low_reminder;
   186             var low = this << x;
   187             low += (low < 0) ? (__m32 + 1) : 0;
   188             return hi.next32(low);
   189         }
   190     };
   191 
   192     numberPrototype.shr64 = function(x) {
   193         if (x >= 32) {
   194             var low = this.high32() >> (x - 32);
   195             low += (low < 0) ? (__m32 + 1) : 0;
   196             return low;
   197         } else {
   198             var low = this >> x;
   199             var hi_reminder = this.high32() << (32 - x);
   200             low |= hi_reminder;
   201             low += (low < 0) ? (__m32 + 1) : 0;
   202             var hi = this.high32() >> x;
   203             return hi.next32(low);
   204         }
   205     };
   206 
   207     numberPrototype.ushr64 = function(x) {
   208         if (x >= 32) {
   209             var low = this.high32() >>> (x - 32);
   210             low += (low < 0) ? (__m32 + 1) : 0;
   211             return low;
   212         } else {
   213             var low = this >>> x;
   214             var hi_reminder = this.high32() << (32 - x);
   215             low |= hi_reminder;
   216             low += (low < 0) ? (__m32 + 1) : 0;
   217             var hi = this.high32() >>> x;
   218             return hi.next32(low);
   219         }
   220     };
   221 
   222     numberPrototype.compare64 = function(x) {
   223         if (this.high32() === x.high32()) {
   224             return (this < x) ? -1 : ((this > x) ? 1 : 0);
   225         }
   226         return (this.high32() < x.high32()) ? -1 : 1;
   227     };
   228 
   229     numberPrototype.neg64 = function() {
   230         var hi = this.high32();
   231         var low = this;
   232         if ((hi === 0) && (low < 0)) {
   233             return -low;
   234         }
   235         hi = ~hi;
   236         low = ~low;
   237         low += (low < 0) ? (__m32 + 1) : 0;
   238         var ret = hi.next32(low);
   239         return ret.add64(1);
   240     };
   241     
   242     function __handleDivByZero() {
   243         var exception = new vm.java_lang_ArithmeticException;
   244         vm.java_lang_ArithmeticException(false).constructor
   245           .cons__VLjava_lang_String_2.call(exception, "/ by zero");
   246 
   247         throw exception;
   248     }
   249 
   250     function __Int64(hi32, lo32) {
   251         this.hi32 = hi32 | 0;
   252         this.lo32 = lo32 | 0;
   253 
   254         this.get32 = function(bitIndex) {
   255             var v0;
   256             var v1;
   257             bitIndex += 32;
   258             var selector = bitIndex >>> 5;
   259             switch (selector) {
   260                 case 0:
   261                     v0 = 0;
   262                     v1 = this.lo32;
   263                     break;
   264                 case 1:
   265                     v0 = this.lo32;
   266                     v1 = this.hi32;
   267                     break;
   268                 case 2:
   269                     v0 = this.hi32;
   270                     v1 = 0;
   271                     break
   272                 default:
   273                     return 0;
   274             }
   275 
   276             var shift = bitIndex & 31;
   277             if (shift === 0) {
   278                 return v0;
   279             }
   280 
   281             return (v1 << (32 - shift)) | (v0 >>> shift);
   282         }
   283 
   284         this.get16 = function(bitIndex) {
   285             return this.get32(bitIndex) & 0xffff;
   286         }
   287 
   288         this.set16 = function(bitIndex, value) {
   289             bitIndex += 32;
   290             var shift = bitIndex & 15;
   291             var svalue = (value & 0xffff) << shift; 
   292             var smask = 0xffff << shift;
   293             var selector = bitIndex >>> 4;
   294             switch (selector) {
   295                 case 0:
   296                     break;
   297                 case 1:
   298                     this.lo32 = (this.lo32 & ~(smask >>> 16))
   299                                     | (svalue >>> 16);
   300                     break;
   301                 case 2:
   302                     this.lo32 = (this.lo32 & ~smask) | svalue;
   303                     break;
   304                 case 3:
   305                     this.lo32 = (this.lo32 & ~(smask << 16))
   306                                     | (svalue << 16);
   307                     this.hi32 = (this.hi32 & ~(smask >>> 16))
   308                                     | (svalue >>> 16);
   309                     break;
   310                 case 4:
   311                     this.hi32 = (this.hi32 & ~smask) | svalue;
   312                     break;
   313                 case 5:
   314                     this.hi32 = (this.hi32 & ~(smask << 16))
   315                                     | (svalue << 16);
   316                     break;
   317             }
   318         }
   319 
   320         this.getDigit = function(index, shift) {
   321             return this.get16((index << 4) - shift);
   322         }
   323 
   324         this.getTwoDigits = function(index, shift) {
   325             return this.get32(((index - 1) << 4) - shift);
   326         }
   327 
   328         this.setDigit = function(index, shift, value) {
   329             this.set16((index << 4) - shift, value);
   330         }
   331 
   332         this.countSignificantDigits = function() {
   333             var sd;
   334             var remaining;
   335 
   336             if (this.hi32 === 0) {
   337                 if (this.lo32 === 0) {
   338                     return 0;
   339                 }
   340 
   341                 sd = 2;
   342                 remaining = this.lo32;
   343             } else {
   344                 sd = 4;
   345                 remaining = this.hi32;
   346             }
   347 
   348             if (remaining < 0) {
   349                 return sd;
   350             }
   351 
   352             return (remaining < 65536) ? sd - 1 : sd;
   353         }
   354         
   355         this.toNumber = function() {
   356             var lo32 = this.lo32;
   357             if (lo32 < 0) {
   358                 lo32 += 0x100000000;
   359             }
   360 
   361             return this.hi32.next32(lo32);
   362         }
   363     }
   364 
   365     function __countLeadingZeroes16(number) {
   366         var nlz = 0;
   367 
   368         if (number < 256) {
   369             nlz += 8;
   370             number <<= 8;
   371         }
   372 
   373         if (number < 4096) {
   374             nlz += 4;
   375             number <<= 4;
   376         }
   377 
   378         if (number < 16384) {
   379             nlz += 2;
   380             number <<= 2;
   381         }
   382 
   383         return (number < 32768) ? nlz + 1 : nlz;
   384     }
   385     
   386     // q = u / v; r = u - q * v;
   387     // v != 0
   388     function __div64(q, r, u, v) {
   389         var m = u.countSignificantDigits();
   390         var n = v.countSignificantDigits();
   391 
   392         q.hi32 = q.lo32 = 0;
   393 
   394         if (n === 1) {
   395             // v has single digit
   396             var vd = v.getDigit(0, 0);
   397             var carry = 0;
   398             for (var i = m - 1; i >= 0; --i) {
   399                 var ui = (carry << 16) | u.getDigit(i, 0);
   400                 if (ui < 0) {
   401                     ui += 0x100000000;
   402                 }
   403                 var qi = (ui / vd) | 0;
   404                 q.setDigit(i, 0, qi);
   405                 carry = ui - qi * vd;
   406             }
   407 
   408             r.hi32 = 0;
   409             r.lo32 = carry;
   410             return;
   411         }
   412 
   413         r.hi32 = u.hi32;  
   414         r.lo32 = u.lo32;
   415 
   416         if (m < n) {
   417             return;
   418         }
   419 
   420         // Normalize
   421         var nrm = __countLeadingZeroes16(v.getDigit(n - 1, 0));
   422 
   423         var vd1 = v.getDigit(n - 1, nrm);                
   424         var vd0 = v.getDigit(n - 2, nrm);
   425         for (var j = m - n; j >= 0; --j) {
   426             // Calculate qj estimate
   427             var ud21 = r.getTwoDigits(j + n, nrm);
   428             var ud2 = ud21 >>> 16;
   429             if (ud21 < 0) {
   430                 ud21 += 0x100000000;
   431             }
   432 
   433             var qest = (ud2 === vd1) ? 0xFFFF : ((ud21 / vd1) | 0);
   434             var rest = ud21 - qest * vd1;
   435 
   436             // 0 <= (qest - qj) <= 2
   437 
   438             // Refine qj estimate
   439             var ud0 = r.getDigit(j + n - 2, nrm);
   440             while ((qest * vd0) > ((rest * 0x10000) + ud0)) {
   441                 --qest;
   442                 rest += vd1;
   443             }
   444 
   445             // 0 <= (qest - qj) <= 1
   446             
   447             // Multiply and subtract
   448             var carry = 0;
   449             for (var i = 0; i < n; ++i) {
   450                 var vi = qest * v.getDigit(i, nrm);
   451                 var ui = r.getDigit(i + j, nrm) - carry - (vi & 0xffff);
   452                 r.setDigit(i + j, nrm, ui);
   453                 carry = (vi >>> 16) - (ui >> 16);
   454             }
   455             var uj = ud2 - carry;
   456 
   457             if (uj < 0) {
   458                 // qest - qj = 1
   459 
   460                 // Add back
   461                 --qest;
   462                 var carry = 0;
   463                 for (var i = 0; i < n; ++i) {
   464                     var ui = r.getDigit(i + j, nrm) + v.getDigit(i, nrm)
   465                                  + carry;
   466                     r.setDigit(i + j, nrm, ui);
   467                     carry = ui >> 16;
   468                 }
   469                 uj += carry;
   470             }
   471 
   472             q.setDigit(j, 0, qest);
   473             r.setDigit(j + n, nrm, uj);
   474         }
   475     }
   476 
   477     numberPrototype.div32 = function(x) {
   478         if (x === 0) {
   479             __handleDivByZero();
   480         }
   481 
   482         return (this / x) | 0;
   483     }
   484 
   485     numberPrototype.mod32 = function(x) {
   486         if (x === 0) {
   487             __handleDivByZero();
   488         }
   489 
   490         return (this % x);
   491     }
   492 
   493     numberPrototype.div64 = function(x) {
   494         var negateResult = false;
   495         var u, v;
   496 
   497         if ((this.high32() & 0x80000000) != 0) {
   498             u = this.neg64();
   499             negateResult = !negateResult;
   500         } else {
   501             u = this;        
   502         }
   503 
   504         if ((x.high32() & 0x80000000) != 0) {
   505             v = x.neg64();
   506             negateResult = !negateResult;
   507         } else {
   508             v = x;
   509         }
   510 
   511         if ((v == 0) && (v.high32() === 0)) {
   512             __handleDivByZero();
   513         }
   514 
   515         if (u.high32() === 0) {
   516             if (v.high32() === 0) {
   517                 var result = (u / v) | 0;
   518                 return negateResult ? result.neg64() : result; 
   519             }
   520 
   521             return 0;
   522         }
   523 
   524         var u64 = new __Int64(u.high32(), u);
   525         var v64 = new __Int64(v.high32(), v);
   526         var q64 = new __Int64(0, 0);
   527         var r64 = new __Int64(0, 0);
   528 
   529         __div64(q64, r64, u64, v64);
   530 
   531         var result = q64.toNumber();
   532         return negateResult ? result.neg64() : result; 
   533     }
   534 
   535     numberPrototype.mod64 = function(x) {
   536         var negateResult = false;
   537         var u, v;
   538         
   539         if ((this.high32() & 0x80000000) != 0) {
   540             u = this.neg64();
   541             negateResult = !negateResult;
   542         } else {
   543             u = this;        
   544         }
   545 
   546         if ((x.high32() & 0x80000000) != 0) {
   547             v = x.neg64();
   548         } else {
   549             v = x;
   550         }
   551 
   552         if ((v == 0) && (v.high32() === 0)) {
   553             __handleDivByZero();
   554         }
   555 
   556         if (u.high32() === 0) {
   557             var result = (v.high32() === 0) ? (u % v) : u;
   558             return negateResult ? result.neg64() : result; 
   559         }
   560 
   561         var u64 = new __Int64(u.high32(), u);
   562         var v64 = new __Int64(v.high32(), v);
   563         var q64 = new __Int64(0, 0);
   564         var r64 = new __Int64(0, 0);
   565 
   566         __div64(q64, r64, u64, v64);
   567 
   568         var result = r64.toNumber();
   569         return negateResult ? result.neg64() : result; 
   570     }
   571 })(Number.prototype);
   572 
   573 vm.java_lang_Number(false);