-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cannot scale a BigInt by a real number #44874
Comments
Dart doesn't have overloading, so since You can scale a bigint, b, by any rational number, p/q, by doing |
@lrhn Thanks. To address your points:
Your solution is useful in a fixed scenario but non-trivial in the general case. I'll have a play around with it, but my original point still stands: this should be built in to |
This is my implementation, fwiw: extension BigIntExtensions on BigInt {
BigInt scale(double scale) {
final decimalPlacesInScale = _getDecimalPlacesIn(scale);
final scaleDenominator = math.pow(10, decimalPlacesInScale);
final scaleNumerator = scale * scaleDenominator;
final result = this * BigInt.from(scaleNumerator) ~/ BigInt.from(scaleDenominator);
return result;
}
static int _getDecimalPlacesIn(double value) {
value = value.abs();
value -= value.toInt();
var result = 0;
while (value != 0) {
value *= 10;
value -= value.toInt();
++result;
}
return result;
}
} I've tested this fairly well, but am quite sure it will have some edge cases wrt larger inputs and scales. It also kinda sux in terms of performance, given the way |
The idea is sound, there are some edge cases. You're effectively converting the double to a rational of two integers. That's not safe, you should be using BigInt scale(double scale) {
if (!scale.isFinite) throw ArgumentError.value(scale, "scale", "Must be a finite value");
var value = this;
if (scale.isNegative) {
scale = -scale;
value = -value;
}
var exponent = 0;
while (scale < 0x10000000000000 /*2^52*/) {
// Potential fractional part.
scale *= 0x100000000;
exponent += 32;
}
return (value * BigInt.from(scale)) >> exponent;
} That is, find exponent such that It's probably possible to be more efficient by reading bits directly from the double - create a double with the same mantissa, but an exponent putting all significant bits above 0.5, and the inverse exponent needed to do the reverse division. |
There is the question of whether one should scale a
Scaling a extension BigIntExtensions on BigInt {
BigInt scale(double scale) {
if (!scale.isFinite) throw ArgumentError.value(scale, "scale", "Must be a finite value");
var value = this;
if (scale.isNegative) {
scale = -scale;
value = -value;
}
var exponent = 0;
while (scale < 0x10000000000000 /*2^52*/) {
// Potential fractional part.
scale *= 0x100000000;
exponent += 32;
}
return (value * BigInt.from(scale)) >> exponent;
}
}
main() {
final n = BigInt.parse('1' + '0' * 50);
print(n);
print(n.scale(1.5));
print(n.scale(1.6));
print(n.scale(1.7));
}
Whether this matters to depends on why If |
It does not seem possible to multiply a
BigInt
by a real number factor. For example, if I have:The final line does not compile because the
*
operator is only able to multiply oneBigInt
by another. Convertingfactor
to aBigInt
will fix the compilation error but break the intent, since it will truncatefactor
to the nearest integral value. I need the truncation to occur after the multiplication of the underlying value by the factor.Unless I'm missing something, there is no way to scale the
BigInt
value by some non-integral factor.The text was updated successfully, but these errors were encountered: