@@ 130-503 (lines=374) @@ | ||
127 | this.bytes = bytes; |
|
128 | } |
|
129 | ||
130 | 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]; |
|
164 | // The low 17 digits of the significand |
|
165 | var significandLow = [0, 0]; |
|
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; |
|
500 | ||
501 | // Return the new Decimal128 |
|
502 | return new Decimal128(buffer); |
|
503 | } |
|
504 | ||
505 | // Extract least significant 5 bits |
|
506 | var COMBINATION_MASK = 0x1f; |
@@ 13243-13613 (lines=371) @@ | ||
13240 | this.bytes = bytes; |
|
13241 | }; |
|
13242 | ||
13243 | Decimal128.fromString = function (string) { |
|
13244 | // Parse state tracking |
|
13245 | var isNegative = false; |
|
13246 | var sawRadix = false; |
|
13247 | var foundNonZero = false; |
|
13248 | ||
13249 | // Total number of significant digits (no leading or trailing zero) |
|
13250 | var significantDigits = 0; |
|
13251 | // Total number of significand digits read |
|
13252 | var nDigitsRead = 0; |
|
13253 | // Total number of digits (no leading zeros) |
|
13254 | var nDigits = 0; |
|
13255 | // The number of the digits after radix |
|
13256 | var radixPosition = 0; |
|
13257 | // The index of the first non-zero in *str* |
|
13258 | var firstNonZero = 0; |
|
13259 | ||
13260 | // Digits Array |
|
13261 | var digits = [0]; |
|
13262 | // The number of digits in digits |
|
13263 | var nDigitsStored = 0; |
|
13264 | // Insertion pointer for digits |
|
13265 | var digitsInsert = 0; |
|
13266 | // The index of the first non-zero digit |
|
13267 | var firstDigit = 0; |
|
13268 | // The index of the last digit |
|
13269 | var lastDigit = 0; |
|
13270 | ||
13271 | // Exponent |
|
13272 | var exponent = 0; |
|
13273 | // loop index over array |
|
13274 | var i = 0; |
|
13275 | // The high 17 digits of the significand |
|
13276 | var significandHigh = [0, 0]; |
|
13277 | // The low 17 digits of the significand |
|
13278 | var significandLow = [0, 0]; |
|
13279 | // The biased exponent |
|
13280 | var biasedExponent = 0; |
|
13281 | ||
13282 | // Read index |
|
13283 | var index = 0; |
|
13284 | ||
13285 | // Trim the string |
|
13286 | string = string.trim(); |
|
13287 | ||
13288 | // Results |
|
13289 | var stringMatch = string.match(PARSE_STRING_REGEXP); |
|
13290 | var infMatch = string.match(PARSE_INF_REGEXP); |
|
13291 | var nanMatch = string.match(PARSE_NAN_REGEXP); |
|
13292 | ||
13293 | // Validate the string |
|
13294 | if (!stringMatch && !infMatch && !nanMatch || string.length == 0) { |
|
13295 | throw new Error("" + string + " not a valid Decimal128 string"); |
|
13296 | } |
|
13297 | ||
13298 | // Check if we have an illegal exponent format |
|
13299 | if (stringMatch && stringMatch[4] && stringMatch[2] === undefined) { |
|
13300 | throw new Error("" + string + " not a valid Decimal128 string"); |
|
13301 | } |
|
13302 | ||
13303 | // Get the negative or positive sign |
|
13304 | if (string[index] == '+' || string[index] == '-') { |
|
13305 | isNegative = string[index++] == '-'; |
|
13306 | } |
|
13307 | ||
13308 | // Check if user passed Infinity or NaN |
|
13309 | if (!isDigit(string[index]) && string[index] != '.') { |
|
13310 | if (string[index] == 'i' || string[index] == 'I') { |
|
13311 | return new Decimal128(new Buffer(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER)); |
|
13312 | } else if (string[index] == 'N') { |
|
13313 | return new Decimal128(new Buffer(NAN_BUFFER)); |
|
13314 | } |
|
13315 | } |
|
13316 | ||
13317 | // Read all the digits |
|
13318 | while (isDigit(string[index]) || string[index] == '.') { |
|
13319 | if (string[index] == '.') { |
|
13320 | if (sawRadix) { |
|
13321 | return new Decimal128(new Buffer(NAN_BUFFER)); |
|
13322 | } |
|
13323 | ||
13324 | sawRadix = true; |
|
13325 | index = index + 1; |
|
13326 | continue; |
|
13327 | } |
|
13328 | ||
13329 | if (nDigitsStored < 34) { |
|
13330 | if (string[index] != '0' || foundNonZero) { |
|
13331 | if (!foundNonZero) { |
|
13332 | firstNonZero = nDigitsRead; |
|
13333 | } |
|
13334 | ||
13335 | foundNonZero = true; |
|
13336 | ||
13337 | // Only store 34 digits |
|
13338 | digits[digitsInsert++] = parseInt(string[index], 10); |
|
13339 | nDigitsStored = nDigitsStored + 1; |
|
13340 | } |
|
13341 | } |
|
13342 | ||
13343 | if (foundNonZero) { |
|
13344 | nDigits = nDigits + 1; |
|
13345 | } |
|
13346 | ||
13347 | if (sawRadix) { |
|
13348 | radixPosition = radixPosition + 1; |
|
13349 | } |
|
13350 | ||
13351 | nDigitsRead = nDigitsRead + 1; |
|
13352 | index = index + 1; |
|
13353 | } |
|
13354 | ||
13355 | if (sawRadix && !nDigitsRead) { |
|
13356 | throw new Error("" + string + " not a valid Decimal128 string"); |
|
13357 | } |
|
13358 | ||
13359 | // Read exponent if exists |
|
13360 | if (string[index] == 'e' || string[index] == 'E') { |
|
13361 | // Read exponent digits |
|
13362 | var match = string.substr(++index).match(EXPONENT_REGEX); |
|
13363 | ||
13364 | // No digits read |
|
13365 | if (!match || !match[2]) { |
|
13366 | return new Decimal128(new Buffer(NAN_BUFFER)); |
|
13367 | } |
|
13368 | ||
13369 | // Get exponent |
|
13370 | exponent = parseInt(match[0], 10); |
|
13371 | ||
13372 | // Adjust the index |
|
13373 | index = index + match[0].length; |
|
13374 | } |
|
13375 | ||
13376 | // Return not a number |
|
13377 | if (string[index]) { |
|
13378 | return new Decimal128(new Buffer(NAN_BUFFER)); |
|
13379 | } |
|
13380 | ||
13381 | // Done reading input |
|
13382 | // Find first non-zero digit in digits |
|
13383 | firstDigit = 0; |
|
13384 | ||
13385 | if (!nDigitsStored) { |
|
13386 | firstDigit = 0; |
|
13387 | lastDigit = 0; |
|
13388 | digits[0] = 0; |
|
13389 | nDigits = 1; |
|
13390 | nDigitsStored = 1; |
|
13391 | significantDigits = 0; |
|
13392 | } else { |
|
13393 | lastDigit = nDigitsStored - 1; |
|
13394 | significantDigits = nDigits; |
|
13395 | ||
13396 | if (exponent != 0 && significantDigits != 1) { |
|
13397 | while (string[firstNonZero + significantDigits - 1] == '0') { |
|
13398 | significantDigits = significantDigits - 1; |
|
13399 | } |
|
13400 | } |
|
13401 | } |
|
13402 | ||
13403 | // Normalization of exponent |
|
13404 | // Correct exponent based on radix position, and shift significand as needed |
|
13405 | // to represent user input |
|
13406 | ||
13407 | // Overflow prevention |
|
13408 | if (exponent <= radixPosition && radixPosition - exponent > 1 << 14) { |
|
13409 | exponent = EXPONENT_MIN; |
|
13410 | } else { |
|
13411 | exponent = exponent - radixPosition; |
|
13412 | } |
|
13413 | ||
13414 | // Attempt to normalize the exponent |
|
13415 | while (exponent > EXPONENT_MAX) { |
|
13416 | // Shift exponent to significand and decrease |
|
13417 | lastDigit = lastDigit + 1; |
|
13418 | ||
13419 | if (lastDigit - firstDigit > MAX_DIGITS) { |
|
13420 | // Check if we have a zero then just hard clamp, otherwise fail |
|
13421 | var digitsString = digits.join(''); |
|
13422 | if (digitsString.match(/^0+$/)) { |
|
13423 | exponent = EXPONENT_MAX; |
|
13424 | break; |
|
13425 | } else { |
|
13426 | return new Decimal128(new Buffer(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER)); |
|
13427 | } |
|
13428 | } |
|
13429 | ||
13430 | exponent = exponent - 1; |
|
13431 | } |
|
13432 | ||
13433 | while (exponent < EXPONENT_MIN || nDigitsStored < nDigits) { |
|
13434 | // Shift last digit |
|
13435 | if (lastDigit == 0) { |
|
13436 | exponent = EXPONENT_MIN; |
|
13437 | significantDigits = 0; |
|
13438 | break; |
|
13439 | } |
|
13440 | ||
13441 | if (nDigitsStored < nDigits) { |
|
13442 | // adjust to match digits not stored |
|
13443 | nDigits = nDigits - 1; |
|
13444 | } else { |
|
13445 | // adjust to round |
|
13446 | lastDigit = lastDigit - 1; |
|
13447 | } |
|
13448 | ||
13449 | if (exponent < EXPONENT_MAX) { |
|
13450 | exponent = exponent + 1; |
|
13451 | } else { |
|
13452 | // Check if we have a zero then just hard clamp, otherwise fail |
|
13453 | var digitsString = digits.join(''); |
|
13454 | if (digitsString.match(/^0+$/)) { |
|
13455 | exponent = EXPONENT_MAX; |
|
13456 | break; |
|
13457 | } else { |
|
13458 | return new Decimal128(new Buffer(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER)); |
|
13459 | } |
|
13460 | } |
|
13461 | } |
|
13462 | ||
13463 | // Round |
|
13464 | // We've normalized the exponent, but might still need to round. |
|
13465 | if (lastDigit - firstDigit + 1 < significantDigits && string[significantDigits] != '0') { |
|
13466 | var endOfString = nDigitsRead; |
|
13467 | ||
13468 | // If we have seen a radix point, 'string' is 1 longer than we have |
|
13469 | // documented with ndigits_read, so inc the position of the first nonzero |
|
13470 | // digit and the position that digits are read to. |
|
13471 | if (sawRadix && exponent == EXPONENT_MIN) { |
|
13472 | firstNonZero = firstNonZero + 1; |
|
13473 | endOfString = endOfString + 1; |
|
13474 | } |
|
13475 | ||
13476 | var roundDigit = parseInt(string[firstNonZero + lastDigit + 1], 10); |
|
13477 | var roundBit = 0; |
|
13478 | ||
13479 | if (roundDigit >= 5) { |
|
13480 | roundBit = 1; |
|
13481 | ||
13482 | if (roundDigit == 5) { |
|
13483 | roundBit = digits[lastDigit] % 2 == 1; |
|
13484 | ||
13485 | for (var i = firstNonZero + lastDigit + 2; i < endOfString; i++) { |
|
13486 | if (parseInt(string[i], 10)) { |
|
13487 | roundBit = 1; |
|
13488 | break; |
|
13489 | } |
|
13490 | } |
|
13491 | } |
|
13492 | } |
|
13493 | ||
13494 | if (roundBit) { |
|
13495 | var dIdx = lastDigit; |
|
13496 | ||
13497 | for (; dIdx >= 0; dIdx--) { |
|
13498 | if (++digits[dIdx] > 9) { |
|
13499 | digits[dIdx] = 0; |
|
13500 | ||
13501 | // overflowed most significant digit |
|
13502 | if (dIdx == 0) { |
|
13503 | if (exponent < EXPONENT_MAX) { |
|
13504 | exponent = exponent + 1; |
|
13505 | digits[dIdx] = 1; |
|
13506 | } else { |
|
13507 | return new Decimal128(new Buffer(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER)); |
|
13508 | } |
|
13509 | } |
|
13510 | } else { |
|
13511 | break; |
|
13512 | } |
|
13513 | } |
|
13514 | } |
|
13515 | } |
|
13516 | ||
13517 | // Encode significand |
|
13518 | // The high 17 digits of the significand |
|
13519 | significandHigh = Long.fromNumber(0); |
|
13520 | // The low 17 digits of the significand |
|
13521 | significandLow = Long.fromNumber(0); |
|
13522 | ||
13523 | // read a zero |
|
13524 | if (significantDigits == 0) { |
|
13525 | significandHigh = Long.fromNumber(0); |
|
13526 | significandLow = Long.fromNumber(0); |
|
13527 | } else if (lastDigit - firstDigit < 17) { |
|
13528 | var dIdx = firstDigit; |
|
13529 | significandLow = Long.fromNumber(digits[dIdx++]); |
|
13530 | significandHigh = new Long(0, 0); |
|
13531 | ||
13532 | for (; dIdx <= lastDigit; dIdx++) { |
|
13533 | significandLow = significandLow.multiply(Long.fromNumber(10)); |
|
13534 | significandLow = significandLow.add(Long.fromNumber(digits[dIdx])); |
|
13535 | } |
|
13536 | } else { |
|
13537 | var dIdx = firstDigit; |
|
13538 | significandHigh = Long.fromNumber(digits[dIdx++]); |
|
13539 | ||
13540 | for (; dIdx <= lastDigit - 17; dIdx++) { |
|
13541 | significandHigh = significandHigh.multiply(Long.fromNumber(10)); |
|
13542 | significandHigh = significandHigh.add(Long.fromNumber(digits[dIdx])); |
|
13543 | } |
|
13544 | ||
13545 | significandLow = Long.fromNumber(digits[dIdx++]); |
|
13546 | ||
13547 | for (; dIdx <= lastDigit; dIdx++) { |
|
13548 | significandLow = significandLow.multiply(Long.fromNumber(10)); |
|
13549 | significandLow = significandLow.add(Long.fromNumber(digits[dIdx])); |
|
13550 | } |
|
13551 | } |
|
13552 | ||
13553 | var significand = multiply64x2(significandHigh, Long.fromString("100000000000000000")); |
|
13554 | ||
13555 | significand.low = significand.low.add(significandLow); |
|
13556 | ||
13557 | if (lessThan(significand.low, significandLow)) { |
|
13558 | significand.high = significand.high.add(Long.fromNumber(1)); |
|
13559 | } |
|
13560 | ||
13561 | // Biased exponent |
|
13562 | var biasedExponent = exponent + EXPONENT_BIAS; |
|
13563 | var dec = { low: Long.fromNumber(0), high: Long.fromNumber(0) }; |
|
13564 | ||
13565 | // Encode combination, exponent, and significand. |
|
13566 | if (significand.high.shiftRightUnsigned(49).and(Long.fromNumber(1)).equals(Long.fromNumber)) { |
|
13567 | // Encode '11' into bits 1 to 3 |
|
13568 | dec.high = dec.high.or(Long.fromNumber(0x3).shiftLeft(61)); |
|
13569 | dec.high = dec.high.or(Long.fromNumber(biasedExponent).and(Long.fromNumber(0x3fff).shiftLeft(47))); |
|
13570 | dec.high = dec.high.or(significand.high.and(Long.fromNumber(0x7fffffffffff))); |
|
13571 | } else { |
|
13572 | dec.high = dec.high.or(Long.fromNumber(biasedExponent & 0x3fff).shiftLeft(49)); |
|
13573 | dec.high = dec.high.or(significand.high.and(Long.fromNumber(0x1ffffffffffff))); |
|
13574 | } |
|
13575 | ||
13576 | dec.low = significand.low; |
|
13577 | ||
13578 | // Encode sign |
|
13579 | if (isNegative) { |
|
13580 | dec.high = dec.high.or(Long.fromString('9223372036854775808')); |
|
13581 | } |
|
13582 | ||
13583 | // Encode into a buffer |
|
13584 | var buffer = new Buffer(16); |
|
13585 | var index = 0; |
|
13586 | ||
13587 | // Encode the low 64 bits of the decimal |
|
13588 | // Encode low bits |
|
13589 | buffer[index++] = dec.low.low_ & 0xff; |
|
13590 | buffer[index++] = dec.low.low_ >> 8 & 0xff; |
|
13591 | buffer[index++] = dec.low.low_ >> 16 & 0xff; |
|
13592 | buffer[index++] = dec.low.low_ >> 24 & 0xff; |
|
13593 | // Encode high bits |
|
13594 | buffer[index++] = dec.low.high_ & 0xff; |
|
13595 | buffer[index++] = dec.low.high_ >> 8 & 0xff; |
|
13596 | buffer[index++] = dec.low.high_ >> 16 & 0xff; |
|
13597 | buffer[index++] = dec.low.high_ >> 24 & 0xff; |
|
13598 | ||
13599 | // Encode the high 64 bits of the decimal |
|
13600 | // Encode low bits |
|
13601 | buffer[index++] = dec.high.low_ & 0xff; |
|
13602 | buffer[index++] = dec.high.low_ >> 8 & 0xff; |
|
13603 | buffer[index++] = dec.high.low_ >> 16 & 0xff; |
|
13604 | buffer[index++] = dec.high.low_ >> 24 & 0xff; |
|
13605 | // Encode high bits |
|
13606 | buffer[index++] = dec.high.high_ & 0xff; |
|
13607 | buffer[index++] = dec.high.high_ >> 8 & 0xff; |
|
13608 | buffer[index++] = dec.high.high_ >> 16 & 0xff; |
|
13609 | buffer[index++] = dec.high.high_ >> 24 & 0xff; |
|
13610 | ||
13611 | // Return the new Decimal128 |
|
13612 | return new Decimal128(buffer); |
|
13613 | }; |
|
13614 | ||
13615 | // Extract least significant 5 bits |
|
13616 | var COMBINATION_MASK = 0x1f; |