@@ -160,6 +160,7 @@ export class Decimal128 extends BSONValue {
160
160
static fromString ( representation : string ) : Decimal128 {
161
161
// Parse state tracking
162
162
let isNegative = false ;
163
+ let sawSign = false ;
163
164
let sawRadix = false ;
164
165
let foundNonZero = false ;
165
166
@@ -180,15 +181,11 @@ export class Decimal128 extends BSONValue {
180
181
let nDigitsStored = 0 ;
181
182
// Insertion pointer for digits
182
183
let digitsInsert = 0 ;
183
- // The index of the first non-zero digit
184
- let firstDigit = 0 ;
185
184
// The index of the last digit
186
185
let lastDigit = 0 ;
187
186
188
187
// Exponent
189
188
let exponent = 0 ;
190
- // loop index over array
191
- let i = 0 ;
192
189
// The high 17 digits of the significand
193
190
let significandHigh = new Long ( 0 , 0 ) ;
194
191
// The low 17 digits of the significand
@@ -241,6 +238,7 @@ export class Decimal128 extends BSONValue {
241
238
242
239
// Get the negative or positive sign
243
240
if ( representation [ index ] === '+' || representation [ index ] === '-' ) {
241
+ sawSign = true ;
244
242
isNegative = representation [ index ++ ] === '-' ;
245
243
}
246
244
@@ -263,7 +261,7 @@ export class Decimal128 extends BSONValue {
263
261
continue ;
264
262
}
265
263
266
- if ( nDigitsStored < 34 ) {
264
+ if ( nDigitsStored < MAX_DIGITS ) {
267
265
if ( representation [ index ] !== '0' || foundNonZero ) {
268
266
if ( ! foundNonZero ) {
269
267
firstNonZero = nDigitsRead ;
@@ -307,11 +305,7 @@ export class Decimal128 extends BSONValue {
307
305
308
306
// Done reading input
309
307
// Find first non-zero digit in digits
310
- firstDigit = 0 ;
311
-
312
308
if ( ! nDigitsStored ) {
313
- firstDigit = 0 ;
314
- lastDigit = 0 ;
315
309
digits [ 0 ] = 0 ;
316
310
nDigits = 1 ;
317
311
nDigitsStored = 1 ;
@@ -320,7 +314,11 @@ export class Decimal128 extends BSONValue {
320
314
lastDigit = nDigitsStored - 1 ;
321
315
significantDigits = nDigits ;
322
316
if ( significantDigits !== 1 ) {
323
- while ( digits [ firstNonZero + significantDigits - 1 ] === 0 ) {
317
+ while (
318
+ representation [
319
+ firstNonZero + significantDigits - 1 + Number ( sawSign ) + Number ( sawRadix )
320
+ ] === '0'
321
+ ) {
324
322
significantDigits = significantDigits - 1 ;
325
323
}
326
324
}
@@ -331,7 +329,7 @@ export class Decimal128 extends BSONValue {
331
329
// to represent user input
332
330
333
331
// Overflow prevention
334
- if ( exponent <= radixPosition && radixPosition - exponent > 1 << 14 ) {
332
+ if ( exponent <= radixPosition && radixPosition > exponent + ( 1 << 14 ) ) {
335
333
exponent = EXPONENT_MIN ;
336
334
} else {
337
335
exponent = exponent - radixPosition ;
@@ -341,11 +339,9 @@ export class Decimal128 extends BSONValue {
341
339
while ( exponent > EXPONENT_MAX ) {
342
340
// Shift exponent to significand and decrease
343
341
lastDigit = lastDigit + 1 ;
344
-
345
- if ( lastDigit - firstDigit > MAX_DIGITS ) {
342
+ if ( lastDigit >= MAX_DIGITS ) {
346
343
// Check if we have a zero then just hard clamp, otherwise fail
347
- const digitsString = digits . join ( '' ) ;
348
- if ( digitsString . match ( / ^ 0 + $ / ) ) {
344
+ if ( significantDigits === 0 ) {
349
345
exponent = EXPONENT_MAX ;
350
346
break ;
351
347
}
@@ -357,85 +353,57 @@ export class Decimal128 extends BSONValue {
357
353
358
354
while ( exponent < EXPONENT_MIN || nDigitsStored < nDigits ) {
359
355
// Shift last digit. can only do this if < significant digits than # stored.
360
- if ( lastDigit === 0 && significantDigits < nDigitsStored ) {
361
- exponent = EXPONENT_MIN ;
362
- significantDigits = 0 ;
363
- break ;
356
+ if ( lastDigit === 0 ) {
357
+ if ( significantDigits === 0 ) {
358
+ exponent = EXPONENT_MIN ;
359
+ break ;
360
+ }
361
+
362
+ invalidErr ( representation , 'exponent underflow' ) ;
364
363
}
365
364
366
365
if ( nDigitsStored < nDigits ) {
366
+ if (
367
+ representation [ nDigits - 1 + Number ( sawSign ) + Number ( sawRadix ) ] !== '0' &&
368
+ significantDigits !== 0
369
+ ) {
370
+ invalidErr ( representation , 'inexact rounding' ) ;
371
+ }
367
372
// adjust to match digits not stored
368
373
nDigits = nDigits - 1 ;
369
374
} else {
375
+ if ( digits [ lastDigit ] !== 0 ) {
376
+ invalidErr ( representation , 'inexact rounding' ) ;
377
+ }
370
378
// adjust to round
371
379
lastDigit = lastDigit - 1 ;
372
380
}
373
381
374
382
if ( exponent < EXPONENT_MAX ) {
375
383
exponent = exponent + 1 ;
376
384
} else {
377
- // Check if we have a zero then just hard clamp, otherwise fail
378
- const digitsString = digits . join ( '' ) ;
379
- if ( digitsString . match ( / ^ 0 + $ / ) ) {
380
- exponent = EXPONENT_MAX ;
381
- break ;
382
- }
383
385
invalidErr ( representation , 'overflow' ) ;
384
386
}
385
387
}
386
388
387
389
// Round
388
390
// We've normalized the exponent, but might still need to round.
389
- if ( lastDigit - firstDigit + 1 < significantDigits ) {
390
- let endOfString = nDigitsRead ;
391
-
391
+ if ( lastDigit + 1 < significantDigits ) {
392
392
// If we have seen a radix point, 'string' is 1 longer than we have
393
393
// documented with ndigits_read, so inc the position of the first nonzero
394
394
// digit and the position that digits are read to.
395
395
if ( sawRadix ) {
396
396
firstNonZero = firstNonZero + 1 ;
397
- endOfString = endOfString + 1 ;
398
397
}
399
- // if negative , we need to increment again to account for - sign at start.
400
- if ( isNegative ) {
398
+ // if saw sign , we need to increment again to account for - or + sign at start.
399
+ if ( sawSign ) {
401
400
firstNonZero = firstNonZero + 1 ;
402
- endOfString = endOfString + 1 ;
403
401
}
404
402
405
403
const roundDigit = parseInt ( representation [ firstNonZero + lastDigit + 1 ] , 10 ) ;
406
- let roundBit = 0 ;
407
-
408
- if ( roundDigit >= 5 ) {
409
- roundBit = 1 ;
410
- if ( roundDigit === 5 ) {
411
- roundBit = digits [ lastDigit ] % 2 === 1 ? 1 : 0 ;
412
- for ( i = firstNonZero + lastDigit + 2 ; i < endOfString ; i ++ ) {
413
- if ( parseInt ( representation [ i ] , 10 ) ) {
414
- roundBit = 1 ;
415
- break ;
416
- }
417
- }
418
- }
419
- }
420
404
421
- if ( roundBit ) {
422
- let dIdx = lastDigit ;
423
-
424
- for ( ; dIdx >= 0 ; dIdx -- ) {
425
- if ( ++ digits [ dIdx ] > 9 ) {
426
- digits [ dIdx ] = 0 ;
427
-
428
- // overflowed most significant digit
429
- if ( dIdx === 0 ) {
430
- if ( exponent < EXPONENT_MAX ) {
431
- exponent = exponent + 1 ;
432
- digits [ dIdx ] = 1 ;
433
- } else {
434
- return new Decimal128 ( isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER ) ;
435
- }
436
- }
437
- }
438
- }
405
+ if ( roundDigit !== 0 ) {
406
+ invalidErr ( representation , 'inexact rounding' ) ;
439
407
}
440
408
}
441
409
@@ -449,8 +417,8 @@ export class Decimal128 extends BSONValue {
449
417
if ( significantDigits === 0 ) {
450
418
significandHigh = Long . fromNumber ( 0 ) ;
451
419
significandLow = Long . fromNumber ( 0 ) ;
452
- } else if ( lastDigit - firstDigit < 17 ) {
453
- let dIdx = firstDigit ;
420
+ } else if ( lastDigit < 17 ) {
421
+ let dIdx = 0 ;
454
422
significandLow = Long . fromNumber ( digits [ dIdx ++ ] ) ;
455
423
significandHigh = new Long ( 0 , 0 ) ;
456
424
@@ -459,7 +427,7 @@ export class Decimal128 extends BSONValue {
459
427
significandLow = significandLow . add ( Long . fromNumber ( digits [ dIdx ] ) ) ;
460
428
}
461
429
} else {
462
- let dIdx = firstDigit ;
430
+ let dIdx = 0 ;
463
431
significandHigh = Long . fromNumber ( digits [ dIdx ++ ] ) ;
464
432
465
433
for ( ; dIdx <= lastDigit - 17 ; dIdx ++ ) {
0 commit comments