emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js
1.1 --- a/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js Tue Feb 05 16:32:14 2013 +0100
1.2 +++ b/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js Tue Feb 05 16:40:01 2013 +0100
1.3 @@ -113,15 +113,6 @@
1.4 return hi.next32(low);
1.5 };
1.6
1.7 -Number.prototype.div64 = function(x) {
1.8 - var low = Math.floor(this.toFP() / x.toFP()); // TODO: not exact enough
1.9 - if (low > __m32) {
1.10 - var hi = Math.floor(low / (__m32+1)) | 0;
1.11 - return hi.next32(low % (__m32+1));
1.12 - }
1.13 - return low;
1.14 -};
1.15 -
1.16 Number.prototype.and64 = function(x) {
1.17 var low = this & x;
1.18 low += (low < 0) ? (__m32+1) : 0;
1.19 @@ -213,3 +204,313 @@
1.20 var ret = hi.next32(low);
1.21 return ret.add64(1);
1.22 };
1.23 +
1.24 +function __initDivMod(numberPrototype) {
1.25 + function __Int64(hi32, lo32) {
1.26 + this.hi32 = hi32 | 0;
1.27 + this.lo32 = lo32 | 0;
1.28 +
1.29 + this.get32 = function(bitIndex) {
1.30 + var v0;
1.31 + var v1;
1.32 + bitIndex += 32;
1.33 + var selector = bitIndex >>> 5;
1.34 + switch (selector) {
1.35 + case 0:
1.36 + v0 = 0;
1.37 + v1 = this.lo32;
1.38 + break;
1.39 + case 1:
1.40 + v0 = this.lo32;
1.41 + v1 = this.hi32;
1.42 + break;
1.43 + case 2:
1.44 + v0 = this.hi32;
1.45 + v1 = 0;
1.46 + break
1.47 + default:
1.48 + return 0;
1.49 + }
1.50 +
1.51 + var shift = bitIndex & 31;
1.52 + if (shift === 0) {
1.53 + return v0;
1.54 + }
1.55 +
1.56 + return (v1 << (32 - shift)) | (v0 >>> shift);
1.57 + }
1.58 +
1.59 + this.get16 = function(bitIndex) {
1.60 + return this.get32(bitIndex) & 0xffff;
1.61 + }
1.62 +
1.63 + this.set16 = function(bitIndex, value) {
1.64 + bitIndex += 32;
1.65 + var shift = bitIndex & 15;
1.66 + var svalue = (value & 0xffff) << shift;
1.67 + var smask = 0xffff << shift;
1.68 + var selector = bitIndex >>> 4;
1.69 + switch (selector) {
1.70 + case 0:
1.71 + break;
1.72 + case 1:
1.73 + this.lo32 = (this.lo32 & ~(smask >>> 16))
1.74 + | (svalue >>> 16);
1.75 + break;
1.76 + case 2:
1.77 + this.lo32 = (this.lo32 & ~smask) | svalue;
1.78 + break;
1.79 + case 3:
1.80 + this.lo32 = (this.lo32 & ~(smask << 16))
1.81 + | (svalue << 16);
1.82 + this.hi32 = (this.hi32 & ~(smask >>> 16))
1.83 + | (svalue >>> 16);
1.84 + break;
1.85 + case 4:
1.86 + this.hi32 = (this.hi32 & ~smask) | svalue;
1.87 + break;
1.88 + case 5:
1.89 + this.hi32 = (this.hi32 & ~(smask << 16))
1.90 + | (svalue << 16);
1.91 + break;
1.92 + }
1.93 + }
1.94 +
1.95 + this.getDigit = function(index, shift) {
1.96 + return this.get16((index << 4) - shift);
1.97 + }
1.98 +
1.99 + this.getTwoDigits = function(index, shift) {
1.100 + return this.get32(((index - 1) << 4) - shift);
1.101 + }
1.102 +
1.103 + this.setDigit = function(index, shift, value) {
1.104 + this.set16((index << 4) - shift, value);
1.105 + }
1.106 +
1.107 + this.countSignificantDigits = function() {
1.108 + var sd;
1.109 + var remaining;
1.110 +
1.111 + if (this.hi32 === 0) {
1.112 + if (this.lo32 === 0) {
1.113 + return 0;
1.114 + }
1.115 +
1.116 + sd = 2;
1.117 + remaining = this.lo32;
1.118 + } else {
1.119 + sd = 4;
1.120 + remaining = this.hi32;
1.121 + }
1.122 +
1.123 + if (remaining < 0) {
1.124 + return sd;
1.125 + }
1.126 +
1.127 + return (remaining < 65536) ? sd - 1 : sd;
1.128 + }
1.129 +
1.130 + this.toNumber = function() {
1.131 + var lo32 = this.lo32;
1.132 + if (lo32 < 0) {
1.133 + lo32 += 0x100000000;
1.134 + }
1.135 +
1.136 + return this.hi32.next32(lo32);
1.137 + }
1.138 + }
1.139 +
1.140 + function __countLeadingZeroes16(number) {
1.141 + var nlz = 0;
1.142 +
1.143 + if (number < 256) {
1.144 + nlz += 8;
1.145 + number <<= 8;
1.146 + }
1.147 +
1.148 + if (number < 4096) {
1.149 + nlz += 4;
1.150 + number <<= 4;
1.151 + }
1.152 +
1.153 + if (number < 16384) {
1.154 + nlz += 2;
1.155 + number <<= 2;
1.156 + }
1.157 +
1.158 + return (number < 32768) ? nlz + 1 : nlz;
1.159 + }
1.160 +
1.161 + // q = u / v; r = u - q * v;
1.162 + // v != 0
1.163 + function __div64(q, r, u, v) {
1.164 + var m = u.countSignificantDigits();
1.165 + var n = v.countSignificantDigits();
1.166 +
1.167 + q.hi32 = q.lo32 = 0;
1.168 +
1.169 + if (n === 1) {
1.170 + // v has single digit
1.171 + var vd = v.getDigit(0, 0);
1.172 + var carry = 0;
1.173 + for (var i = m - 1; i >= 0; --i) {
1.174 + var ui = (carry << 16) | u.getDigit(i, 0);
1.175 + if (ui < 0) {
1.176 + ui += 0x100000000;
1.177 + }
1.178 + var qi = (ui / vd) | 0;
1.179 + q.setDigit(i, 0, qi);
1.180 + carry = ui - qi * vd;
1.181 + }
1.182 +
1.183 + r.hi32 = 0;
1.184 + r.lo32 = carry;
1.185 + return;
1.186 + }
1.187 +
1.188 + r.hi32 = u.hi32;
1.189 + r.lo32 = u.lo32;
1.190 +
1.191 + if (m < n) {
1.192 + return;
1.193 + }
1.194 +
1.195 + // Normalize
1.196 + var nrm = __countLeadingZeroes16(v.getDigit(n - 1, 0));
1.197 +
1.198 + var vd1 = v.getDigit(n - 1, nrm);
1.199 + var vd0 = v.getDigit(n - 2, nrm);
1.200 + for (var j = m - n; j >= 0; --j) {
1.201 + // Calculate qj estimate
1.202 + var ud21 = r.getTwoDigits(j + n, nrm);
1.203 + var ud2 = ud21 >>> 16;
1.204 + if (ud21 < 0) {
1.205 + ud21 += 0x100000000;
1.206 + }
1.207 +
1.208 + var qest = (ud2 === vd1) ? 0xFFFF : ((ud21 / vd1) | 0);
1.209 + var rest = ud21 - qest * vd1;
1.210 +
1.211 + // 0 <= (qest - qj) <= 2
1.212 +
1.213 + // Refine qj estimate
1.214 + var ud0 = r.getDigit(j + n - 2, nrm);
1.215 + while ((qest * vd0) > ((rest * 0x10000) + ud0)) {
1.216 + --qest;
1.217 + rest += vd1;
1.218 + }
1.219 +
1.220 + // 0 <= (qest - qj) <= 1
1.221 +
1.222 + // Multiply and subtract
1.223 + var carry = 0;
1.224 + for (var i = 0; i < n; ++i) {
1.225 + var vi = qest * v.getDigit(i, nrm);
1.226 + var ui = r.getDigit(i + j, nrm) - carry - (vi & 0xffff);
1.227 + r.setDigit(i + j, nrm, ui);
1.228 + carry = (vi >>> 16) - (ui >> 16);
1.229 + }
1.230 + var uj = ud2 - carry;
1.231 +
1.232 + if (uj < 0) {
1.233 + // qest - qj = 1
1.234 +
1.235 + // Add back
1.236 + --qest;
1.237 + var carry = 0;
1.238 + for (var i = 0; i < n; ++i) {
1.239 + var ui = r.getDigit(i + j, nrm) + v.getDigit(i, nrm)
1.240 + + carry;
1.241 + r.setDigit(i + j, nrm, ui);
1.242 + carry = ui >> 16;
1.243 + }
1.244 + uj += carry;
1.245 + }
1.246 +
1.247 + q.setDigit(j, 0, qest);
1.248 + r.setDigit(j + n, nrm, uj);
1.249 + }
1.250 + }
1.251 +
1.252 + numberPrototype.div64 = function(x) {
1.253 + var negateResult = false;
1.254 + var u, v;
1.255 +
1.256 + if ((this.high32() & 0x80000000) != 0) {
1.257 + u = this.neg64();
1.258 + negateResult = !negateResult;
1.259 + } else {
1.260 + u = this;
1.261 + }
1.262 +
1.263 + if ((x.high32() & 0x80000000) != 0) {
1.264 + v = x.neg64();
1.265 + negateResult = !negateResult;
1.266 + } else {
1.267 + v = x;
1.268 + }
1.269 +
1.270 + if ((v === 0) && (v.high32() === 0)) {
1.271 + // TODO: throw
1.272 + }
1.273 +
1.274 + if (u.high32() === 0) {
1.275 + if (v.high32() === 0) {
1.276 + var result = (u / v) | 0;
1.277 + return negateResult ? result.neg64() : result;
1.278 + }
1.279 +
1.280 + return 0;
1.281 + }
1.282 +
1.283 + var u64 = new __Int64(u.high32(), u);
1.284 + var v64 = new __Int64(v.high32(), v);
1.285 + var q64 = new __Int64(0, 0);
1.286 + var r64 = new __Int64(0, 0);
1.287 +
1.288 + __div64(q64, r64, u64, v64);
1.289 +
1.290 + var result = q64.toNumber();
1.291 + return negateResult ? result.neg64() : result;
1.292 + }
1.293 +
1.294 + numberPrototype.mod64 = function(x) {
1.295 + var negateResult = false;
1.296 + var u, v;
1.297 +
1.298 + if ((this.high32() & 0x80000000) != 0) {
1.299 + u = this.neg64();
1.300 + negateResult = !negateResult;
1.301 + } else {
1.302 + u = this;
1.303 + }
1.304 +
1.305 + if ((x.high32() & 0x80000000) != 0) {
1.306 + v = x.neg64();
1.307 + } else {
1.308 + v = x;
1.309 + }
1.310 +
1.311 + if ((v === 0) && (v.high32() === 0)) {
1.312 + // TODO: throw
1.313 + }
1.314 +
1.315 + if (u.high32() === 0) {
1.316 + var result = (v.high32() === 0) ? (u % v) : u;
1.317 + return negateResult ? result.neg64() : result;
1.318 + }
1.319 +
1.320 + var u64 = new __Int64(u.high32(), u);
1.321 + var v64 = new __Int64(v.high32(), v);
1.322 + var q64 = new __Int64(0, 0);
1.323 + var r64 = new __Int64(0, 0);
1.324 +
1.325 + __div64(q64, r64, u64, v64);
1.326 +
1.327 + var result = r64.toNumber();
1.328 + return negateResult ? result.neg64() : result;
1.329 + }
1.330 +};
1.331 +
1.332 +__initDivMod(Number.prototype);