@@ -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
@@ -180,15 +181,11 @@ export class Decimal128 extends BSONValue {
180181 let nDigitsStored = 0 ;
181182 // Insertion pointer for digits
182183 let digitsInsert = 0 ;
183- // The index of the first non-zero digit
184- let firstDigit = 0 ;
185184 // The index of the last digit
186185 let lastDigit = 0 ;
187186
188187 // Exponent
189188 let exponent = 0 ;
190- // loop index over array
191- let i = 0 ;
192189 // The high 17 digits of the significand
193190 let significandHigh = new Long ( 0 , 0 ) ;
194191 // The low 17 digits of the significand
@@ -241,6 +238,7 @@ export class Decimal128 extends BSONValue {
241238
242239 // Get the negative or positive sign
243240 if ( representation [ index ] === '+' || representation [ index ] === '-' ) {
241+ sawSign = true ;
244242 isNegative = representation [ index ++ ] === '-' ;
245243 }
246244
@@ -263,7 +261,7 @@ export class Decimal128 extends BSONValue {
263261 continue ;
264262 }
265263
266- if ( nDigitsStored < 34 ) {
264+ if ( nDigitsStored < MAX_DIGITS ) {
267265 if ( representation [ index ] !== '0' || foundNonZero ) {
268266 if ( ! foundNonZero ) {
269267 firstNonZero = nDigitsRead ;
@@ -307,11 +305,7 @@ export class Decimal128 extends BSONValue {
307305
308306 // Done reading input
309307 // Find first non-zero digit in digits
310- firstDigit = 0 ;
311-
312308 if ( ! nDigitsStored ) {
313- firstDigit = 0 ;
314- lastDigit = 0 ;
315309 digits [ 0 ] = 0 ;
316310 nDigits = 1 ;
317311 nDigitsStored = 1 ;
@@ -320,7 +314,11 @@ export class Decimal128 extends BSONValue {
320314 lastDigit = nDigitsStored - 1 ;
321315 significantDigits = nDigits ;
322316 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+ ) {
324322 significantDigits = significantDigits - 1 ;
325323 }
326324 }
@@ -331,7 +329,7 @@ export class Decimal128 extends BSONValue {
331329 // to represent user input
332330
333331 // Overflow prevention
334- if ( exponent <= radixPosition && radixPosition - exponent > 1 << 14 ) {
332+ if ( exponent <= radixPosition && radixPosition > exponent + ( 1 << 14 ) ) {
335333 exponent = EXPONENT_MIN ;
336334 } else {
337335 exponent = exponent - radixPosition ;
@@ -341,11 +339,9 @@ export class Decimal128 extends BSONValue {
341339 while ( exponent > EXPONENT_MAX ) {
342340 // Shift exponent to significand and decrease
343341 lastDigit = lastDigit + 1 ;
344-
345- if ( lastDigit - firstDigit > MAX_DIGITS ) {
342+ if ( lastDigit >= MAX_DIGITS ) {
346343 // 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 ) {
349345 exponent = EXPONENT_MAX ;
350346 break ;
351347 }
@@ -357,85 +353,57 @@ export class Decimal128 extends BSONValue {
357353
358354 while ( exponent < EXPONENT_MIN || nDigitsStored < nDigits ) {
359355 // 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' ) ;
364363 }
365364
366365 if ( nDigitsStored < nDigits ) {
366+ if (
367+ representation [ nDigits - 1 + Number ( sawSign ) + Number ( sawRadix ) ] !== '0' &&
368+ significantDigits !== 0
369+ ) {
370+ invalidErr ( representation , 'inexact rounding' ) ;
371+ }
367372 // adjust to match digits not stored
368373 nDigits = nDigits - 1 ;
369374 } else {
375+ if ( digits [ lastDigit ] !== 0 ) {
376+ invalidErr ( representation , 'inexact rounding' ) ;
377+ }
370378 // adjust to round
371379 lastDigit = lastDigit - 1 ;
372380 }
373381
374382 if ( exponent < EXPONENT_MAX ) {
375383 exponent = exponent + 1 ;
376384 } 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- }
383385 invalidErr ( representation , 'overflow' ) ;
384386 }
385387 }
386388
387389 // Round
388390 // 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 ) {
392392 // If we have seen a radix point, 'string' is 1 longer than we have
393393 // documented with ndigits_read, so inc the position of the first nonzero
394394 // digit and the position that digits are read to.
395395 if ( sawRadix ) {
396396 firstNonZero = firstNonZero + 1 ;
397- endOfString = endOfString + 1 ;
398397 }
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 ) {
401400 firstNonZero = firstNonZero + 1 ;
402- endOfString = endOfString + 1 ;
403401 }
404402
405403 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- }
420404
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' ) ;
439407 }
440408 }
441409
@@ -449,8 +417,8 @@ export class Decimal128 extends BSONValue {
449417 if ( significantDigits === 0 ) {
450418 significandHigh = Long . fromNumber ( 0 ) ;
451419 significandLow = Long . fromNumber ( 0 ) ;
452- } else if ( lastDigit - firstDigit < 17 ) {
453- let dIdx = firstDigit ;
420+ } else if ( lastDigit < 17 ) {
421+ let dIdx = 0 ;
454422 significandLow = Long . fromNumber ( digits [ dIdx ++ ] ) ;
455423 significandHigh = new Long ( 0 , 0 ) ;
456424
@@ -459,7 +427,7 @@ export class Decimal128 extends BSONValue {
459427 significandLow = significandLow . add ( Long . fromNumber ( digits [ dIdx ] ) ) ;
460428 }
461429 } else {
462- let dIdx = firstDigit ;
430+ let dIdx = 0 ;
463431 significandHigh = Long . fromNumber ( digits [ dIdx ++ ] ) ;
464432
465433 for ( ; dIdx <= lastDigit - 17 ; dIdx ++ ) {
0 commit comments