1 | System.register("bigfloat", [], function(exports_1) {
|
2 | ;
|
3 | var dblEpsilon, limbSize, BigFloat;
|
4 | /** Create a string with the given number of zero digits. */
|
5 | function zeroes(count) {
|
6 | return (new Array(count + 1).join('0'));
|
7 | }
|
8 | return {
|
9 | setters:[],
|
10 | execute: function() {
|
11 | /** Difference between closest possible IEEE 754 doubles between 1 and 2. */
|
12 | exports_1("dblEpsilon", dblEpsilon = Math.pow(2, -52));
|
13 | /** Base for calculations, the bigger the better but must fit in 32 bits. */
|
14 | limbSize = Math.pow(2, 32);
|
15 | BigFloat = (function () {
|
16 | function BigFloat(dbl) {
|
17 | if (dbl)
|
18 | this.setDouble(dbl);
|
19 | else {
|
20 | this.fractionLen = 0;
|
21 | this.limbList = [];
|
22 | }
|
23 | }
|
24 | /** Output EXACT value of an IEEE 754 double in base 2, 10 or 16.
|
25 | * Exponent must be between -2 and 61, and last 3 bits of mantissa must be 0.
|
26 | * Useful for debugging. */
|
27 | BigFloat.doubleToString = function (dbl, base) {
|
28 | if (base === void 0) { base = 10; }
|
29 | var pad = BigFloat.padTbl[base];
|
30 | var sign = '';
|
31 | var out = '';
|
32 | var limb;
|
33 | var limbStr;
|
34 | var groupSize = limbSize;
|
35 | if (isNaN(dbl))
|
36 | return ('NaN');
|
37 | // For negative numbers, output sign and get absolute value.
|
38 | if (dbl < 0) {
|
39 | sign = '-';
|
40 | dbl = -dbl;
|
41 | }
|
42 | if (!isFinite(dbl))
|
43 | return (sign + 'Inf');
|
44 | if (dbl < 1) {
|
45 | out += '0';
|
46 | }
|
47 | else {
|
48 | var iPart = Math.floor(dbl);
|
49 | dbl -= iPart;
|
50 | if (base == 10)
|
51 | groupSize = 1000000000;
|
52 | while (iPart) {
|
53 | // Extract groups of digits starting from the least significant.
|
54 | limb = iPart % groupSize;
|
55 | iPart = (iPart - limb) / groupSize;
|
56 | limbStr = limb.toString(base);
|
57 | // Prepend digits to result.
|
58 | out = limbStr + out;
|
59 | // If more limbs remain, pad with zeroes to group length.
|
60 | if (iPart)
|
61 | out = pad.substr(limbStr.length) + out;
|
62 | }
|
63 | }
|
64 | // Is there a fractional part remaining?
|
65 | if (dbl > 0) {
|
66 | out += '.';
|
67 | if (base == 10) {
|
68 | groupSize = 10;
|
69 | pad = '';
|
70 | }
|
71 | while (dbl) {
|
72 | // Extract groups of digits starting from the most significant.
|
73 | dbl *= groupSize;
|
74 | limb = dbl >>> 0;
|
75 | dbl -= limb;
|
76 | limbStr = limb.toString(base);
|
77 | // Append digits to result and pad with zeroes to group length.
|
78 | out += pad.substr(limbStr.length) + limbStr;
|
79 | }
|
80 | }
|
81 | // Remove trailing zeroes.
|
82 | return (sign + out.replace(/(\.[0-9a-z]*[1-9a-z])0+$/, '$1'));
|
83 | };
|
84 | /** Set value from a floating point number (probably IEEE 754 double). */
|
85 | BigFloat.prototype.setDouble = function (dbl) {
|
86 | if (dbl < 0) {
|
87 | dbl = -dbl;
|
88 | this.isNegative = 1;
|
89 | }
|
90 | else
|
91 | this.isNegative = 0;
|
92 | var iPart = Math.floor(dbl);
|
93 | var fPart = dbl - iPart;
|
94 | var fractionLen = 0;
|
95 | var limbList = [];
|
96 | var limb;
|
97 | // Handle fractional part.
|
98 | while (fPart) {
|
99 | // Extract limbs starting from the most significant.
|
100 | fPart *= limbSize;
|
101 | limb = fPart >>> 0;
|
102 | fPart -= limb;
|
103 | // Append limb to value (limbs are reversed later).
|
104 | limbList.push(limb);
|
105 | ++fractionLen;
|
106 | }
|
107 | limbList.reverse();
|
108 | // Handle integer part.
|
109 | while (iPart) {
|
110 | // Extract limbs starting from the least significant.
|
111 | limb = iPart % limbSize; // Could also be iPart >>> 0
|
112 | iPart = (iPart - limb) / limbSize;
|
113 | // Append limb to value.
|
114 | limbList.push(limb);
|
115 | }
|
116 | this.limbList = limbList;
|
117 | this.fractionLen = fractionLen;
|
118 | return (this);
|
119 | };
|
120 | /** Multiply by an integer and write output limbs to another list. */
|
121 | BigFloat.prototype.mulInt = function (factor, dstLimbList, srcPos, dstPos, overwriteMask) {
|
122 | if (!factor)
|
123 | return (0);
|
124 | var limbList = this.limbList;
|
125 | var limbCount = limbList.length;
|
126 | var limb;
|
127 | var lo;
|
128 | var carry = 0;
|
129 | // limbList is an array of 32-bit ints but split here into 16-bit low
|
130 | // and high words for multiplying by a 32-bit term, so the intermediate
|
131 | // 48-bit multiplication results fit into 53 bits of IEEE 754 mantissa.
|
132 | while (srcPos < limbCount) {
|
133 | limb = limbList[srcPos++];
|
134 | // Multiply lower half of limb with factor, making carry temporarily take 48 bits.
|
135 | carry += factor * (limb & 0xffff);
|
136 | // Get lowest 16 bits of full product.
|
137 | lo = carry & 0xffff;
|
138 | // Right shift by dividing because >> and >>> truncate to 32 bits before shifting.
|
139 | carry = (carry - lo) / 65536;
|
140 | // Multiply higher half of limb and combine with lowest 16 bits of full product.
|
141 | carry += factor * (limb >>> 16);
|
142 | lo |= carry << 16;
|
143 | // Lowest 32 bits of full product are added to output limb.
|
144 | limb = ((dstLimbList[dstPos] & overwriteMask) + lo) >>> 0;
|
145 | dstLimbList[dstPos++] = limb;
|
146 | // Highest 32 bits of full product stay in carry, also increment by 1 if previous sum overflowed.
|
147 | carry = (carry / 65536) >>> 0;
|
148 | // Bit twiddle equivalent to: if(limb < (lo >>> 0)) ++carry;
|
149 | carry += (lo ^ (((limb - lo) ^ lo) & ~(limb ^ lo))) >>> 31;
|
150 | }
|
151 | // Extend result by one more limb if it overflows.
|
152 | if (carry)
|
153 | dstLimbList[dstPos] = carry;
|
154 | return (carry);
|
155 | };
|
156 | BigFloat.prototype.mulBig = function (multiplier) {
|
157 | var multiplierLimbs = multiplier.limbList;
|
158 | var lenMultiplier = multiplierLimbs.length;
|
159 | var product = new BigFloat();
|
160 | var productLimbs = product.limbList;
|
161 | for (var posMultiplier = 0; posMultiplier < lenMultiplier; ++posMultiplier) {
|
162 | this.mulInt(multiplierLimbs[posMultiplier], productLimbs, 0, posMultiplier, 0xffffffff);
|
163 | }
|
164 | product.isNegative = this.isNegative ^ multiplier.isNegative;
|
165 | product.fractionLen = this.fractionLen + multiplier.fractionLen;
|
166 | return (product);
|
167 | };
|
168 | /** Multiply and return product in a new BigFloat. */
|
169 | BigFloat.prototype.mul = function (multiplier) {
|
170 | if (typeof (multiplier) == 'number') {
|
171 | multiplier = BigFloat.tempFloat.setDouble(multiplier);
|
172 | }
|
173 | return (this.mulBig(multiplier));
|
174 | };
|
175 | BigFloat.prototype.absDeltaFrom = function (other) {
|
176 | var limbList = this.limbList;
|
177 | var otherList = other.limbList;
|
178 | var limbCount = limbList.length;
|
179 | var otherCount = otherList.length;
|
180 | // Compare lengths.
|
181 | var d = (limbCount - this.fractionLen) - (otherCount - other.fractionLen);
|
182 | // If lengths are equal, compare each limb from most to least significant.
|
183 | while (!d && limbCount && otherCount)
|
184 | d = limbList[--limbCount] - otherList[--otherCount];
|
185 | if (d)
|
186 | return (d);
|
187 | if (limbCount) {
|
188 | do
|
189 | d = limbList[--limbCount];
|
190 | while (!d && limbCount);
|
191 | }
|
192 | else if (otherCount) {
|
193 | do
|
194 | d = -otherList[--otherCount];
|
195 | while (!d && otherCount);
|
196 | }
|
197 | return (d);
|
198 | };
|
199 | BigFloat.prototype.isZero = function () {
|
200 | var limbList = this.limbList;
|
201 | var limbCount = limbList.length;
|
202 | var d;
|
203 | if (!limbCount)
|
204 | return (true);
|
205 | do
|
206 | d = limbList[--limbCount];
|
207 | while (!d && limbCount);
|
208 | return (!d);
|
209 | };
|
210 | /** Return an arbitrary number with sign matching the result of this - other. */
|
211 | BigFloat.prototype.deltaFrom = function (other) {
|
212 | var isNegative = this.isNegative;
|
213 | var d = other.isNegative - isNegative;
|
214 | // Check if signs are different.
|
215 | if (d) {
|
216 | // Make sure positive and negative zero have no difference.
|
217 | if (this.isZero() && other.isZero())
|
218 | return (0);
|
219 | // Return difference of signs.
|
220 | return (d);
|
221 | }
|
222 | if (isNegative) {
|
223 | return (-this.absDeltaFrom(other));
|
224 | }
|
225 | else {
|
226 | return (this.absDeltaFrom(other));
|
227 | }
|
228 | };
|
229 | BigFloat.prototype.addBig = function (addend) {
|
230 | var augend = this;
|
231 | var sum = new BigFloat();
|
232 | var fractionLen = augend.fractionLen;
|
233 | var len = fractionLen - addend.fractionLen;
|
234 | if (len < 0) {
|
235 | len = -len;
|
236 | fractionLen += len;
|
237 | augend = addend;
|
238 | addend = this;
|
239 | }
|
240 | sum.isNegative = this.isNegative;
|
241 | sum.fractionLen = fractionLen;
|
242 | var sumLimbs = sum.limbList;
|
243 | var augendLimbs = augend.limbList;
|
244 | var addendLimbs = addend.limbList;
|
245 | var posAugend = 0;
|
246 | var posAddend = 0;
|
247 | var carry = 0;
|
248 | var limbSum;
|
249 | // If one input has more fractional limbs, just copy the leftovers to output.
|
250 | while (posAugend < len) {
|
251 | sumLimbs[posAugend] = augendLimbs[posAugend];
|
252 | ++posAugend;
|
253 | }
|
254 | var lenAddend = addendLimbs.length;
|
255 | len = augendLimbs.length - posAugend;
|
256 | if (len > lenAddend)
|
257 | len = lenAddend;
|
258 | // Calculate sum where input numbers overlap.
|
259 | while (posAddend < len) {
|
260 | carry += augendLimbs[posAugend] + addendLimbs[posAddend++];
|
261 | limbSum = carry >>> 0;
|
262 | carry = carry - limbSum && 1;
|
263 | sumLimbs[posAugend++] = limbSum;
|
264 | }
|
265 | var posSum = posAugend;
|
266 | if (len < lenAddend) {
|
267 | len = lenAddend;
|
268 | augend = addend;
|
269 | posAugend = posAddend;
|
270 | augendLimbs = addendLimbs;
|
271 | }
|
272 | else
|
273 | len = augendLimbs.length;
|
274 | // Copy leftover most significant limbs to output, propagating carry.
|
275 | while (posAugend < len) {
|
276 | carry += augendLimbs[posAugend++];
|
277 | limbSum = carry >>> 0;
|
278 | carry = carry - limbSum && 1;
|
279 | sumLimbs[posSum++] = limbSum;
|
280 | }
|
281 | if (carry)
|
282 | sumLimbs[posSum] = carry;
|
283 | return (sum);
|
284 | };
|
285 | BigFloat.prototype.subBig = function (subtrahend) {
|
286 | var minuend = this;
|
287 | var difference = new BigFloat();
|
288 | difference.isNegative = this.isNegative;
|
289 | // Make sure the subtrahend is the smaller number.
|
290 | if (minuend.absDeltaFrom(subtrahend) < 0) {
|
291 | minuend = subtrahend;
|
292 | subtrahend = this;
|
293 | difference.isNegative ^= 1;
|
294 | }
|
295 | var fractionLen = minuend.fractionLen;
|
296 | var len = fractionLen - subtrahend.fractionLen;
|
297 | var differenceLimbs = difference.limbList;
|
298 | var minuendLimbs = minuend.limbList;
|
299 | var subtrahendLimbs = subtrahend.limbList;
|
300 | var lenMinuend = minuendLimbs.length;
|
301 | var lenSubtrahend = subtrahendLimbs.length;
|
302 | var lenFinal = lenMinuend;
|
303 | var posMinuend = 0;
|
304 | var posSubtrahend = 0;
|
305 | var posDifference = 0;
|
306 | var carry = 0;
|
307 | var limbDiff;
|
308 | if (len >= 0) {
|
309 | while (posMinuend < len) {
|
310 | differenceLimbs[posMinuend] = minuendLimbs[posMinuend];
|
311 | ++posMinuend;
|
312 | }
|
313 | len += lenSubtrahend;
|
314 | if (len > lenMinuend)
|
315 | len = lenMinuend;
|
316 | posDifference = posMinuend;
|
317 | }
|
318 | else {
|
319 | len = -len;
|
320 | fractionLen += len;
|
321 | lenFinal += len;
|
322 | while (posSubtrahend < len) {
|
323 | carry -= subtrahendLimbs[posSubtrahend];
|
324 | limbDiff = carry >>> 0;
|
325 | carry = -(carry < 0);
|
326 | differenceLimbs[posSubtrahend++] = limbDiff;
|
327 | }
|
328 | len += lenMinuend;
|
329 | if (len > lenSubtrahend)
|
330 | len = lenSubtrahend;
|
331 | posDifference = posSubtrahend;
|
332 | }
|
333 | difference.fractionLen = fractionLen;
|
334 | // Calculate difference where input numbers overlap.
|
335 | while (posDifference < len) {
|
336 | carry += minuendLimbs[posMinuend++] - subtrahendLimbs[posSubtrahend++];
|
337 | limbDiff = carry >>> 0;
|
338 | carry = -(carry < 0);
|
339 | differenceLimbs[posDifference++] = limbDiff;
|
340 | }
|
341 | // Copy leftover most significant limbs to output, propagating carry.
|
342 | while (posDifference < lenFinal) {
|
343 | carry += minuendLimbs[posMinuend++];
|
344 | limbDiff = carry >>> 0;
|
345 | carry = -(carry < 0);
|
346 | differenceLimbs[posDifference++] = limbDiff;
|
347 | }
|
348 | return (difference);
|
349 | };
|
350 | BigFloat.prototype.addSub = function (addend, flip) {
|
351 | if (typeof (addend) == 'number') {
|
352 | addend = BigFloat.tempFloat.setDouble(addend);
|
353 | }
|
354 | if (this.isNegative ^ addend.isNegative ^ flip) {
|
355 | return (this.subBig(addend));
|
356 | }
|
357 | else {
|
358 | return (this.addBig(addend));
|
359 | }
|
360 | };
|
361 | /** Add and return sum in a new BigFloat. */
|
362 | BigFloat.prototype.add = function (addend) {
|
363 | return (this.addSub(addend, 0));
|
364 | };
|
365 | /** Subtract and return difference in a new BigFloat. */
|
366 | BigFloat.prototype.sub = function (subtrahend) {
|
367 | return (this.addSub(subtrahend, 1));
|
368 | };
|
369 | /** Divide by integer, replacing current value by quotient. Return integer remainder. */
|
370 | BigFloat.prototype.divInt = function (divisor) {
|
371 | var limbList = this.limbList;
|
372 | var limbNum = limbList.length;
|
373 | var limb;
|
374 | var hi, lo;
|
375 | var carry = 0;
|
376 | // If most significant limb is zero after dividing, decrement number of limbs remaining.
|
377 | if (limbList[limbNum - 1] < divisor) {
|
378 | carry = limbList[--limbNum];
|
379 | limbList.length = limbNum;
|
380 | }
|
381 | while (limbNum--) {
|
382 | limb = limbList[limbNum];
|
383 | carry = carry * 0x10000 + (limb >>> 16);
|
384 | hi = (carry / divisor) >>> 0;
|
385 | carry = carry - hi * divisor;
|
386 | carry = carry * 0x10000 + (limb & 0xffff);
|
387 | lo = (carry / divisor) >>> 0;
|
388 | carry = carry - lo * divisor;
|
389 | limbList[limbNum] = ((hi << 16) | lo) >>> 0;
|
390 | }
|
391 | return (carry);
|
392 | };
|
393 | BigFloat.prototype.fractionToString = function (base, groupSize, digitList) {
|
394 | var pad = BigFloat.padTbl[base];
|
395 | var limbList = this.limbList;
|
396 | var limbCount = this.fractionLen;
|
397 | var limbNum = 0;
|
398 | var limbStr;
|
399 | // Skip least significant limbs that equal zero.
|
400 | while (1) {
|
401 | if (limbNum >= limbCount)
|
402 | return;
|
403 | if (limbList[limbNum])
|
404 | break;
|
405 | ++limbNum;
|
406 | }
|
407 | digitList.push('.');
|
408 | var fPart = BigFloat.tempFloat;
|
409 | fPart.limbList = limbList.slice(limbNum, limbCount);
|
410 | limbCount -= limbNum;
|
411 | limbNum = 0;
|
412 | while (1) {
|
413 | if (fPart.limbList[limbNum]) {
|
414 | var carry = fPart.mulInt(groupSize, fPart.limbList, limbNum, limbNum, 0);
|
415 | if (carry)
|
416 | fPart.limbList.pop();
|
417 | limbStr = '' + carry;
|
418 | digitList.push(pad.substr(limbStr.length) + limbStr);
|
419 | }
|
420 | else if (++limbNum >= limbCount)
|
421 | break;
|
422 | }
|
423 | };
|
424 | /** Convert to string in base 2, 10 or 16. */
|
425 | BigFloat.prototype.toString = function (base) {
|
426 | if (base === void 0) { base = 10; }
|
427 | var pad = BigFloat.padTbl[base];
|
428 | var digitList = [];
|
429 | var limbList = this.limbList;
|
430 | var limb;
|
431 | var limbStr;
|
432 | if (base == 10) {
|
433 | var groupSize = 1000000000;
|
434 | var iPart = BigFloat.tempFloat;
|
435 | iPart.limbList = limbList.slice(this.fractionLen);
|
436 | // Loop while 2 or more limbs remain, requiring arbitrary precision division to extract digits.
|
437 | while (iPart.limbList.length) {
|
438 | limbStr = '' + iPart.divInt(groupSize);
|
439 | // Prepend digits into final result, padded with zeroes to 9 digits.
|
440 | // Since more limbs still remain, whole result will not have extra padding.
|
441 | digitList.push(pad.substr(limbStr.length) + limbStr);
|
442 | }
|
443 | // Prepend last remaining limb and sign to result.
|
444 | digitList.push('' + (iPart.limbList[0] || 0));
|
445 | if (this.isNegative)
|
446 | digitList.push('-');
|
447 | digitList.reverse();
|
448 | // Handle fractional part.
|
449 | this.fractionToString(base, groupSize, digitList);
|
450 | }
|
451 | else {
|
452 | var limbNum = limbList.length;
|
453 | var fractionPos = this.fractionLen;
|
454 | if (this.isNegative)
|
455 | digitList.push('-');
|
456 | if (limbNum == fractionPos)
|
457 | digitList.push('0');
|
458 | while (limbNum--) {
|
459 | limbStr = limbList[limbNum].toString(base);
|
460 | if (limbNum == fractionPos - 1)
|
461 | digitList.push('.');
|
462 | digitList.push(pad.substr(limbStr.length) + limbStr);
|
463 | }
|
464 | }
|
465 | // Remove leading and trailing zeroes.
|
466 | return (BigFloat.trim(digitList.join('')));
|
467 | };
|
468 | /** Remove leading and trailing insignificant zero digits. */
|
469 | BigFloat.trim = function (str) {
|
470 | return (str
|
471 | .replace(/^(-?)0+([1-9a-z]|0(\.|$))/, '$1$2')
|
472 | .replace(/(\.|(\.[0-9a-z]*[1-9a-z]))0+$/, '$2'));
|
473 | };
|
474 | BigFloat.padTbl = {
|
475 | 2: zeroes(32),
|
476 | 10: zeroes(9),
|
477 | 16: zeroes(8)
|
478 | };
|
479 | BigFloat.tempFloat = new BigFloat();
|
480 | return BigFloat;
|
481 | })();
|
482 | exports_1("BigFloat", BigFloat);
|
483 | }
|
484 | }
|
485 | });
|