diff --git a/src/main/java/org/apache/commons/lang3/math/Fraction.java b/src/main/java/org/apache/commons/lang3/math/Fraction.java index cb18b130d17..95f40dc3453 100644 --- a/src/main/java/org/apache/commons/lang3/math/Fraction.java +++ b/src/main/java/org/apache/commons/lang3/math/Fraction.java @@ -551,10 +551,10 @@ private Fraction addSub(final Fraction fraction, final boolean isAdd) { Objects.requireNonNull(fraction, "fraction"); // zero is identity for addition. if (numerator == 0) { - return isAdd ? fraction : fraction.negate(); + return isAdd ? fraction.reduce() : fraction.reduce().negate(); } if (fraction.numerator == 0) { - return this; + return reduce(); } // Knuth 4.5.1 assumes operands in lowest terms and this class does not reduce on // construction, so reduce both first, as multiplyBy does. diff --git a/src/test/java/org/apache/commons/lang3/math/FractionTest.java b/src/test/java/org/apache/commons/lang3/math/FractionTest.java index 57ec9d3a47b..a3d4c9ed2f1 100644 --- a/src/test/java/org/apache/commons/lang3/math/FractionTest.java +++ b/src/test/java/org/apache/commons/lang3/math/FractionTest.java @@ -118,6 +118,34 @@ void testAddSubtractUnreducedOperands() { assertThrows(ArithmeticException.class, () -> maxValue.add(maxValue)); } + @Test + void testAddSubtractZeroOperand() { + // A zero operand returns the other operand in reduced form. + Fraction f = Fraction.ZERO.add(Fraction.getFraction(2, 4)); + assertEquals(1, f.getNumerator()); + assertEquals(2, f.getDenominator()); + + f = Fraction.getFraction(2, 4).add(Fraction.ZERO); + assertEquals(1, f.getNumerator()); + assertEquals(2, f.getDenominator()); + + f = Fraction.ZERO.subtract(Fraction.getFraction(2, 4)); + assertEquals(-1, f.getNumerator()); + assertEquals(2, f.getDenominator()); + + f = Fraction.getFraction(2, 4).subtract(Fraction.ZERO); + assertEquals(1, f.getNumerator()); + assertEquals(2, f.getDenominator()); + + // Integer.MIN_VALUE/2 reduces to -1073741824/1, whose negation fits an int. + f = Fraction.ZERO.subtract(Fraction.getFraction(Integer.MIN_VALUE, 2)); + assertEquals(1073741824, f.getNumerator()); + assertEquals(1, f.getDenominator()); + + // Integer.MIN_VALUE/1 is in lowest terms and still cannot be negated. + assertThrows(ArithmeticException.class, () -> Fraction.ZERO.subtract(Fraction.getFraction(Integer.MIN_VALUE, 1))); + } + @Test void testAdd() { Fraction f;