Implementation
static Value fromDouble(double num) {
if (num == double.infinity) {
return fInfinity;
} else if (num == double.negativeInfinity) {
return fNegativeInfinity;
} else if (num.isNaN) {
return fInfinity;
}
// Slow but simple
final String s = num.toStringAsExponential(9);
BigInt mantissa = BigInt.zero;
// Huh! It looks like ints are limited to 32 bits under JS, at least
// as regards left-shift as of April 2021.
int i = 0;
while (true) {
final int c = s.codeUnitAt(i);
if (c == '-'.codeUnitAt(0)) {
assert(mantissa == BigInt.zero, "$c in '$s' at $i");
mantissa = BigInt.from(9);
} else if (c == '.'.codeUnitAt(0)) {
// do nothing
} else if (c == 'e'.codeUnitAt(0)) {
i++;
break;
} else {
final int d = c - '0'.codeUnitAt(0);
assert(d >= 0 && d < 10, '$d in "$s" at $i');
mantissa = (mantissa << 4) | BigInt.from(d);
}
i++;
}
assert(i >= 12 && i <= 13, '$i $s');
bool negativeExponent = false;
int exponent = 0;
while (i < s.length) {
final int c = s.codeUnitAt(i);
if (c == '-'.codeUnitAt(0)) {
assert(exponent == 0);
negativeExponent = true;
} else if (c == '+'.codeUnitAt(0)) {
assert(exponent == 0 && !negativeExponent);
// do nothing
} else {
final int d = c - '0'.codeUnitAt(0);
assert(d >= 0 && d < 10, 'for character ${s.substring(i, i + 1)}');
exponent = (exponent << 4) | d;
}
i++;
}
if (exponent >= 0x100) {
if (negativeExponent) {
return zero;
} else if (mantissa & _mantissaSign == BigInt.zero) {
// positive mantissa
return fInfinity;
} else {
return fNegativeInfinity;
}
} else if (negativeExponent) {
exponent = ((0x999 + 1) - exponent); // 1000's complement in BCD
}
if (mantissa == _mantissaSign) {
// -0.0, which the real calculator doesn't distinguish from 0.0
mantissa = BigInt.zero;
}
return Value._fromMantissaAndRawExponent(mantissa, exponent);
}