in rhino/src/main/java/org/mozilla/javascript/ScriptRuntime.java [443:579]
private static double stringToNumber(
String source, int sourceStart, int sourceEnd, int radix, boolean isPrefix) {
char digitMax = '9';
char lowerCaseBound = 'a';
char upperCaseBound = 'A';
if (radix < 10) {
digitMax = (char) ('0' + radix - 1);
}
if (radix > 10) {
lowerCaseBound = (char) ('a' + radix - 10);
upperCaseBound = (char) ('A' + radix - 10);
}
int end;
double sum = 0.0;
for (end = sourceStart; end <= sourceEnd; end++) {
char c = source.charAt(end);
int newDigit;
if ('0' <= c && c <= digitMax) newDigit = c - '0';
else if ('a' <= c && c < lowerCaseBound) newDigit = c - 'a' + 10;
else if ('A' <= c && c < upperCaseBound) newDigit = c - 'A' + 10;
else if (!isPrefix) return NaN; // isn't a prefix but found unexpected char
else break; // unexpected char
sum = sum * radix + newDigit;
}
if (sourceStart == end) { // stopped right at the beginning
return NaN;
}
if (sum > NativeNumber.MAX_SAFE_INTEGER) {
if (radix == 10) {
/* If we're accumulating a decimal number and the number
* is >= 2^53, then the result from the repeated multiply-add
* above may be inaccurate. Call Java to get the correct
* answer.
*/
try {
return Double.parseDouble(source.substring(sourceStart, end));
} catch (NumberFormatException nfe) {
return NaN;
}
} else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32) {
/* The number may also be inaccurate for one of these bases.
* This happens if the addition in value*radix + digit causes
* a round-down to an even least significant mantissa bit
* when the first dropped bit is a one. If any of the
* following digits in the number (which haven't been added
* in yet) are nonzero then the correct action would have
* been to round up instead of down. An example of this
* occurs when reading the number 0x1000000000000081, which
* rounds to 0x1000000000000000 instead of 0x1000000000000100.
*/
int bitShiftInChar = 1;
int digit = 0;
final int SKIP_LEADING_ZEROS = 0;
final int FIRST_EXACT_53_BITS = 1;
final int AFTER_BIT_53 = 2;
final int ZEROS_AFTER_54 = 3;
final int MIXED_AFTER_54 = 4;
int state = SKIP_LEADING_ZEROS;
int exactBitsLimit = 53;
double factor = 0.0;
boolean bit53 = false;
// bit54 is the 54th bit (the first dropped from the mantissa)
boolean bit54 = false;
int pos = sourceStart;
for (; ; ) {
if (bitShiftInChar == 1) {
if (pos == end) break;
digit = source.charAt(pos++);
if ('0' <= digit && digit <= '9') digit -= '0';
else if ('a' <= digit && digit <= 'z') digit -= 'a' - 10;
else digit -= 'A' - 10;
bitShiftInChar = radix;
}
bitShiftInChar >>= 1;
boolean bit = (digit & bitShiftInChar) != 0;
switch (state) {
case SKIP_LEADING_ZEROS:
if (bit) {
--exactBitsLimit;
sum = 1.0;
state = FIRST_EXACT_53_BITS;
}
break;
case FIRST_EXACT_53_BITS:
sum *= 2.0;
if (bit) sum += 1.0;
--exactBitsLimit;
if (exactBitsLimit == 0) {
bit53 = bit;
state = AFTER_BIT_53;
}
break;
case AFTER_BIT_53:
bit54 = bit;
factor = 2.0;
state = ZEROS_AFTER_54;
break;
case ZEROS_AFTER_54:
if (bit) {
state = MIXED_AFTER_54;
}
// fallthrough
case MIXED_AFTER_54:
factor *= 2;
break;
}
}
switch (state) {
case SKIP_LEADING_ZEROS:
sum = 0.0;
break;
case FIRST_EXACT_53_BITS:
case AFTER_BIT_53:
// do nothing
break;
case ZEROS_AFTER_54:
// x1.1 -> x1 + 1 (round up)
// x0.1 -> x0 (round down)
if (bit54 && bit53) sum += 1.0;
sum *= factor;
break;
case MIXED_AFTER_54:
// x.100...1.. -> x + 1 (round up)
// x.0anything -> x (round down)
if (bit54) sum += 1.0;
sum *= factor;
break;
}
}
/* We don't worry about inaccurate numbers for any other base. */
}
return sum;
}