I've been attempting to convert a decimal number to a rational, where the decimal is an instance of BigDecimal
. This works perfectly find for all terminating decimals, however non-terminating decimals cause rounding errors, and I don't know how to fix them.
The Code To Produce a Fraction:
public static Fraction of(BigDecimal bigDecimal, int decimalCutoff) {
bigDecimal = bigDecimal.stripTrailingZeros(); //Get rid of excess zeros
int n = 0; //Set up exponent
while (!PlasmaBigMathUtil.isInteger(bigDecimal) && n <= decimalCutoff) { //Loop through and build up the exponent
n++;
}
return new Fraction(bigDecimal.scaleByPowerOfTen(n).toBigInteger(), BigDecimal.ONE.scaleByPowerOfTen(n).toBigInteger()); //Return the decimal*10^n over 10^n
}
All tests for terminating fractions function as expected, and the isInteger
method works fine. The problem is that when inputting something like 1/3
(3.33...
), it outputs 3333333333333333/10000000000000000
(33333333333333330000000000000000000000000000000000000000000000000000000000000000000000000000000000000/100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
un-reduced).
The reduce method is as follows:
public void reduce() {
BigInteger greater = PlasmaBigMathUtil.greatestCommonFactor(this.numerator, this.denominator);
this.numerator = this.numerator.divide(greater);
this.denominator = this.denominator.divide(greater);
}
And the greatest common factor is implemented like so (using Euclid's Algorithm) :
public static BigInteger greatestCommonFactor(BigInteger a, BigInteger b) {
a = a.abs();
b = b.abs();
return b.equals(BigInteger.ZERO) ? a : PlasmaBigMathUtil.greatestCommonFactor(b, a.mod(b));
}
I expect there is some check I can do, or some rounding case I can handle to properly convert 1/3
to, well, 1/3
, but I'm unsure of what that is. Any help would be greatly appreciated.