diff options
Diffstat (limited to 'src/test/java/org/apache/commons/lang3/math/FractionTest.java')
-rw-r--r-- | src/test/java/org/apache/commons/lang3/math/FractionTest.java | 1124 |
1 files changed, 1124 insertions, 0 deletions
diff --git a/src/test/java/org/apache/commons/lang3/math/FractionTest.java b/src/test/java/org/apache/commons/lang3/math/FractionTest.java new file mode 100644 index 000000000..269c14558 --- /dev/null +++ b/src/test/java/org/apache/commons/lang3/math/FractionTest.java @@ -0,0 +1,1124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.commons.lang3.math; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.apache.commons.lang3.AbstractLangTest; +import org.junit.jupiter.api.Test; + +/** + * Test cases for the {@link Fraction} class + */ +public class FractionTest extends AbstractLangTest { + + private static final int SKIP = 500; //53 + + @Test + public void testAbs() { + Fraction f; + + f = Fraction.getFraction(50, 75); + f = f.abs(); + assertEquals(50, f.getNumerator()); + assertEquals(75, f.getDenominator()); + + f = Fraction.getFraction(-50, 75); + f = f.abs(); + assertEquals(50, f.getNumerator()); + assertEquals(75, f.getDenominator()); + + f = Fraction.getFraction(Integer.MAX_VALUE, 1); + f = f.abs(); + assertEquals(Integer.MAX_VALUE, f.getNumerator()); + assertEquals(1, f.getDenominator()); + + f = Fraction.getFraction(Integer.MAX_VALUE, -1); + f = f.abs(); + assertEquals(Integer.MAX_VALUE, f.getNumerator()); + assertEquals(1, f.getDenominator()); + + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(Integer.MIN_VALUE, 1).abs()); + } + + @Test + public void testAdd() { + Fraction f; + Fraction f1; + Fraction f2; + + f1 = Fraction.getFraction(3, 5); + f2 = Fraction.getFraction(1, 5); + f = f1.add(f2); + assertEquals(4, f.getNumerator()); + assertEquals(5, f.getDenominator()); + + f1 = Fraction.getFraction(3, 5); + f2 = Fraction.getFraction(2, 5); + f = f1.add(f2); + assertEquals(1, f.getNumerator()); + assertEquals(1, f.getDenominator()); + + f1 = Fraction.getFraction(3, 5); + f2 = Fraction.getFraction(3, 5); + f = f1.add(f2); + assertEquals(6, f.getNumerator()); + assertEquals(5, f.getDenominator()); + + f1 = Fraction.getFraction(3, 5); + f2 = Fraction.getFraction(-4, 5); + f = f1.add(f2); + assertEquals(-1, f.getNumerator()); + assertEquals(5, f.getDenominator()); + + f1 = Fraction.getFraction(Integer.MAX_VALUE - 1, 1); + f2 = Fraction.ONE; + f = f1.add(f2); + assertEquals(Integer.MAX_VALUE, f.getNumerator()); + assertEquals(1, f.getDenominator()); + + f1 = Fraction.getFraction(3, 5); + f2 = Fraction.getFraction(1, 2); + f = f1.add(f2); + assertEquals(11, f.getNumerator()); + assertEquals(10, f.getDenominator()); + + f1 = Fraction.getFraction(3, 8); + f2 = Fraction.getFraction(1, 6); + f = f1.add(f2); + assertEquals(13, f.getNumerator()); + assertEquals(24, f.getDenominator()); + + f1 = Fraction.getFraction(0, 5); + f2 = Fraction.getFraction(1, 5); + f = f1.add(f2); + assertSame(f2, f); + f = f2.add(f1); + assertSame(f2, f); + + f1 = Fraction.getFraction(-1, 13*13*2*2); + f2 = Fraction.getFraction(-2, 13*17*2); + final Fraction fr = f1.add(f2); + assertEquals(13*13*17*2*2, fr.getDenominator()); + assertEquals(-17 - 2*13*2, fr.getNumerator()); + + assertThrows(NullPointerException.class, () -> fr.add(null)); + + // if this fraction is added naively, it will overflow. + // check that it doesn't. + f1 = Fraction.getFraction(1, 32768*3); + f2 = Fraction.getFraction(1, 59049); + f = f1.add(f2); + assertEquals(52451, f.getNumerator()); + assertEquals(1934917632, f.getDenominator()); + + f1 = Fraction.getFraction(Integer.MIN_VALUE, 3); + f2 = Fraction.ONE_THIRD; + f = f1.add(f2); + assertEquals(Integer.MIN_VALUE+1, f.getNumerator()); + assertEquals(3, f.getDenominator()); + + f1 = Fraction.getFraction(Integer.MAX_VALUE - 1, 1); + f2 = Fraction.ONE; + f = f1.add(f2); + assertEquals(Integer.MAX_VALUE, f.getNumerator()); + assertEquals(1, f.getDenominator()); + + final Fraction overflower = f; + assertThrows(ArithmeticException.class, () -> overflower.add(Fraction.ONE)); // should overflow + + // denominator should not be a multiple of 2 or 3 to trigger overflow + assertThrows( + ArithmeticException.class, + () -> Fraction.getFraction(Integer.MIN_VALUE, 5).add(Fraction.getFraction(-1, 5))); + + final Fraction maxValue = Fraction.getFraction(-Integer.MAX_VALUE, 1); + assertThrows(ArithmeticException.class, () -> maxValue.add(maxValue)); + + final Fraction negativeMaxValue = Fraction.getFraction(-Integer.MAX_VALUE, 1); + assertThrows(ArithmeticException.class, () -> negativeMaxValue.add(negativeMaxValue)); + + final Fraction f3 = Fraction.getFraction(3, 327680); + final Fraction f4 = Fraction.getFraction(2, 59049); + assertThrows(ArithmeticException.class, () -> f3.add(f4)); // should overflow + } + + @Test + public void testCompareTo() { + final Fraction f1; + Fraction f2; + + f1 = Fraction.getFraction(3, 5); + assertEquals(0, f1.compareTo(f1)); + + final Fraction fr = f1; + assertThrows(NullPointerException.class, () -> fr.compareTo(null)); + + f2 = Fraction.getFraction(2, 5); + assertTrue(f1.compareTo(f2) > 0); + assertEquals(0, f2.compareTo(f2)); + + f2 = Fraction.getFraction(4, 5); + assertTrue(f1.compareTo(f2) < 0); + assertEquals(0, f2.compareTo(f2)); + + f2 = Fraction.getFraction(3, 5); + assertEquals(0, f1.compareTo(f2)); + assertEquals(0, f2.compareTo(f2)); + + f2 = Fraction.getFraction(6, 10); + assertEquals(0, f1.compareTo(f2)); + assertEquals(0, f2.compareTo(f2)); + + f2 = Fraction.getFraction(-1, 1, Integer.MAX_VALUE); + assertTrue(f1.compareTo(f2) > 0); + assertEquals(0, f2.compareTo(f2)); + + } + + @Test + public void testConstants() { + assertEquals(0, Fraction.ZERO.getNumerator()); + assertEquals(1, Fraction.ZERO.getDenominator()); + + assertEquals(1, Fraction.ONE.getNumerator()); + assertEquals(1, Fraction.ONE.getDenominator()); + + assertEquals(1, Fraction.ONE_HALF.getNumerator()); + assertEquals(2, Fraction.ONE_HALF.getDenominator()); + + assertEquals(1, Fraction.ONE_THIRD.getNumerator()); + assertEquals(3, Fraction.ONE_THIRD.getDenominator()); + + assertEquals(2, Fraction.TWO_THIRDS.getNumerator()); + assertEquals(3, Fraction.TWO_THIRDS.getDenominator()); + + assertEquals(1, Fraction.ONE_QUARTER.getNumerator()); + assertEquals(4, Fraction.ONE_QUARTER.getDenominator()); + + assertEquals(2, Fraction.TWO_QUARTERS.getNumerator()); + assertEquals(4, Fraction.TWO_QUARTERS.getDenominator()); + + assertEquals(3, Fraction.THREE_QUARTERS.getNumerator()); + assertEquals(4, Fraction.THREE_QUARTERS.getDenominator()); + + assertEquals(1, Fraction.ONE_FIFTH.getNumerator()); + assertEquals(5, Fraction.ONE_FIFTH.getDenominator()); + + assertEquals(2, Fraction.TWO_FIFTHS.getNumerator()); + assertEquals(5, Fraction.TWO_FIFTHS.getDenominator()); + + assertEquals(3, Fraction.THREE_FIFTHS.getNumerator()); + assertEquals(5, Fraction.THREE_FIFTHS.getDenominator()); + + assertEquals(4, Fraction.FOUR_FIFTHS.getNumerator()); + assertEquals(5, Fraction.FOUR_FIFTHS.getDenominator()); + } + + @Test + public void testConversions() { + final Fraction f; + + f = Fraction.getFraction(3, 7, 8); + assertEquals(3, f.intValue()); + assertEquals(3L, f.longValue()); + assertEquals(3.875f, f.floatValue(), 0.00001f); + assertEquals(3.875d, f.doubleValue(), 0.00001d); + } + + @Test + public void testDivide() { + Fraction f; + Fraction f1; + Fraction f2; + + f1 = Fraction.getFraction(3, 5); + f2 = Fraction.getFraction(2, 5); + f = f1.divideBy(f2); + assertEquals(3, f.getNumerator()); + assertEquals(2, f.getDenominator()); + + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(3, 5).divideBy(Fraction.ZERO)); + + f1 = Fraction.getFraction(0, 5); + f2 = Fraction.getFraction(2, 7); + f = f1.divideBy(f2); + assertSame(Fraction.ZERO, f); + + f1 = Fraction.getFraction(2, 7); + f2 = Fraction.ONE; + f = f1.divideBy(f2); + assertEquals(2, f.getNumerator()); + assertEquals(7, f.getDenominator()); + + f1 = Fraction.getFraction(1, Integer.MAX_VALUE); + f = f1.divideBy(f1); + assertEquals(1, f.getNumerator()); + assertEquals(1, f.getDenominator()); + + f1 = Fraction.getFraction(Integer.MIN_VALUE, Integer.MAX_VALUE); + f2 = Fraction.getFraction(1, Integer.MAX_VALUE); + final Fraction fr = f1.divideBy(f2); + assertEquals(Integer.MIN_VALUE, fr.getNumerator()); + assertEquals(1, fr.getDenominator()); + + assertThrows(NullPointerException.class, () -> fr.divideBy(null)); + + final Fraction smallest = Fraction.getFraction(1, Integer.MAX_VALUE); + assertThrows(ArithmeticException.class, () -> smallest.divideBy(smallest.invert())); // Should overflow + + final Fraction negative = Fraction.getFraction(1, -Integer.MAX_VALUE); + assertThrows(ArithmeticException.class, () -> negative.divideBy(negative.invert())); // Should overflow + } + + + @Test + public void testEquals() { + Fraction f1; + Fraction f2; + + f1 = Fraction.getFraction(3, 5); + assertNotEquals(null, f1); + assertNotEquals(f1, new Object()); + assertNotEquals(f1, Integer.valueOf(6)); + + f1 = Fraction.getFraction(3, 5); + f2 = Fraction.getFraction(2, 5); + assertNotEquals(f1, f2); + assertEquals(f1, f1); + assertEquals(f2, f2); + + f2 = Fraction.getFraction(3, 5); + assertEquals(f1, f2); + + f2 = Fraction.getFraction(6, 10); + assertNotEquals(f1, f2); + } + + @Test + public void testFactory_double() { + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(Double.NaN)); + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(Double.POSITIVE_INFINITY)); + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(Double.NEGATIVE_INFINITY)); + assertThrows(ArithmeticException.class, () -> Fraction.getFraction((double) Integer.MAX_VALUE + 1)); + + // zero + Fraction f = Fraction.getFraction(0.0d); + assertEquals(0, f.getNumerator()); + assertEquals(1, f.getDenominator()); + + // one + f = Fraction.getFraction(1.0d); + assertEquals(1, f.getNumerator()); + assertEquals(1, f.getDenominator()); + + // one half + f = Fraction.getFraction(0.5d); + assertEquals(1, f.getNumerator()); + assertEquals(2, f.getDenominator()); + + // negative + f = Fraction.getFraction(-0.875d); + assertEquals(-7, f.getNumerator()); + assertEquals(8, f.getDenominator()); + + // over 1 + f = Fraction.getFraction(1.25d); + assertEquals(5, f.getNumerator()); + assertEquals(4, f.getDenominator()); + + // two thirds + f = Fraction.getFraction(0.66666d); + assertEquals(2, f.getNumerator()); + assertEquals(3, f.getDenominator()); + + // small + f = Fraction.getFraction(1.0d/10001d); + assertEquals(0, f.getNumerator()); + assertEquals(1, f.getDenominator()); + + // normal + Fraction f2 = null; + for (int i = 1; i <= 100; i++) { // denominator + for (int j = 1; j <= i; j++) { // numerator + f = Fraction.getFraction((double) j / (double) i); + + f2 = Fraction.getReducedFraction(j, i); + assertEquals(f2.getNumerator(), f.getNumerator()); + assertEquals(f2.getDenominator(), f.getDenominator()); + } + } + // save time by skipping some tests! ( + for (int i = 1001; i <= 10000; i+=SKIP) { // denominator + for (int j = 1; j <= i; j++) { // numerator + f = Fraction.getFraction((double) j / (double) i); + f2 = Fraction.getReducedFraction(j, i); + assertEquals(f2.getNumerator(), f.getNumerator()); + assertEquals(f2.getDenominator(), f.getDenominator()); + } + } + } + + @Test + public void testFactory_int_int() { + Fraction f; + + // zero + f = Fraction.getFraction(0, 1); + assertEquals(0, f.getNumerator()); + assertEquals(1, f.getDenominator()); + + f = Fraction.getFraction(0, 2); + assertEquals(0, f.getNumerator()); + assertEquals(2, f.getDenominator()); + + // normal + f = Fraction.getFraction(1, 1); + assertEquals(1, f.getNumerator()); + assertEquals(1, f.getDenominator()); + + f = Fraction.getFraction(2, 1); + assertEquals(2, f.getNumerator()); + assertEquals(1, f.getDenominator()); + + f = Fraction.getFraction(23, 345); + assertEquals(23, f.getNumerator()); + assertEquals(345, f.getDenominator()); + + // improper + f = Fraction.getFraction(22, 7); + assertEquals(22, f.getNumerator()); + assertEquals(7, f.getDenominator()); + + // negatives + f = Fraction.getFraction(-6, 10); + assertEquals(-6, f.getNumerator()); + assertEquals(10, f.getDenominator()); + + f = Fraction.getFraction(6, -10); + assertEquals(-6, f.getNumerator()); + assertEquals(10, f.getDenominator()); + + f = Fraction.getFraction(-6, -10); + assertEquals(6, f.getNumerator()); + assertEquals(10, f.getDenominator()); + + // zero denominator + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(1, 0)); + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(2, 0)); + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(-3, 0)); + + // very large: can't represent as unsimplified fraction, although + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(4, Integer.MIN_VALUE)); + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(1, Integer.MIN_VALUE)); + } + + @Test + public void testFactory_int_int_int() { + Fraction f; + + // zero + f = Fraction.getFraction(0, 0, 2); + assertEquals(0, f.getNumerator()); + assertEquals(2, f.getDenominator()); + + f = Fraction.getFraction(2, 0, 2); + assertEquals(4, f.getNumerator()); + assertEquals(2, f.getDenominator()); + + f = Fraction.getFraction(0, 1, 2); + assertEquals(1, f.getNumerator()); + assertEquals(2, f.getDenominator()); + + // normal + f = Fraction.getFraction(1, 1, 2); + assertEquals(3, f.getNumerator()); + assertEquals(2, f.getDenominator()); + + // negatives + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(1, -6, -10)); + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(1, -6, -10)); + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(1, -6, -10)); + + // negative whole + f = Fraction.getFraction(-1, 6, 10); + assertEquals(-16, f.getNumerator()); + assertEquals(10, f.getDenominator()); + + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(-1, -6, 10)); + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(-1, 6, -10)); + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(-1, -6, -10)); + + // zero denominator + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(0, 1, 0)); + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(1, 2, 0)); + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(-1, -3, 0)); + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(Integer.MAX_VALUE, 1, 2)); + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(-Integer.MAX_VALUE, 1, 2)); + + // very large + f = Fraction.getFraction(-1, 0, Integer.MAX_VALUE); + assertEquals(-Integer.MAX_VALUE, f.getNumerator()); + assertEquals(Integer.MAX_VALUE, f.getDenominator()); + + // negative denominators not allowed in this constructor. + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(0, 4, Integer.MIN_VALUE)); + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(1, 1, Integer.MAX_VALUE)); + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(-1, 2, Integer.MAX_VALUE)); + } + + @Test + public void testFactory_String() { + assertThrows(NullPointerException.class, () -> Fraction.getFraction(null)); + } + + @Test + public void testFactory_String_double() { + Fraction f; + + f = Fraction.getFraction("0.0"); + assertEquals(0, f.getNumerator()); + assertEquals(1, f.getDenominator()); + + f = Fraction.getFraction("0.2"); + assertEquals(1, f.getNumerator()); + assertEquals(5, f.getDenominator()); + + f = Fraction.getFraction("0.5"); + assertEquals(1, f.getNumerator()); + assertEquals(2, f.getDenominator()); + + f = Fraction.getFraction("0.66666"); + assertEquals(2, f.getNumerator()); + assertEquals(3, f.getDenominator()); + + assertThrows(NumberFormatException.class, () -> Fraction.getFraction("2.3R")); + assertThrows(NumberFormatException.class, () -> Fraction.getFraction("2147483648")); // too big + assertThrows(NumberFormatException.class, () -> Fraction.getFraction(".")); + } + + @Test + public void testFactory_String_improper() { + Fraction f; + + f = Fraction.getFraction("0/1"); + assertEquals(0, f.getNumerator()); + assertEquals(1, f.getDenominator()); + + f = Fraction.getFraction("1/5"); + assertEquals(1, f.getNumerator()); + assertEquals(5, f.getDenominator()); + + f = Fraction.getFraction("1/2"); + assertEquals(1, f.getNumerator()); + assertEquals(2, f.getDenominator()); + + f = Fraction.getFraction("2/3"); + assertEquals(2, f.getNumerator()); + assertEquals(3, f.getDenominator()); + + f = Fraction.getFraction("7/3"); + assertEquals(7, f.getNumerator()); + assertEquals(3, f.getDenominator()); + + f = Fraction.getFraction("2/4"); + assertEquals(2, f.getNumerator()); + assertEquals(4, f.getDenominator()); + + assertThrows(NumberFormatException.class, () -> Fraction.getFraction("2/d")); + assertThrows(NumberFormatException.class, () -> Fraction.getFraction("2e/3")); + assertThrows(NumberFormatException.class, () -> Fraction.getFraction("2/")); + assertThrows(NumberFormatException.class, () -> Fraction.getFraction("/")); + } + + @Test + public void testFactory_String_proper() { + Fraction f; + + f = Fraction.getFraction("0 0/1"); + assertEquals(0, f.getNumerator()); + assertEquals(1, f.getDenominator()); + + f = Fraction.getFraction("1 1/5"); + assertEquals(6, f.getNumerator()); + assertEquals(5, f.getDenominator()); + + f = Fraction.getFraction("7 1/2"); + assertEquals(15, f.getNumerator()); + assertEquals(2, f.getDenominator()); + + f = Fraction.getFraction("1 2/4"); + assertEquals(6, f.getNumerator()); + assertEquals(4, f.getDenominator()); + + f = Fraction.getFraction("-7 1/2"); + assertEquals(-15, f.getNumerator()); + assertEquals(2, f.getDenominator()); + + f = Fraction.getFraction("-1 2/4"); + assertEquals(-6, f.getNumerator()); + assertEquals(4, f.getDenominator()); + + assertThrows(NumberFormatException.class, () -> Fraction.getFraction("2 3")); + assertThrows(NumberFormatException.class, () -> Fraction.getFraction("a 3")); + assertThrows(NumberFormatException.class, () -> Fraction.getFraction("2 b/4")); + assertThrows(NumberFormatException.class, () -> Fraction.getFraction("2 ")); + assertThrows(NumberFormatException.class, () -> Fraction.getFraction(" 3")); + assertThrows(NumberFormatException.class, () -> Fraction.getFraction(" ")); + } + + @Test + public void testGets() { + Fraction f; + + f = Fraction.getFraction(3, 5, 6); + assertEquals(23, f.getNumerator()); + assertEquals(3, f.getProperWhole()); + assertEquals(5, f.getProperNumerator()); + assertEquals(6, f.getDenominator()); + + f = Fraction.getFraction(-3, 5, 6); + assertEquals(-23, f.getNumerator()); + assertEquals(-3, f.getProperWhole()); + assertEquals(5, f.getProperNumerator()); + assertEquals(6, f.getDenominator()); + + f = Fraction.getFraction(Integer.MIN_VALUE, 0, 1); + assertEquals(Integer.MIN_VALUE, f.getNumerator()); + assertEquals(Integer.MIN_VALUE, f.getProperWhole()); + assertEquals(0, f.getProperNumerator()); + assertEquals(1, f.getDenominator()); + } + + @Test + public void testHashCode() { + final Fraction f1 = Fraction.getFraction(3, 5); + Fraction f2 = Fraction.getFraction(3, 5); + + assertEquals(f1.hashCode(), f2.hashCode()); + + f2 = Fraction.getFraction(2, 5); + assertTrue(f1.hashCode() != f2.hashCode()); + + f2 = Fraction.getFraction(6, 10); + assertTrue(f1.hashCode() != f2.hashCode()); + } + + @Test + public void testInvert() { + Fraction f; + + f = Fraction.getFraction(50, 75); + f = f.invert(); + assertEquals(75, f.getNumerator()); + assertEquals(50, f.getDenominator()); + + f = Fraction.getFraction(4, 3); + f = f.invert(); + assertEquals(3, f.getNumerator()); + assertEquals(4, f.getDenominator()); + + f = Fraction.getFraction(-15, 47); + f = f.invert(); + assertEquals(-47, f.getNumerator()); + assertEquals(15, f.getDenominator()); + + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(0, 3).invert()); + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(Integer.MIN_VALUE, 1).invert()); + + f = Fraction.getFraction(Integer.MAX_VALUE, 1); + f = f.invert(); + assertEquals(1, f.getNumerator()); + assertEquals(Integer.MAX_VALUE, f.getDenominator()); + } + + @Test + public void testMultiply() { + Fraction f; + Fraction f1; + Fraction f2; + + f1 = Fraction.getFraction(3, 5); + f2 = Fraction.getFraction(2, 5); + f = f1.multiplyBy(f2); + assertEquals(6, f.getNumerator()); + assertEquals(25, f.getDenominator()); + + f1 = Fraction.getFraction(6, 10); + f2 = Fraction.getFraction(6, 10); + f = f1.multiplyBy(f2); + assertEquals(9, f.getNumerator()); + assertEquals(25, f.getDenominator()); + f = f.multiplyBy(f2); + assertEquals(27, f.getNumerator()); + assertEquals(125, f.getDenominator()); + + f1 = Fraction.getFraction(3, 5); + f2 = Fraction.getFraction(-2, 5); + f = f1.multiplyBy(f2); + assertEquals(-6, f.getNumerator()); + assertEquals(25, f.getDenominator()); + + f1 = Fraction.getFraction(-3, 5); + f2 = Fraction.getFraction(-2, 5); + f = f1.multiplyBy(f2); + assertEquals(6, f.getNumerator()); + assertEquals(25, f.getDenominator()); + + + f1 = Fraction.getFraction(0, 5); + f2 = Fraction.getFraction(2, 7); + f = f1.multiplyBy(f2); + assertSame(Fraction.ZERO, f); + + f1 = Fraction.getFraction(2, 7); + f2 = Fraction.ONE; + f = f1.multiplyBy(f2); + assertEquals(2, f.getNumerator()); + assertEquals(7, f.getDenominator()); + + f1 = Fraction.getFraction(Integer.MAX_VALUE, 1); + f2 = Fraction.getFraction(Integer.MIN_VALUE, Integer.MAX_VALUE); + f = f1.multiplyBy(f2); + assertEquals(Integer.MIN_VALUE, f.getNumerator()); + assertEquals(1, f.getDenominator()); + + final Fraction fr = f; + assertThrows(NullPointerException.class, () -> fr.multiplyBy(null)); + + final Fraction fr1 = Fraction.getFraction(1, Integer.MAX_VALUE); + assertThrows(ArithmeticException.class, () -> fr1.multiplyBy(fr1)); + + final Fraction fr2 = Fraction.getFraction(1, -Integer.MAX_VALUE); + assertThrows(ArithmeticException.class, () -> fr2.multiplyBy(fr2)); + } + + @Test + public void testNegate() { + Fraction f; + + f = Fraction.getFraction(50, 75); + f = f.negate(); + assertEquals(-50, f.getNumerator()); + assertEquals(75, f.getDenominator()); + + f = Fraction.getFraction(-50, 75); + f = f.negate(); + assertEquals(50, f.getNumerator()); + assertEquals(75, f.getDenominator()); + + // large values + f = Fraction.getFraction(Integer.MAX_VALUE-1, Integer.MAX_VALUE); + f = f.negate(); + assertEquals(Integer.MIN_VALUE+2, f.getNumerator()); + assertEquals(Integer.MAX_VALUE, f.getDenominator()); + + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(Integer.MIN_VALUE, 1).negate()); + } + + @Test + public void testPow() { + Fraction f; + + f = Fraction.getFraction(3, 5); + assertEquals(Fraction.ONE, f.pow(0)); + + f = Fraction.getFraction(3, 5); + assertSame(f, f.pow(1)); + assertEquals(f, f.pow(1)); + + f = Fraction.getFraction(3, 5); + f = f.pow(2); + assertEquals(9, f.getNumerator()); + assertEquals(25, f.getDenominator()); + + f = Fraction.getFraction(3, 5); + f = f.pow(3); + assertEquals(27, f.getNumerator()); + assertEquals(125, f.getDenominator()); + + f = Fraction.getFraction(3, 5); + f = f.pow(-1); + assertEquals(5, f.getNumerator()); + assertEquals(3, f.getDenominator()); + + f = Fraction.getFraction(3, 5); + f = f.pow(-2); + assertEquals(25, f.getNumerator()); + assertEquals(9, f.getDenominator()); + + // check unreduced fractions stay that way. + f = Fraction.getFraction(6, 10); + assertEquals(Fraction.ONE, f.pow(0)); + + f = Fraction.getFraction(6, 10); + assertEquals(f, f.pow(1)); + assertNotEquals(f.pow(1), Fraction.getFraction(3, 5)); + + f = Fraction.getFraction(6, 10); + f = f.pow(2); + assertEquals(9, f.getNumerator()); + assertEquals(25, f.getDenominator()); + + f = Fraction.getFraction(6, 10); + f = f.pow(3); + assertEquals(27, f.getNumerator()); + assertEquals(125, f.getDenominator()); + + f = Fraction.getFraction(6, 10); + f = f.pow(-1); + assertEquals(10, f.getNumerator()); + assertEquals(6, f.getDenominator()); + + f = Fraction.getFraction(6, 10); + f = f.pow(-2); + assertEquals(25, f.getNumerator()); + assertEquals(9, f.getDenominator()); + + // zero to any positive power is still zero. + f = Fraction.getFraction(0, 1231); + f = f.pow(1); + assertEquals(0, f.compareTo(Fraction.ZERO)); + assertEquals(0, f.getNumerator()); + assertEquals(1231, f.getDenominator()); + f = f.pow(2); + assertEquals(0, f.compareTo(Fraction.ZERO)); + assertEquals(0, f.getNumerator()); + assertEquals(1, f.getDenominator()); + + // zero to negative powers should throw an exception + final Fraction fr = f; + assertThrows(ArithmeticException.class, () -> fr.pow(-1)); + assertThrows(ArithmeticException.class, () -> fr.pow(Integer.MIN_VALUE)); + + // one to any power is still one. + f = Fraction.getFraction(1, 1); + f = f.pow(0); + assertEquals(f, Fraction.ONE); + f = f.pow(1); + assertEquals(f, Fraction.ONE); + f = f.pow(-1); + assertEquals(f, Fraction.ONE); + f = f.pow(Integer.MAX_VALUE); + assertEquals(f, Fraction.ONE); + f = f.pow(Integer.MIN_VALUE); + assertEquals(f, Fraction.ONE); + + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(Integer.MAX_VALUE, 1).pow(2)); + + // Numerator growing too negative during the pow operation. + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(Integer.MIN_VALUE, 1).pow(3)); + + assertThrows(ArithmeticException.class, () -> Fraction.getFraction(65536, 1).pow(2)); + } + + @Test + public void testReduce() { + Fraction f; + + f = Fraction.getFraction(50, 75); + Fraction result = f.reduce(); + assertEquals(2, result.getNumerator()); + assertEquals(3, result.getDenominator()); + + f = Fraction.getFraction(-2, -3); + result = f.reduce(); + assertEquals(2, result.getNumerator()); + assertEquals(3, result.getDenominator()); + + f = Fraction.getFraction(2, -3); + result = f.reduce(); + assertEquals(-2, result.getNumerator()); + assertEquals(3, result.getDenominator()); + + f = Fraction.getFraction(-2, 3); + result = f.reduce(); + assertEquals(-2, result.getNumerator()); + assertEquals(3, result.getDenominator()); + assertSame(f, result); + + f = Fraction.getFraction(2, 3); + result = f.reduce(); + assertEquals(2, result.getNumerator()); + assertEquals(3, result.getDenominator()); + assertSame(f, result); + + f = Fraction.getFraction(0, 1); + result = f.reduce(); + assertEquals(0, result.getNumerator()); + assertEquals(1, result.getDenominator()); + assertSame(f, result); + + f = Fraction.getFraction(0, 100); + result = f.reduce(); + assertEquals(0, result.getNumerator()); + assertEquals(1, result.getDenominator()); + assertSame(result, Fraction.ZERO); + + f = Fraction.getFraction(Integer.MIN_VALUE, 2); + result = f.reduce(); + assertEquals(Integer.MIN_VALUE / 2, result.getNumerator()); + assertEquals(1, result.getDenominator()); + } + + @Test + public void testReducedFactory_int_int() { + Fraction f; + + // zero + f = Fraction.getReducedFraction(0, 1); + assertEquals(0, f.getNumerator()); + assertEquals(1, f.getDenominator()); + + // normal + f = Fraction.getReducedFraction(1, 1); + assertEquals(1, f.getNumerator()); + assertEquals(1, f.getDenominator()); + + f = Fraction.getReducedFraction(2, 1); + assertEquals(2, f.getNumerator()); + assertEquals(1, f.getDenominator()); + + // improper + f = Fraction.getReducedFraction(22, 7); + assertEquals(22, f.getNumerator()); + assertEquals(7, f.getDenominator()); + + // negatives + f = Fraction.getReducedFraction(-6, 10); + assertEquals(-3, f.getNumerator()); + assertEquals(5, f.getDenominator()); + + f = Fraction.getReducedFraction(6, -10); + assertEquals(-3, f.getNumerator()); + assertEquals(5, f.getDenominator()); + + f = Fraction.getReducedFraction(-6, -10); + assertEquals(3, f.getNumerator()); + assertEquals(5, f.getDenominator()); + + // zero denominator + assertThrows(ArithmeticException.class, () -> Fraction.getReducedFraction(1, 0)); + assertThrows(ArithmeticException.class, () -> Fraction.getReducedFraction(2, 0)); + assertThrows(ArithmeticException.class, () -> Fraction.getReducedFraction(-3, 0)); + + // reduced + f = Fraction.getReducedFraction(0, 2); + assertEquals(0, f.getNumerator()); + assertEquals(1, f.getDenominator()); + + f = Fraction.getReducedFraction(2, 2); + assertEquals(1, f.getNumerator()); + assertEquals(1, f.getDenominator()); + + f = Fraction.getReducedFraction(2, 4); + assertEquals(1, f.getNumerator()); + assertEquals(2, f.getDenominator()); + + f = Fraction.getReducedFraction(15, 10); + assertEquals(3, f.getNumerator()); + assertEquals(2, f.getDenominator()); + + f = Fraction.getReducedFraction(121, 22); + assertEquals(11, f.getNumerator()); + assertEquals(2, f.getDenominator()); + + // Extreme values + // OK, can reduce before negating + f = Fraction.getReducedFraction(-2, Integer.MIN_VALUE); + assertEquals(1, f.getNumerator()); + assertEquals(-(Integer.MIN_VALUE / 2), f.getDenominator()); + + // Can't reduce, negation will throw + assertThrows(ArithmeticException.class, () -> Fraction.getReducedFraction(-7, Integer.MIN_VALUE)); + + // LANG-662 + f = Fraction.getReducedFraction(Integer.MIN_VALUE, 2); + assertEquals(Integer.MIN_VALUE / 2, f.getNumerator()); + assertEquals(1, f.getDenominator()); + } + + @Test + public void testSubtract() { + Fraction f; + Fraction f1; + Fraction f2; + + f1 = Fraction.getFraction(3, 5); + f2 = Fraction.getFraction(1, 5); + f = f1.subtract(f2); + assertEquals(2, f.getNumerator()); + assertEquals(5, f.getDenominator()); + + f1 = Fraction.getFraction(7, 5); + f2 = Fraction.getFraction(2, 5); + f = f1.subtract(f2); + assertEquals(1, f.getNumerator()); + assertEquals(1, f.getDenominator()); + + f1 = Fraction.getFraction(3, 5); + f2 = Fraction.getFraction(3, 5); + f = f1.subtract(f2); + assertEquals(0, f.getNumerator()); + assertEquals(1, f.getDenominator()); + + f1 = Fraction.getFraction(3, 5); + f2 = Fraction.getFraction(-4, 5); + f = f1.subtract(f2); + assertEquals(7, f.getNumerator()); + assertEquals(5, f.getDenominator()); + + f1 = Fraction.getFraction(0, 5); + f2 = Fraction.getFraction(4, 5); + f = f1.subtract(f2); + assertEquals(-4, f.getNumerator()); + assertEquals(5, f.getDenominator()); + + f1 = Fraction.getFraction(0, 5); + f2 = Fraction.getFraction(-4, 5); + f = f1.subtract(f2); + assertEquals(4, f.getNumerator()); + assertEquals(5, f.getDenominator()); + + f1 = Fraction.getFraction(3, 5); + f2 = Fraction.getFraction(1, 2); + f = f1.subtract(f2); + assertEquals(1, f.getNumerator()); + assertEquals(10, f.getDenominator()); + + f1 = Fraction.getFraction(0, 5); + f2 = Fraction.getFraction(1, 5); + f = f2.subtract(f1); + assertSame(f2, f); + + final Fraction fr = f; + assertThrows(NullPointerException.class, () -> fr.subtract(null)); + + // if this fraction is subtracted naively, it will overflow. + // check that it doesn't. + f1 = Fraction.getFraction(1, 32768*3); + f2 = Fraction.getFraction(1, 59049); + f = f1.subtract(f2); + assertEquals(-13085, f.getNumerator()); + assertEquals(1934917632, f.getDenominator()); + + f1 = Fraction.getFraction(Integer.MIN_VALUE, 3); + f2 = Fraction.ONE_THIRD.negate(); + f = f1.subtract(f2); + assertEquals(Integer.MIN_VALUE+1, f.getNumerator()); + assertEquals(3, f.getDenominator()); + + f1 = Fraction.getFraction(Integer.MAX_VALUE, 1); + f2 = Fraction.ONE; + f = f1.subtract(f2); + assertEquals(Integer.MAX_VALUE-1, f.getNumerator()); + assertEquals(1, f.getDenominator()); + + // Should overflow + assertThrows( + ArithmeticException.class, + () -> Fraction.getFraction(1, Integer.MAX_VALUE).subtract(Fraction.getFraction(1, Integer.MAX_VALUE - 1))); + f = f1.subtract(f2); + + // denominator should not be a multiple of 2 or 3 to trigger overflow + assertThrows( + ArithmeticException.class, + () -> Fraction.getFraction(Integer.MIN_VALUE, 5).subtract(Fraction.getFraction(1, 5))); + + assertThrows( + ArithmeticException.class, () -> Fraction.getFraction(Integer.MIN_VALUE, 1).subtract(Fraction.ONE)); + + assertThrows( + ArithmeticException.class, + () -> Fraction.getFraction(Integer.MAX_VALUE, 1).subtract(Fraction.ONE.negate())); + + // Should overflow + assertThrows( + ArithmeticException.class, + () -> Fraction.getFraction(3, 327680).subtract(Fraction.getFraction(2, 59049))); + } + + @Test + public void testToProperString() { + Fraction f; + + f = Fraction.getFraction(3, 5); + final String str = f.toProperString(); + assertEquals("3/5", str); + assertSame(str, f.toProperString()); + + f = Fraction.getFraction(7, 5); + assertEquals("1 2/5", f.toProperString()); + + f = Fraction.getFraction(14, 10); + assertEquals("1 4/10", f.toProperString()); + + f = Fraction.getFraction(4, 2); + assertEquals("2", f.toProperString()); + + f = Fraction.getFraction(0, 2); + assertEquals("0", f.toProperString()); + + f = Fraction.getFraction(2, 2); + assertEquals("1", f.toProperString()); + + f = Fraction.getFraction(-7, 5); + assertEquals("-1 2/5", f.toProperString()); + + f = Fraction.getFraction(Integer.MIN_VALUE, 0, 1); + assertEquals("-2147483648", f.toProperString()); + + f = Fraction.getFraction(-1, 1, Integer.MAX_VALUE); + assertEquals("-1 1/2147483647", f.toProperString()); + + assertEquals("-1", Fraction.getFraction(-1).toProperString()); + } + + @Test + public void testToString() { + Fraction f; + + f = Fraction.getFraction(3, 5); + final String str = f.toString(); + assertEquals("3/5", str); + assertSame(str, f.toString()); + + f = Fraction.getFraction(7, 5); + assertEquals("7/5", f.toString()); + + f = Fraction.getFraction(4, 2); + assertEquals("4/2", f.toString()); + + f = Fraction.getFraction(0, 2); + assertEquals("0/2", f.toString()); + + f = Fraction.getFraction(2, 2); + assertEquals("2/2", f.toString()); + + f = Fraction.getFraction(Integer.MIN_VALUE, 0, 1); + assertEquals("-2147483648/1", f.toString()); + + f = Fraction.getFraction(-1, 1, Integer.MAX_VALUE); + assertEquals("-2147483648/2147483647", f.toString()); + } +} |