formio/node_modules/bson/lib/bson/decimal128.js   F
last analyzed

Complexity

Total Complexity 117
Complexity/F 11.7

Size

Lines of Code 728
Function Count 10

Duplication

Duplicated Lines 641
Ratio 88.05 %

Importance

Changes 0
Metric Value
cc 0
wmc 117
nc 0
mnd 7
bc 101
fnc 10
dl 641
loc 728
rs 1.263
bpm 10.1
cpm 11.7
noi 6
c 0
b 0
f 0

10 Functions

Rating   Name   Duplication   Size   Complexity  
F Decimal128.fromString 374 374 72
A decimal128.js ➔ Decimal128 0 4 1
A decimal128.js ➔ lessThan 0 16 4
B decimal128.js ➔ longtoHex 16 16 1
A decimal128.js ➔ isDigit 0 3 1
F Decimal128.toString 204 204 27
A decimal128.js ➔ int32toHex 0 11 1
B decimal128.js ➔ divideu128 21 21 6
A Decimal128.toJSON 0 3 1
B decimal128.js ➔ multiply64x2 26 26 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like formio/node_modules/bson/lib/bson/decimal128.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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 View Code Duplication
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 View Code Duplication
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 View Code Duplication
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;
0 ignored issues
show
Unused Code introduced by
The assignment to variable index seems to be never used. Consider removing it.
Loading history...
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;
0 ignored issues
show
Unused Code introduced by
The assignment to variable index seems to be never used. Consider removing it.
Loading history...
122
  return buffer.reverse().toString('hex');
123
}
124
125
var Decimal128 = function(bytes) {
126
  this._bsontype = 'Decimal128';
127
  this.bytes = bytes;
128
}
129
130 View Code Duplication
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];
0 ignored issues
show
Unused Code introduced by
The assignment to variable significandHigh seems to be never used. Consider removing it.
Loading history...
164
  // The low 17 digits of the significand
165
  var significandLow = [0, 0];
0 ignored issues
show
Unused Code introduced by
The assignment to variable significandLow seems to be never used. Consider removing it.
Loading history...
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;
0 ignored issues
show
Unused Code introduced by
The assignment to variable index seems to be never used. Consider removing it.
Loading history...
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 View Code Duplication
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;
0 ignored issues
show
Unused Code introduced by
The assignment to variable index seems to be never used. Consider removing it.
Loading history...
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;
729