@@ -160,6 +160,7 @@ export class Decimal128 extends BSONValue {
160160 static fromString ( representation : string ) : Decimal128 {
161161 // Parse state tracking
162162 let isNegative = false ;
163+ let sawSign = false ;
163164 let sawRadix = false ;
164165 let foundNonZero = false ;
165166
@@ -187,8 +188,6 @@ export class Decimal128 extends BSONValue {
187188
188189 // Exponent
189190 let exponent = 0 ;
190- // loop index over array
191- let i = 0 ;
192191 // The high 17 digits of the significand
193192 let significandHigh = new Long ( 0 , 0 ) ;
194193 // The low 17 digits of the significand
@@ -241,6 +240,7 @@ export class Decimal128 extends BSONValue {
241240
242241 // Get the negative or positive sign
243242 if ( representation [ index ] === '+' || representation [ index ] === '-' ) {
243+ sawSign = true ;
244244 isNegative = representation [ index ++ ] === '-' ;
245245 }
246246
@@ -263,7 +263,7 @@ export class Decimal128 extends BSONValue {
263263 continue ;
264264 }
265265
266- if ( nDigitsStored < 34 ) {
266+ if ( nDigitsStored < MAX_DIGITS ) {
267267 if ( representation [ index ] !== '0' || foundNonZero ) {
268268 if ( ! foundNonZero ) {
269269 firstNonZero = nDigitsRead ;
@@ -320,7 +320,11 @@ export class Decimal128 extends BSONValue {
320320 lastDigit = nDigitsStored - 1 ;
321321 significantDigits = nDigits ;
322322 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+ ) {
324328 significantDigits = significantDigits - 1 ;
325329 }
326330 }
@@ -331,7 +335,7 @@ export class Decimal128 extends BSONValue {
331335 // to represent user input
332336
333337 // Overflow prevention
334- if ( exponent <= radixPosition && radixPosition - exponent > 1 << 14 ) {
338+ if ( exponent <= radixPosition && radixPosition > exponent + ( 1 << 14 ) ) {
335339 exponent = EXPONENT_MIN ;
336340 } else {
337341 exponent = exponent - radixPosition ;
@@ -342,10 +346,9 @@ export class Decimal128 extends BSONValue {
342346 // Shift exponent to significand and decrease
343347 lastDigit = lastDigit + 1 ;
344348
345- if ( lastDigit - firstDigit > MAX_DIGITS ) {
349+ if ( lastDigit - firstDigit >= MAX_DIGITS ) {
346350 // 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 ) {
349352 exponent = EXPONENT_MAX ;
350353 break ;
351354 }
@@ -357,85 +360,57 @@ export class Decimal128 extends BSONValue {
357360
358361 while ( exponent < EXPONENT_MIN || nDigitsStored < nDigits ) {
359362 // 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' ) ;
364370 }
365371
366372 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+ }
367379 // adjust to match digits not stored
368380 nDigits = nDigits - 1 ;
369381 } else {
382+ if ( digits [ lastDigit ] !== 0 ) {
383+ invalidErr ( representation , 'inexact rounding not allowed' ) ;
384+ }
370385 // adjust to round
371386 lastDigit = lastDigit - 1 ;
372387 }
373388
374389 if ( exponent < EXPONENT_MAX ) {
375390 exponent = exponent + 1 ;
376391 } 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- }
383392 invalidErr ( representation , 'overflow' ) ;
384393 }
385394 }
386395
387396 // Round
388397 // We've normalized the exponent, but might still need to round.
389398 if ( lastDigit - firstDigit + 1 < significantDigits ) {
390- let endOfString = nDigitsRead ;
391-
392399 // If we have seen a radix point, 'string' is 1 longer than we have
393400 // documented with ndigits_read, so inc the position of the first nonzero
394401 // digit and the position that digits are read to.
395402 if ( sawRadix ) {
396403 firstNonZero = firstNonZero + 1 ;
397- endOfString = endOfString + 1 ;
398404 }
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 ) {
401407 firstNonZero = firstNonZero + 1 ;
402- endOfString = endOfString + 1 ;
403408 }
404409
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 ) ;
420411
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' ) ;
439414 }
440415 }
441416
0 commit comments