23ae082e7b700a22d6bfdc624f49e66763beaac7
[aai/esr-gui.git] /
1 "use strict"
2
3 var Long = require('./long');
4
5 var PARSE_STRING_REGEXP = /^(\+|\-)?(\d+|(\d*\.\d*))?(E|e)?([\-\+])?(\d+)?$/;
6 var PARSE_INF_REGEXP = /^(\+|\-)?(Infinity|inf)$/i;
7 var PARSE_NAN_REGEXP = /^(\+|\-)?NaN$/i;
8
9 var EXPONENT_MAX = 6111;
10 var EXPONENT_MIN = -6176;
11 var EXPONENT_BIAS = 6176;
12 var MAX_DIGITS = 34;
13
14 // Nan value bits as 32 bit values (due to lack of longs)
15 var NAN_BUFFER = [0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00].reverse();
16 // Infinity value bits 32 bit values (due to lack of longs)
17 var INF_NEGATIVE_BUFFER = [0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00].reverse();
18 var INF_POSITIVE_BUFFER = [0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00].reverse();
19
20 var EXPONENT_REGEX = /^([\-\+])?(\d+)?$/;
21
22
23 // Detect if the value is a digit
24 var isDigit = function(value) {
25   return !isNaN(parseInt(value, 10));
26 }
27
28 // Divide two uint128 values
29 var divideu128 = function(value) {
30   var DIVISOR = Long.fromNumber(1000 * 1000 * 1000);
31   var _rem = Long.fromNumber(0);
32   var i = 0;
33
34   if(!value.parts[0] && !value.parts[1] &&
35      !value.parts[2] && !value.parts[3]) {
36     return { quotient: value, rem: _rem };
37   }
38
39   for(var i = 0; i <= 3; i++) {
40     // Adjust remainder to match value of next dividend
41     _rem = _rem.shiftLeft(32);
42     // Add the divided to _rem
43     _rem = _rem.add(new Long(value.parts[i], 0));
44     value.parts[i] = _rem.div(DIVISOR).low_;
45     _rem = _rem.modulo(DIVISOR);
46   }
47
48   return { quotient: value, rem: _rem };
49 }
50
51 // Multiply two Long values and return the 128 bit value
52 var multiply64x2 = function(left, right) {
53   if(!left && !right) {
54     return {high: Long.fromNumber(0), low: Long.fromNumber(0)};
55   }
56
57   var leftHigh = left.shiftRightUnsigned(32);
58   var leftLow = new Long(left.getLowBits(), 0);
59   var rightHigh = right.shiftRightUnsigned(32);
60   var rightLow = new Long(right.getLowBits(), 0);
61
62   var productHigh = leftHigh.multiply(rightHigh);
63   var productMid = leftHigh.multiply(rightLow);
64   var productMid2 = leftLow.multiply(rightHigh);
65   var productLow = leftLow.multiply(rightLow);
66
67   productHigh = productHigh.add(productMid.shiftRightUnsigned(32));
68   productMid = new Long(productMid.getLowBits(), 0)
69                 .add(productMid2)
70                 .add(productLow.shiftRightUnsigned(32));
71
72   productHigh = productHigh.add(productMid.shiftRightUnsigned(32));
73   productLow = productMid.shiftLeft(32).add(new Long(productLow.getLowBits(), 0));
74
75   // Return the 128 bit result
76   return {high: productHigh, low: productLow};
77 }
78
79 var lessThan = function(left, right) {
80   // Make values unsigned
81   var uhleft = left.high_ >>> 0;
82   var uhright = right.high_ >>> 0;
83
84   // Compare high bits first
85   if(uhleft < uhright) {
86     return true
87   } else if(uhleft == uhright) {
88     var ulleft = left.low_ >>> 0;
89     var ulright = right.low_ >>> 0;
90     if(ulleft < ulright) return true;
91   }
92
93   return false;
94 }
95
96 var longtoHex = function(value) {
97   var buffer = new Buffer(8);
98   var index = 0;
99   // Encode the low 64 bits of the decimal
100   // Encode low bits
101   buffer[index++] = value.low_ & 0xff;
102   buffer[index++] = (value.low_ >> 8) & 0xff;
103   buffer[index++] = (value.low_ >> 16) & 0xff;
104   buffer[index++] = (value.low_ >> 24) & 0xff;
105   // Encode high bits
106   buffer[index++] = value.high_ & 0xff;
107   buffer[index++] = (value.high_ >> 8) & 0xff;
108   buffer[index++] = (value.high_ >> 16) & 0xff;
109   buffer[index++] = (value.high_ >> 24) & 0xff;
110   return buffer.reverse().toString('hex');
111 }
112
113 var int32toHex = function(value) {
114   var buffer = new Buffer(4);
115   var index = 0;
116   // Encode the low 64 bits of the decimal
117   // Encode low bits
118   buffer[index++] = value & 0xff;
119   buffer[index++] = (value >> 8) & 0xff;
120   buffer[index++] = (value >> 16) & 0xff;
121   buffer[index++] = (value >> 24) & 0xff;
122   return buffer.reverse().toString('hex');
123 }
124
125 var Decimal128 = function(bytes) {
126   this._bsontype = 'Decimal128';
127   this.bytes = bytes;
128 }
129
130 Decimal128.fromString = function(string) {
131   // Parse state tracking
132   var isNegative = false;
133   var sawRadix = false;
134   var foundNonZero = false;
135
136   // Total number of significant digits (no leading or trailing zero)
137   var significantDigits = 0;
138   // Total number of significand digits read
139   var nDigitsRead = 0;
140   // Total number of digits (no leading zeros)
141   var nDigits = 0;
142   // The number of the digits after radix
143   var radixPosition = 0;
144   // The index of the first non-zero in *str*
145   var firstNonZero = 0;
146
147   // Digits Array
148   var digits = [0];
149   // The number of digits in digits
150   var nDigitsStored = 0;
151   // Insertion pointer for digits
152   var digitsInsert = 0;
153   // The index of the first non-zero digit
154   var firstDigit = 0;
155   // The index of the last digit
156   var lastDigit = 0;
157
158   // Exponent
159   var exponent = 0;
160   // loop index over array
161   var i = 0;
162   // The high 17 digits of the significand
163   var significandHigh = [0, 0];
164   // The low 17 digits of the significand
165   var significandLow = [0, 0];
166   // The biased exponent
167   var biasedExponent = 0;
168
169   // Read index
170   var index = 0;
171
172   // Trim the string
173   string = string.trim();
174
175   // Results
176   var stringMatch = string.match(PARSE_STRING_REGEXP);
177   var infMatch = string.match(PARSE_INF_REGEXP);
178   var nanMatch = string.match(PARSE_NAN_REGEXP);
179
180   // Validate the string
181   if(!stringMatch
182     && ! infMatch
183     && ! nanMatch || string.length == 0) {
184       throw new Error("" + string + " not a valid Decimal128 string");
185   }
186
187   // Check if we have an illegal exponent format
188   if(stringMatch && stringMatch[4] && stringMatch[2] === undefined) {
189     throw new Error("" + string + " not a valid Decimal128 string");
190   }
191
192   // Get the negative or positive sign
193   if(string[index] == '+' || string[index] == '-') {
194     isNegative = string[index++] == '-';
195   }
196
197   // Check if user passed Infinity or NaN
198   if(!isDigit(string[index]) && string[index] != '.') {
199     if(string[index] == 'i' || string[index] == 'I') {
200       return new Decimal128(new Buffer(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER));
201     } else if(string[index] == 'N') {
202       return new Decimal128(new Buffer(NAN_BUFFER));
203     }
204   }
205
206   // Read all the digits
207   while(isDigit(string[index]) || string[index] == '.') {
208     if(string[index] == '.') {
209       if(sawRadix) {
210         return new Decimal128(new Buffer(NAN_BUFFER));
211       }
212
213       sawRadix = true;
214       index = index + 1;
215       continue;
216     }
217
218     if(nDigitsStored < 34) {
219       if(string[index] != '0' || foundNonZero) {
220         if(!foundNonZero) {
221           firstNonZero = nDigitsRead;
222         }
223
224         foundNonZero = true;
225
226         // Only store 34 digits
227         digits[digitsInsert++] = parseInt(string[index], 10);
228         nDigitsStored = nDigitsStored + 1;
229       }
230     }
231
232     if(foundNonZero) {
233       nDigits = nDigits + 1;
234     }
235
236     if(sawRadix) {
237       radixPosition = radixPosition + 1;
238     }
239
240     nDigitsRead = nDigitsRead + 1;
241     index = index + 1;
242   }
243
244   if(sawRadix && !nDigitsRead) {
245     throw new Error("" + string + " not a valid Decimal128 string");
246   }
247
248   // Read exponent if exists
249   if(string[index] == 'e' || string[index] == 'E') {
250     // Read exponent digits
251     var match = string.substr(++index).match(EXPONENT_REGEX);
252
253     // No digits read
254     if(!match || !match[2]) {
255       return new Decimal128(new Buffer(NAN_BUFFER));
256     }
257
258     // Get exponent
259     exponent = parseInt(match[0], 10);
260
261     // Adjust the index
262     index = index + match[0].length;
263   }
264
265   // Return not a number
266   if(string[index]) {
267     return new Decimal128(new Buffer(NAN_BUFFER));
268   }
269
270   // Done reading input
271   // Find first non-zero digit in digits
272   firstDigit = 0;
273
274   if(!nDigitsStored) {
275     firstDigit = 0;
276     lastDigit = 0;
277     digits[0] = 0;
278     nDigits = 1;
279     nDigitsStored = 1;
280     significantDigits = 0;
281   } else {
282     lastDigit = nDigitsStored - 1;
283     significantDigits = nDigits;
284
285     if(exponent != 0 && significantDigits != 1) {
286       while(string[firstNonZero + significantDigits - 1] == '0') {
287         significantDigits = significantDigits - 1;
288       }
289     }
290   }
291
292   // Normalization of exponent
293   // Correct exponent based on radix position, and shift significand as needed
294   // to represent user input
295
296   // Overflow prevention
297   if(exponent <= radixPosition && radixPosition - exponent > (1 << 14)) {
298     exponent = EXPONENT_MIN;
299   } else {
300     exponent = exponent - radixPosition;
301   }
302
303   // Attempt to normalize the exponent
304   while(exponent > EXPONENT_MAX) {
305     // Shift exponent to significand and decrease
306     lastDigit = lastDigit + 1;
307
308     if(lastDigit - firstDigit > MAX_DIGITS) {
309       // Check if we have a zero then just hard clamp, otherwise fail
310       var digitsString = digits.join('');
311       if(digitsString.match(/^0+$/)) {
312         exponent = EXPONENT_MAX;
313         break;
314       } else {
315         return new Decimal128(new Buffer(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER));
316       }
317     }
318
319     exponent = exponent - 1;
320   }
321
322   while(exponent < EXPONENT_MIN || nDigitsStored < nDigits) {
323     // Shift last digit
324     if(lastDigit == 0) {
325       exponent = EXPONENT_MIN;
326       significantDigits = 0;
327       break;
328     }
329
330     if(nDigitsStored < nDigits) {
331       // adjust to match digits not stored
332       nDigits = nDigits - 1;
333     } else {
334       // adjust to round
335       lastDigit = lastDigit - 1;
336     }
337
338     if(exponent < EXPONENT_MAX) {
339       exponent = exponent + 1;
340     } else {
341       // Check if we have a zero then just hard clamp, otherwise fail
342       var digitsString = digits.join('');
343       if(digitsString.match(/^0+$/)) {
344         exponent = EXPONENT_MAX;
345         break;
346       } else {
347         return new Decimal128(new Buffer(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER))
348       }
349     }
350   }
351
352
353   // Round
354   // We've normalized the exponent, but might still need to round.
355   if((lastDigit - firstDigit + 1 < significantDigits) && string[significantDigits] != '0') {
356     var endOfString = nDigitsRead;
357
358     // If we have seen a radix point, 'string' is 1 longer than we have
359     // documented with ndigits_read, so inc the position of the first nonzero
360     // digit and the position that digits are read to.
361     if(sawRadix && exponent == EXPONENT_MIN) {
362       firstNonZero = firstNonZero + 1;
363       endOfString = endOfString + 1;
364     }
365
366     var roundDigit = parseInt(string[firstNonZero + lastDigit + 1], 10);
367     var roundBit = 0;
368
369     if(roundDigit >= 5) {
370       roundBit = 1;
371
372       if(roundDigit == 5) {
373         roundBit = digits[lastDigit] % 2 == 1;
374
375         for(var i = firstNonZero + lastDigit + 2; i < endOfString; i++) {
376           if(parseInt(string[i], 10)) {
377             roundBit = 1;
378             break;
379           }
380         }
381       }
382     }
383
384     if(roundBit) {
385       var dIdx = lastDigit;
386
387       for(; dIdx >= 0; dIdx--) {
388         if(++digits[dIdx] > 9) {
389           digits[dIdx] = 0;
390
391           // overflowed most significant digit
392           if(dIdx == 0) {
393             if(exponent < EXPONENT_MAX) {
394               exponent = exponent + 1;
395               digits[dIdx] = 1;
396             } else {
397               return new Decimal128(new Buffer(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER))
398             }
399           }
400         } else {
401           break;
402         }
403       }
404     }
405   }
406
407   // Encode significand
408   // The high 17 digits of the significand
409   significandHigh = Long.fromNumber(0);
410   // The low 17 digits of the significand
411   significandLow = Long.fromNumber(0);
412
413   // read a zero
414   if(significantDigits == 0) {
415     significandHigh = Long.fromNumber(0);
416     significandLow = Long.fromNumber(0);
417   } else if(lastDigit - firstDigit < 17) {
418     var dIdx = firstDigit;
419     significandLow = Long.fromNumber(digits[dIdx++]);
420     significandHigh = new Long(0, 0);
421
422     for(; dIdx <= lastDigit; dIdx++) {
423       significandLow = significandLow.multiply(Long.fromNumber(10));
424       significandLow = significandLow.add(Long.fromNumber(digits[dIdx]));
425     }
426   } else {
427     var dIdx = firstDigit;
428     significandHigh = Long.fromNumber(digits[dIdx++]);
429
430     for(; dIdx <= lastDigit - 17; dIdx++) {
431       significandHigh = significandHigh.multiply(Long.fromNumber(10));
432       significandHigh = significandHigh.add(Long.fromNumber(digits[dIdx]));
433     }
434
435     significandLow = Long.fromNumber(digits[dIdx++]);
436
437     for(; dIdx <= lastDigit; dIdx++) {
438       significandLow = significandLow.multiply(Long.fromNumber(10));
439       significandLow = significandLow.add(Long.fromNumber(digits[dIdx]));
440     }
441   }
442
443   var significand = multiply64x2(significandHigh, Long.fromString("100000000000000000"));
444
445   significand.low = significand.low.add(significandLow);
446
447   if(lessThan(significand.low, significandLow)) {
448     significand.high = significand.high.add(Long.fromNumber(1));
449   }
450
451   // Biased exponent
452   var biasedExponent = (exponent + EXPONENT_BIAS);
453   var dec = { low: Long.fromNumber(0), high: Long.fromNumber(0) };
454
455   // Encode combination, exponent, and significand.
456   if(significand.high.shiftRightUnsigned(49).and(Long.fromNumber(1)).equals(Long.fromNumber)) {
457     // Encode '11' into bits 1 to 3
458     dec.high = dec.high.or(Long.fromNumber(0x3).shiftLeft(61));
459     dec.high = dec.high.or(Long.fromNumber(biasedExponent).and(Long.fromNumber(0x3fff).shiftLeft(47)));
460     dec.high = dec.high.or(significand.high.and(Long.fromNumber(0x7fffffffffff)));
461   } else {
462     dec.high = dec.high.or(Long.fromNumber(biasedExponent & 0x3fff).shiftLeft(49));
463     dec.high = dec.high.or(significand.high.and(Long.fromNumber(0x1ffffffffffff)));
464   }
465
466   dec.low = significand.low;
467
468   // Encode sign
469   if(isNegative) {
470     dec.high = dec.high.or(Long.fromString('9223372036854775808'));
471   }
472
473   // Encode into a buffer
474   var buffer = new Buffer(16);
475   var index = 0;
476
477   // Encode the low 64 bits of the decimal
478   // Encode low bits
479   buffer[index++] = dec.low.low_ & 0xff;
480   buffer[index++] = (dec.low.low_ >> 8) & 0xff;
481   buffer[index++] = (dec.low.low_ >> 16) & 0xff;
482   buffer[index++] = (dec.low.low_ >> 24) & 0xff;
483   // Encode high bits
484   buffer[index++] = dec.low.high_ & 0xff;
485   buffer[index++] = (dec.low.high_ >> 8) & 0xff;
486   buffer[index++] = (dec.low.high_ >> 16) & 0xff;
487   buffer[index++] = (dec.low.high_ >> 24) & 0xff;
488
489   // Encode the high 64 bits of the decimal
490   // Encode low bits
491   buffer[index++] = dec.high.low_ & 0xff;
492   buffer[index++] = (dec.high.low_ >> 8) & 0xff;
493   buffer[index++] = (dec.high.low_ >> 16) & 0xff;
494   buffer[index++] = (dec.high.low_ >> 24) & 0xff;
495   // Encode high bits
496   buffer[index++] = dec.high.high_ & 0xff;
497   buffer[index++] = (dec.high.high_ >> 8) & 0xff;
498   buffer[index++] = (dec.high.high_ >> 16) & 0xff;
499   buffer[index++] = (dec.high.high_ >> 24) & 0xff;
500
501   // Return the new Decimal128
502   return new Decimal128(buffer);
503 }
504
505 // Extract least significant 5 bits
506 var COMBINATION_MASK = 0x1f;
507 // Extract least significant 14 bits
508 var EXPONENT_MASK = 0x3fff;
509 // Value of combination field for Inf
510 var COMBINATION_INFINITY = 30;
511 // Value of combination field for NaN
512 var COMBINATION_NAN = 31;
513 // Value of combination field for NaN
514 var COMBINATION_SNAN = 32;
515 // decimal128 exponent bias
516 var EXPONENT_BIAS = 6176;
517
518 Decimal128.prototype.toString = function() {
519   // Note: bits in this routine are referred to starting at 0,
520   // from the sign bit, towards the coefficient.
521
522   // bits 0 - 31
523   var high;
524   // bits 32 - 63
525   var midh;
526   // bits 64 - 95
527   var midl;
528   // bits 96 - 127
529   var low;
530   // bits 1 - 5
531   var combination;
532   // decoded biased exponent (14 bits)
533   var biased_exponent;
534   // the number of significand digits
535   var significand_digits = 0;
536   // the base-10 digits in the significand
537   var significand = new Array(36);
538   for(var i = 0; i < significand.length; i++) significand[i] = 0;
539   // read pointer into significand
540   var index = 0;
541
542   // unbiased exponent
543   var exponent;
544   // the exponent if scientific notation is used
545   var scientific_exponent;
546
547   // true if the number is zero
548   var is_zero = false;
549
550   // the most signifcant significand bits (50-46)
551   var significand_msb;
552   // temporary storage for significand decoding
553   var significand128 = {parts: new Array(4)};
554   // indexing variables
555   var i;
556   var j, k;
557
558   // Output string
559   var string = [];
560
561   // Unpack index
562   var index = 0;
563
564   // Buffer reference
565   var buffer = this.bytes;
566
567   // Unpack the low 64bits into a long
568   low = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
569   midl = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
570
571   // Unpack the high 64bits into a long
572   midh = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
573   high = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
574
575   // Unpack index
576   var index = 0;
577
578   // Create the state of the decimal
579   var dec = {
580     low: new Long(low, midl),
581     high: new Long(midh, high) };
582
583   if(dec.high.lessThan(Long.ZERO)) {
584     string.push('-');
585   }
586
587   // Decode combination field and exponent
588   combination = (high >> 26) & COMBINATION_MASK;
589
590   if((combination >> 3) == 3) {
591     // Check for 'special' values
592     if(combination == COMBINATION_INFINITY) {
593       return string.join('') + "Infinity";
594     } else if(combination == COMBINATION_NAN) {
595       return "NaN";
596     } else {
597       biased_exponent = (high >> 15) & EXPONENT_MASK;
598       significand_msb = 0x08 + ((high >> 14) & 0x01);
599     }
600   } else {
601     significand_msb = (high >> 14) & 0x07;
602     biased_exponent = (high >> 17) & EXPONENT_MASK;
603   }
604
605   exponent = biased_exponent - EXPONENT_BIAS;
606
607   // Create string of significand digits
608
609   // Convert the 114-bit binary number represented by
610   // (significand_high, significand_low) to at most 34 decimal
611   // digits through modulo and division.
612   significand128.parts[0] = (high & 0x3fff) + ((significand_msb & 0xf) << 14);
613   significand128.parts[1] = midh;
614   significand128.parts[2] = midl;
615   significand128.parts[3] = low;
616
617   if(significand128.parts[0] == 0 && significand128.parts[1] == 0
618     && significand128.parts[2] == 0 && significand128.parts[3] == 0) {
619       is_zero = true;
620   } else {
621     for(var k = 3; k >= 0; k--) {
622       var least_digits = 0;
623       // Peform the divide
624       var result = divideu128(significand128);
625       significand128 = result.quotient;
626       least_digits = result.rem.low_;
627
628       // We now have the 9 least significant digits (in base 2).
629       // Convert and output to string.
630       if(!least_digits) continue;
631
632       for(var j = 8; j >= 0; j--) {
633         // significand[k * 9 + j] = Math.round(least_digits % 10);
634         significand[k * 9 + j] = least_digits % 10;
635         // least_digits = Math.round(least_digits / 10);
636         least_digits = Math.floor(least_digits / 10);
637       }
638     }
639   }
640
641   // Output format options:
642   // Scientific - [-]d.dddE(+/-)dd or [-]dE(+/-)dd
643   // Regular    - ddd.ddd
644
645   if(is_zero) {
646     significand_digits = 1;
647     significand[index] = 0;
648   } else {
649     significand_digits = 36;
650     var i = 0;
651
652     while(!significand[index]) {
653       i++;
654       significand_digits = significand_digits - 1;
655       index = index + 1;
656     }
657   }
658
659   scientific_exponent = significand_digits - 1 + exponent;
660
661   // The scientific exponent checks are dictated by the string conversion
662   // specification and are somewhat arbitrary cutoffs.
663   //
664   // We must check exponent > 0, because if this is the case, the number
665   // has trailing zeros.  However, we *cannot* output these trailing zeros,
666   // because doing so would change the precision of the value, and would
667   // change stored data if the string converted number is round tripped.
668
669   if(scientific_exponent >= 34 || scientific_exponent <= -7 ||
670     exponent > 0) {
671     // Scientific format
672     string.push(significand[index++]);
673     significand_digits = significand_digits - 1;
674
675     if(significand_digits) {
676       string.push('.');
677     }
678
679     for(var i = 0; i < significand_digits; i++) {
680       string.push(significand[index++]);
681     }
682
683     // Exponent
684     string.push('E');
685     if(scientific_exponent > 0) {
686       string.push('+' + scientific_exponent);
687     } else {
688       string.push(scientific_exponent);
689     }
690   } else {
691     // Regular format with no decimal place
692     if(exponent >= 0) {
693       for(var i = 0; i < significand_digits; i++) {
694         string.push(significand[index++]);
695       }
696     } else {
697       var radix_position = significand_digits + exponent;
698
699       // non-zero digits before radix
700       if(radix_position > 0) {
701         for(var i = 0; i < radix_position; i++) {
702           string.push(significand[index++]);
703         }
704       } else {
705         string.push('0');
706       }
707
708       string.push('.');
709       // add leading zeros after radix
710       while(radix_position++ < 0) {
711         string.push('0');
712       }
713
714       for(var i = 0; i < significand_digits - Math.max(radix_position - 1, 0); i++) {
715         string.push(significand[index++]);
716       }
717     }
718   }
719
720   return string.join('');
721 }
722
723 Decimal128.prototype.toJSON = function() {
724   return { "$numberDecimal": this.toString() };
725 }
726
727 module.exports = Decimal128;
728 module.exports.Decimal128 = Decimal128;