3 var Long = require('./long');
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;
9 var EXPONENT_MAX = 6111;
10 var EXPONENT_MIN = -6176;
11 var EXPONENT_BIAS = 6176;
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();
20 var EXPONENT_REGEX = /^([\-\+])?(\d+)?$/;
23 // Detect if the value is a digit
24 var isDigit = function(value) {
25 return !isNaN(parseInt(value, 10));
28 // Divide two uint128 values
29 var divideu128 = function(value) {
30 var DIVISOR = Long.fromNumber(1000 * 1000 * 1000);
31 var _rem = Long.fromNumber(0);
34 if(!value.parts[0] && !value.parts[1] &&
35 !value.parts[2] && !value.parts[3]) {
36 return { quotient: value, rem: _rem };
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);
48 return { quotient: value, rem: _rem };
51 // Multiply two Long values and return the 128 bit value
52 var multiply64x2 = function(left, right) {
54 return {high: Long.fromNumber(0), low: Long.fromNumber(0)};
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);
62 var productHigh = leftHigh.multiply(rightHigh);
63 var productMid = leftHigh.multiply(rightLow);
64 var productMid2 = leftLow.multiply(rightHigh);
65 var productLow = leftLow.multiply(rightLow);
67 productHigh = productHigh.add(productMid.shiftRightUnsigned(32));
68 productMid = new Long(productMid.getLowBits(), 0)
70 .add(productLow.shiftRightUnsigned(32));
72 productHigh = productHigh.add(productMid.shiftRightUnsigned(32));
73 productLow = productMid.shiftLeft(32).add(new Long(productLow.getLowBits(), 0));
75 // Return the 128 bit result
76 return {high: productHigh, low: productLow};
79 var lessThan = function(left, right) {
80 // Make values unsigned
81 var uhleft = left.high_ >>> 0;
82 var uhright = right.high_ >>> 0;
84 // Compare high bits first
85 if(uhleft < uhright) {
87 } else if(uhleft == uhright) {
88 var ulleft = left.low_ >>> 0;
89 var ulright = right.low_ >>> 0;
90 if(ulleft < ulright) return true;
96 var longtoHex = function(value) {
97 var buffer = new Buffer(8);
99 // Encode the low 64 bits of the decimal
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;
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');
113 var int32toHex = function(value) {
114 var buffer = new Buffer(4);
116 // Encode the low 64 bits of the decimal
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');
125 var Decimal128 = function(bytes) {
126 this._bsontype = 'Decimal128';
130 Decimal128.fromString = function(string) {
131 // Parse state tracking
132 var isNegative = false;
133 var sawRadix = false;
134 var foundNonZero = false;
136 // Total number of significant digits (no leading or trailing zero)
137 var significantDigits = 0;
138 // Total number of significand digits read
140 // Total number of digits (no leading zeros)
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;
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
155 // The index of the last digit
160 // loop index over array
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;
173 string = string.trim();
176 var stringMatch = string.match(PARSE_STRING_REGEXP);
177 var infMatch = string.match(PARSE_INF_REGEXP);
178 var nanMatch = string.match(PARSE_NAN_REGEXP);
180 // Validate the string
183 && ! nanMatch || string.length == 0) {
184 throw new Error("" + string + " not a valid Decimal128 string");
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");
192 // Get the negative or positive sign
193 if(string[index] == '+' || string[index] == '-') {
194 isNegative = string[index++] == '-';
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));
206 // Read all the digits
207 while(isDigit(string[index]) || string[index] == '.') {
208 if(string[index] == '.') {
210 return new Decimal128(new Buffer(NAN_BUFFER));
218 if(nDigitsStored < 34) {
219 if(string[index] != '0' || foundNonZero) {
221 firstNonZero = nDigitsRead;
226 // Only store 34 digits
227 digits[digitsInsert++] = parseInt(string[index], 10);
228 nDigitsStored = nDigitsStored + 1;
233 nDigits = nDigits + 1;
237 radixPosition = radixPosition + 1;
240 nDigitsRead = nDigitsRead + 1;
244 if(sawRadix && !nDigitsRead) {
245 throw new Error("" + string + " not a valid Decimal128 string");
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);
254 if(!match || !match[2]) {
255 return new Decimal128(new Buffer(NAN_BUFFER));
259 exponent = parseInt(match[0], 10);
262 index = index + match[0].length;
265 // Return not a number
267 return new Decimal128(new Buffer(NAN_BUFFER));
270 // Done reading input
271 // Find first non-zero digit in digits
280 significantDigits = 0;
282 lastDigit = nDigitsStored - 1;
283 significantDigits = nDigits;
285 if(exponent != 0 && significantDigits != 1) {
286 while(string[firstNonZero + significantDigits - 1] == '0') {
287 significantDigits = significantDigits - 1;
292 // Normalization of exponent
293 // Correct exponent based on radix position, and shift significand as needed
294 // to represent user input
296 // Overflow prevention
297 if(exponent <= radixPosition && radixPosition - exponent > (1 << 14)) {
298 exponent = EXPONENT_MIN;
300 exponent = exponent - radixPosition;
303 // Attempt to normalize the exponent
304 while(exponent > EXPONENT_MAX) {
305 // Shift exponent to significand and decrease
306 lastDigit = lastDigit + 1;
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;
315 return new Decimal128(new Buffer(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER));
319 exponent = exponent - 1;
322 while(exponent < EXPONENT_MIN || nDigitsStored < nDigits) {
325 exponent = EXPONENT_MIN;
326 significantDigits = 0;
330 if(nDigitsStored < nDigits) {
331 // adjust to match digits not stored
332 nDigits = nDigits - 1;
335 lastDigit = lastDigit - 1;
338 if(exponent < EXPONENT_MAX) {
339 exponent = exponent + 1;
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;
347 return new Decimal128(new Buffer(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER))
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;
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;
366 var roundDigit = parseInt(string[firstNonZero + lastDigit + 1], 10);
369 if(roundDigit >= 5) {
372 if(roundDigit == 5) {
373 roundBit = digits[lastDigit] % 2 == 1;
375 for(var i = firstNonZero + lastDigit + 2; i < endOfString; i++) {
376 if(parseInt(string[i], 10)) {
385 var dIdx = lastDigit;
387 for(; dIdx >= 0; dIdx--) {
388 if(++digits[dIdx] > 9) {
391 // overflowed most significant digit
393 if(exponent < EXPONENT_MAX) {
394 exponent = exponent + 1;
397 return new Decimal128(new Buffer(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER))
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);
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);
422 for(; dIdx <= lastDigit; dIdx++) {
423 significandLow = significandLow.multiply(Long.fromNumber(10));
424 significandLow = significandLow.add(Long.fromNumber(digits[dIdx]));
427 var dIdx = firstDigit;
428 significandHigh = Long.fromNumber(digits[dIdx++]);
430 for(; dIdx <= lastDigit - 17; dIdx++) {
431 significandHigh = significandHigh.multiply(Long.fromNumber(10));
432 significandHigh = significandHigh.add(Long.fromNumber(digits[dIdx]));
435 significandLow = Long.fromNumber(digits[dIdx++]);
437 for(; dIdx <= lastDigit; dIdx++) {
438 significandLow = significandLow.multiply(Long.fromNumber(10));
439 significandLow = significandLow.add(Long.fromNumber(digits[dIdx]));
443 var significand = multiply64x2(significandHigh, Long.fromString("100000000000000000"));
445 significand.low = significand.low.add(significandLow);
447 if(lessThan(significand.low, significandLow)) {
448 significand.high = significand.high.add(Long.fromNumber(1));
452 var biasedExponent = (exponent + EXPONENT_BIAS);
453 var dec = { low: Long.fromNumber(0), high: Long.fromNumber(0) };
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)));
462 dec.high = dec.high.or(Long.fromNumber(biasedExponent & 0x3fff).shiftLeft(49));
463 dec.high = dec.high.or(significand.high.and(Long.fromNumber(0x1ffffffffffff)));
466 dec.low = significand.low;
470 dec.high = dec.high.or(Long.fromString('9223372036854775808'));
473 // Encode into a buffer
474 var buffer = new Buffer(16);
477 // Encode the low 64 bits of the decimal
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;
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;
489 // Encode the high 64 bits of the decimal
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;
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;
501 // Return the new Decimal128
502 return new Decimal128(buffer);
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;
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.
532 // decoded biased exponent (14 bits)
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
544 // the exponent if scientific notation is used
545 var scientific_exponent;
547 // true if the number is zero
550 // the most signifcant significand bits (50-46)
552 // temporary storage for significand decoding
553 var significand128 = {parts: new Array(4)};
554 // indexing variables
565 var buffer = this.bytes;
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;
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;
578 // Create the state of the decimal
580 low: new Long(low, midl),
581 high: new Long(midh, high) };
583 if(dec.high.lessThan(Long.ZERO)) {
587 // Decode combination field and exponent
588 combination = (high >> 26) & COMBINATION_MASK;
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) {
597 biased_exponent = (high >> 15) & EXPONENT_MASK;
598 significand_msb = 0x08 + ((high >> 14) & 0x01);
601 significand_msb = (high >> 14) & 0x07;
602 biased_exponent = (high >> 17) & EXPONENT_MASK;
605 exponent = biased_exponent - EXPONENT_BIAS;
607 // Create string of significand digits
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;
617 if(significand128.parts[0] == 0 && significand128.parts[1] == 0
618 && significand128.parts[2] == 0 && significand128.parts[3] == 0) {
621 for(var k = 3; k >= 0; k--) {
622 var least_digits = 0;
624 var result = divideu128(significand128);
625 significand128 = result.quotient;
626 least_digits = result.rem.low_;
628 // We now have the 9 least significant digits (in base 2).
629 // Convert and output to string.
630 if(!least_digits) continue;
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);
641 // Output format options:
642 // Scientific - [-]d.dddE(+/-)dd or [-]dE(+/-)dd
646 significand_digits = 1;
647 significand[index] = 0;
649 significand_digits = 36;
652 while(!significand[index]) {
654 significand_digits = significand_digits - 1;
659 scientific_exponent = significand_digits - 1 + exponent;
661 // The scientific exponent checks are dictated by the string conversion
662 // specification and are somewhat arbitrary cutoffs.
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.
669 if(scientific_exponent >= 34 || scientific_exponent <= -7 ||
672 string.push(significand[index++]);
673 significand_digits = significand_digits - 1;
675 if(significand_digits) {
679 for(var i = 0; i < significand_digits; i++) {
680 string.push(significand[index++]);
685 if(scientific_exponent > 0) {
686 string.push('+' + scientific_exponent);
688 string.push(scientific_exponent);
691 // Regular format with no decimal place
693 for(var i = 0; i < significand_digits; i++) {
694 string.push(significand[index++]);
697 var radix_position = significand_digits + exponent;
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++]);
709 // add leading zeros after radix
710 while(radix_position++ < 0) {
714 for(var i = 0; i < significand_digits - Math.max(radix_position - 1, 0); i++) {
715 string.push(significand[index++]);
720 return string.join('');
723 Decimal128.prototype.toJSON = function() {
724 return { "$numberDecimal": this.toString() };
727 module.exports = Decimal128;
728 module.exports.Decimal128 = Decimal128;