UNPKG

23.9 kBJavaScriptView Raw
1System.register("bigfloat", [], function(exports_1) {
2 "use strict";
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});