in commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/Fraction.java [158:267]
private Fraction(final double value,
final double epsilon,
final int maxDenominator,
final int maxIterations) {
if (!Double.isFinite(value)) {
throw new IllegalArgumentException(NOT_FINITE + value);
}
// Remove sign, this is restored at the end.
// (Assumes the value is not zero and thus signum(value) is not zero).
final double absValue = Math.abs(value);
double r0 = absValue;
long a0 = (long) Math.floor(r0);
if (a0 > OVERFLOW) {
throw new FractionException(FractionException.ERROR_CONVERSION_OVERFLOW, value, a0, 1);
}
// check for (almost) integer arguments, which should not go to iterations.
if (r0 - a0 <= epsilon) {
int num = (int) a0;
int den = 1;
// Restore the sign.
if (Math.signum(num) != Math.signum(value)) {
if (num == Integer.MIN_VALUE) {
den = -den;
} else {
num = -num;
}
}
this.numerator = num;
this.denominator = den;
return;
}
// Support 2^31 as maximum denominator.
// This is negative as an integer so convert to long.
final long maxDen = Math.abs((long) maxDenominator);
long p0 = 1;
long q0 = 0;
long p1 = a0;
long q1 = 1;
long p2;
long q2;
int n = 0;
boolean stop = false;
do {
++n;
final double r1 = 1.0 / (r0 - a0);
final long a1 = (long) Math.floor(r1);
p2 = (a1 * p1) + p0;
q2 = (a1 * q1) + q0;
if (Long.compareUnsigned(p2, OVERFLOW) > 0 ||
Long.compareUnsigned(q2, OVERFLOW) > 0) {
// In maxDenominator mode, fall-back to the previous valid fraction.
if (epsilon == 0.0) {
p2 = p1;
q2 = q1;
break;
}
throw new FractionException(FractionException.ERROR_CONVERSION_OVERFLOW, value, p2, q2);
}
final double convergent = (double) p2 / (double) q2;
if (n < maxIterations &&
Math.abs(convergent - absValue) > epsilon &&
q2 < maxDen) {
p0 = p1;
p1 = p2;
q0 = q1;
q1 = q2;
a0 = a1;
r0 = r1;
} else {
stop = true;
}
} while (!stop);
if (n >= maxIterations) {
throw new FractionException(FractionException.ERROR_CONVERSION, value, maxIterations);
}
// Use p2 / q2 or p1 / q1 if q2 has grown too large in maxDenominator mode
// Note: Conversion of long 2^31 to an integer will create a negative. This could
// be either the numerator or denominator. This is handled by restoring the sign.
int num;
int den;
if (q2 <= maxDen) {
num = (int) p2;
den = (int) q2;
} else {
num = (int) p1;
den = (int) q1;
}
// Restore the sign.
if (Math.signum(num) * Math.signum(den) != Math.signum(value)) {
if (num == Integer.MIN_VALUE) {
den = -den;
} else {
num = -num;
}
}
this.numerator = num;
this.denominator = den;
}