@@ -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
@@ -187,8 +188,6 @@ export class Decimal128 extends BSONValue {
187
188
188
189
// Exponent
189
190
let exponent = 0 ;
190
- // loop index over array
191
- let i = 0 ;
192
191
// The high 17 digits of the significand
193
192
let significandHigh = new Long ( 0 , 0 ) ;
194
193
// The low 17 digits of the significand
@@ -241,6 +240,7 @@ export class Decimal128 extends BSONValue {
241
240
242
241
// Get the negative or positive sign
243
242
if ( representation [ index ] === '+' || representation [ index ] === '-' ) {
243
+ sawSign = true ;
244
244
isNegative = representation [ index ++ ] === '-' ;
245
245
}
246
246
@@ -263,7 +263,7 @@ export class Decimal128 extends BSONValue {
263
263
continue ;
264
264
}
265
265
266
- if ( nDigitsStored < 34 ) {
266
+ if ( nDigitsStored < MAX_DIGITS ) {
267
267
if ( representation [ index ] !== '0' || foundNonZero ) {
268
268
if ( ! foundNonZero ) {
269
269
firstNonZero = nDigitsRead ;
@@ -320,7 +320,11 @@ export class Decimal128 extends BSONValue {
320
320
lastDigit = nDigitsStored - 1 ;
321
321
significantDigits = nDigits ;
322
322
if ( significantDigits !== 1 ) {
323
- while ( digits [ firstNonZero + significantDigits - 1 ] === 0 ) {
323
+ while (
324
+ representation [
325
+ firstNonZero + significantDigits - 1 + Number ( sawSign ) + Number ( sawRadix )
326
+ ] === '0'
327
+ ) {
324
328
significantDigits = significantDigits - 1 ;
325
329
}
326
330
}
@@ -331,7 +335,7 @@ export class Decimal128 extends BSONValue {
331
335
// to represent user input
332
336
333
337
// Overflow prevention
334
- if ( exponent <= radixPosition && radixPosition - exponent > 1 << 14 ) {
338
+ if ( exponent <= radixPosition && radixPosition > exponent + ( 1 << 14 ) ) {
335
339
exponent = EXPONENT_MIN ;
336
340
} else {
337
341
exponent = exponent - radixPosition ;
@@ -342,10 +346,9 @@ export class Decimal128 extends BSONValue {
342
346
// Shift exponent to significand and decrease
343
347
lastDigit = lastDigit + 1 ;
344
348
345
- if ( lastDigit - firstDigit > MAX_DIGITS ) {
349
+ if ( lastDigit - firstDigit >= MAX_DIGITS ) {
346
350
// Check if we have a zero then just hard clamp, otherwise fail
347
- const digitsString = digits . join ( '' ) ;
348
- if ( digitsString . match ( / ^ 0 + $ / ) ) {
351
+ if ( significantDigits === 0 ) {
349
352
exponent = EXPONENT_MAX ;
350
353
break ;
351
354
}
@@ -357,85 +360,57 @@ export class Decimal128 extends BSONValue {
357
360
358
361
while ( exponent < EXPONENT_MIN || nDigitsStored < nDigits ) {
359
362
// 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 ;
363
+ if ( lastDigit === 0 ) {
364
+ if ( significantDigits === 0 ) {
365
+ exponent = EXPONENT_MIN ;
366
+ break ;
367
+ }
368
+
369
+ invalidErr ( representation , 'exponent underflow' ) ;
364
370
}
365
371
366
372
if ( nDigitsStored < nDigits ) {
373
+ if (
374
+ representation [ nDigits - 1 + Number ( sawSign ) + Number ( sawRadix ) ] !== '0' &&
375
+ significantDigits !== 0
376
+ ) {
377
+ invalidErr ( representation , 'inexact rounding not allowed' ) ;
378
+ }
367
379
// adjust to match digits not stored
368
380
nDigits = nDigits - 1 ;
369
381
} else {
382
+ if ( digits [ lastDigit ] !== 0 ) {
383
+ invalidErr ( representation , 'inexact rounding not allowed' ) ;
384
+ }
370
385
// adjust to round
371
386
lastDigit = lastDigit - 1 ;
372
387
}
373
388
374
389
if ( exponent < EXPONENT_MAX ) {
375
390
exponent = exponent + 1 ;
376
391
} 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
392
invalidErr ( representation , 'overflow' ) ;
384
393
}
385
394
}
386
395
387
396
// Round
388
397
// We've normalized the exponent, but might still need to round.
389
398
if ( lastDigit - firstDigit + 1 < significantDigits ) {
390
- let endOfString = nDigitsRead ;
391
-
392
399
// If we have seen a radix point, 'string' is 1 longer than we have
393
400
// documented with ndigits_read, so inc the position of the first nonzero
394
401
// digit and the position that digits are read to.
395
402
if ( sawRadix ) {
396
403
firstNonZero = firstNonZero + 1 ;
397
- endOfString = endOfString + 1 ;
398
404
}
399
- // if negative , we need to increment again to account for - sign at start.
400
- if ( isNegative ) {
405
+ // if saw sign , we need to increment again to account for - or + sign at start.
406
+ if ( sawSign ) {
401
407
firstNonZero = firstNonZero + 1 ;
402
- endOfString = endOfString + 1 ;
403
408
}
404
409
405
- const roundDigit = parseInt ( representation [ firstNonZero + endOfString + 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
- }
410
+ const roundDigit = parseInt ( representation [ firstNonZero + lastDigit + 1 ] , 10 ) ;
420
411
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
- }
412
+ if ( roundDigit !== 0 ) {
413
+ invalidErr ( representation , 'inexact rounding not allowed' ) ;
439
414
}
440
415
}
441
416
0 commit comments