toStringAsPrecisionFast method
Provides a faster approach than the orginal method
Implementation
String toStringAsPrecisionFast(int requiredPrecision) {
assert(requiredPrecision > 0);
// this method is not able to manage rationals with infinite precision,
// so we transform all numbers with infinite precision into
// finite precision ones.
// It is not important to calculate the exact precision of the new
// number, what is fundament is that the new precision must not be lesser
// than the required one.
// The exact calculation will be done in the recursive call to
// this method.
if (!hasFinitePrecision) {
/// in case of fractional digits starting with many zeros,
/// we risk to loose precision, so, to compensate,
/// we add the denominator precision.
/// As there is not a precision method in the BigInt class
/// we use the shortcut of creating a string and calculating
/// the length. Maybe that there is a cleaner way,
var pwr = requiredPrecision + denominator.toRadixString(10).length;
var shifter = _r10.pow(pwr);
var rational = (this * shifter).round() / shifter;
return rational.toStringAsPrecisionFast(requiredPrecision);
}
/// The shift exponent is used to calculate the value of the number
/// to round in order to loose precision (if exceeding the required one)
///
/// `(precision - scale)`
/// here we calculate how many digits and in which direction we have to
/// move the fractional separator in order to obtain fields of the format
/// `0.xxxxxxx`
/// For example:
/// 1230 125.78 0.0034
/// ^ (4) ^ (3) (-2)^
/// (4-0=>4)(5-2=>3)(2-4=>-2)
/// .1230 .12578 .34
/// Now that we have the field in `0.xxxxx` format, we shift left for the
/// number of required precision digits.
/// For example:
/// Precision -> 3
/// .1230 .12578 .34
/// 123 125.78 340
/// Precision -> 1
/// .1230 .12578 .34
/// 1.230 1.2578 3.4
/// As the required precision augments the exponent that we calculate,
/// the previous calculation (precision - scale), that goes in the opposite
/// direction, must be subtracted.
/// The exponent for shifting the value is made by the formula:
/// `requiredPrecision - (precision - scale)`
var shiftExponent = requiredPrecision - (precision - scale);
Rational value;
if (shiftExponent == 0) {
/// No shifting needed
value = this;
} else {
/// given the exponent, we calculate the value to be used in order
/// to shift our number
var coefficient = _r10.power(shiftExponent);
/// here we shift the number and round, so that we loose the non required
/// precision digits (if any), and then we move back the digits in the
/// opposite direction.
value = (this * coefficient).round() / coefficient;
}
return shiftExponent <= 0
? value.toString()
: value.toStringAsFixed(shiftExponent);
}