    1   /*
    2    * Copyright 2005 The Apache Software Foundation.
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  package org.apache.commons.math.fraction;
    17
    18  import org.apache.commons.math.ConvergenceException;
    19
    20  import junit.framework.TestCase;
    21
    22  /***
    23   * @version $Revision: 264689 $ $Date: 2005-08-29 20:28:42 -0700 (Mon, 29 Aug 2005) $
    24   */
    25  public class FractionTest extends TestCase {
    26
    27      private void assertFraction(int expectedNumerator, int expectedDenominator, Fraction actual) {
    28          assertEquals(expectedNumerator, actual.getNumerator());
    29          assertEquals(expectedDenominator, actual.getDenominator());
    30      }
    31
    32      public void testConstructor() {
    33          assertFraction(0, 1, new Fraction(0, 1));
    34          assertFraction(0, 1, new Fraction(0, 2));
    35          assertFraction(0, 1, new Fraction(0, -1));
    36          assertFraction(1, 2, new Fraction(1, 2));
    37          assertFraction(1, 2, new Fraction(2, 4));
    38          assertFraction(-1, 2, new Fraction(-1, 2));
    39          assertFraction(-1, 2, new Fraction(1, -2));
    40          assertFraction(-1, 2, new Fraction(-2, 4));
    41          assertFraction(-1, 2, new Fraction(2, -4));
    42
    43          // overflow
    44          try {
    45              new Fraction(Integer.MIN_VALUE, -1);
    46              fail();
    47          } catch (ArithmeticException ex) {
    48              // success
    49          }
    50          try {
    51              new Fraction(1, Integer.MIN_VALUE);
    52              fail();
    53          } catch (ArithmeticException ex) {
    54              // success
    55          }
    56          try {
    57              assertFraction(0, 1, new Fraction(0.00000000000001));
    58              assertFraction(2, 5, new Fraction(0.40000000000001));
    59              assertFraction(15, 1, new Fraction(15.0000000000001));
    60
    61          } catch (ConvergenceException ex) {
    62              fail(ex.getMessage());
    63          }
    64      }
    65
    66      public void testCompareTo() {
    67          Fraction first = new Fraction(1, 2);
    68          Fraction second = new Fraction(1, 3);
    69          Fraction third = new Fraction(1, 2);
    70
    71          assertEquals(0, first.compareTo(first));
    72          assertEquals(0, first.compareTo(third));
    73          assertEquals(1, first.compareTo(second));
    74          assertEquals(-1, second.compareTo(first));
    75      }
    76
    77      public void testDoubleValue() {
    78          Fraction first = new Fraction(1, 2);
    79          Fraction second = new Fraction(1, 3);
    80
    81          assertEquals(0.5, first.doubleValue(), 0.0);
    82          assertEquals(1.0 / 3.0, second.doubleValue(), 0.0);
    83      }
    84
    85      public void testFloatValue() {
    86          Fraction first = new Fraction(1, 2);
    87          Fraction second = new Fraction(1, 3);
    88
    89          assertEquals(0.5f, first.floatValue(), 0.0f);
    90          assertEquals((float)(1.0 / 3.0), second.floatValue(), 0.0f);
    91      }
    92
    93      public void testIntValue() {
    94          Fraction first = new Fraction(1, 2);
    95          Fraction second = new Fraction(3, 2);
    96
    97          assertEquals(0, first.intValue());
    98          assertEquals(1, second.intValue());
    99      }
    100
    101     public void testLongValue() {
    102         Fraction first = new Fraction(1, 2);
    103         Fraction second = new Fraction(3, 2);
    104
    105         assertEquals(0L, first.longValue());
    106         assertEquals(1L, second.longValue());
    107     }
    108
    109     public void testConstructorDouble() {
    110         try {
    111             assertFraction(1, 2, new Fraction(0.5));
    112             assertFraction(1, 3, new Fraction(1.0 / 3.0));
    113             assertFraction(17, 100, new Fraction(17.0 / 100.0));
    114             assertFraction(317, 100, new Fraction(317.0 / 100.0));
    115             assertFraction(-1, 2, new Fraction(-0.5));
    116             assertFraction(-1, 3, new Fraction(-1.0 / 3.0));
    117             assertFraction(-17, 100, new Fraction(17.0 / -100.0));
    118             assertFraction(-317, 100, new Fraction(-317.0 / 100.0));
    119         } catch (ConvergenceException ex) {
    120             fail(ex.getMessage());
    121         }
    122     }
    123
    124     public void testAbs() {
    125         Fraction a = new Fraction(10, 21);
    126         Fraction b = new Fraction(-10, 21);
    127         Fraction c = new Fraction(10, -21);
    128
    129         assertFraction(10, 21, a.abs());
    130         assertFraction(10, 21, b.abs());
    131         assertFraction(10, 21, c.abs());
    132     }
    133
    134     public void testReciprocal() {
    135         Fraction f = null;
    136
    137         f = new Fraction(50, 75);
    138         f = f.reciprocal();
    139         assertEquals(3, f.getNumerator());
    140         assertEquals(2, f.getDenominator());
    141
    142         f = new Fraction(4, 3);
    143         f = f.reciprocal();
    144         assertEquals(3, f.getNumerator());
    145         assertEquals(4, f.getDenominator());
    146
    147         f = new Fraction(-15, 47);
    148         f = f.reciprocal();
    149         assertEquals(-47, f.getNumerator());
    150         assertEquals(15, f.getDenominator());
    151
    152         f = new Fraction(0, 3);
    153         try {
    154             f = f.reciprocal();
    155             fail("expecting ArithmeticException");
    156         } catch (ArithmeticException ex) {}
    157
    158         // large values
    159         f = new Fraction(Integer.MAX_VALUE, 1);
    160         f = f.reciprocal();
    161         assertEquals(1, f.getNumerator());
    162         assertEquals(Integer.MAX_VALUE, f.getDenominator());
    163     }
    164
    165     public void testNegate() {
    166         Fraction f = null;
    167
    168         f = new Fraction(50, 75);
    169         f = f.negate();
    170         assertEquals(-2, f.getNumerator());
    171         assertEquals(3, f.getDenominator());
    172
    173         f = new Fraction(-50, 75);
    174         f = f.negate();
    175         assertEquals(2, f.getNumerator());
    176         assertEquals(3, f.getDenominator());
    177
    178         // large values
    179         f = new Fraction(Integer.MAX_VALUE-1, Integer.MAX_VALUE);
    180         f = f.negate();
    181         assertEquals(Integer.MIN_VALUE+2, f.getNumerator());
    182         assertEquals(Integer.MAX_VALUE, f.getDenominator());
    183
    184         f = new Fraction(Integer.MIN_VALUE, 1);
    185         try {
    186             f = f.negate();
    187             fail("expecting ArithmeticException");
    188         } catch (ArithmeticException ex) {}
    189     }
    190
    191     public void testAdd() {
    192         Fraction a = new Fraction(1, 2);
    193         Fraction b = new Fraction(2, 3);
    194
    195         assertFraction(1, 1, a.add(a));
    196         assertFraction(7, 6, a.add(b));
    197         assertFraction(7, 6, b.add(a));
    198         assertFraction(4, 3, b.add(b));
    199
    200         Fraction f1 = new Fraction(Integer.MAX_VALUE - 1, 1);
    201         Fraction f2 = Fraction.ONE;
    202         Fraction f = f1.add(f2);
    203         assertEquals(Integer.MAX_VALUE, f.getNumerator());
    204         assertEquals(1, f.getDenominator());
    205
    206         f1 = new Fraction(-1, 13*13*2*2);
    207         f2 = new Fraction(-2, 13*17*2);
    208         f = f1.add(f2);
    209         assertEquals(13*13*17*2*2, f.getDenominator());
    210         assertEquals(-17 - 2*13*2, f.getNumerator());
    211
    212         try {
    213             f.add(null);
    214             fail("expecting IllegalArgumentException");
    215         } catch (IllegalArgumentException ex) {}
    216
    217         // if this fraction is added naively, it will overflow.
    218         // check that it doesn't.
    219         f1 = new Fraction(1,32768*3);
    220         f2 = new Fraction(1,59049);
    221         f = f1.add(f2);
    222         assertEquals(52451, f.getNumerator());
    223         assertEquals(1934917632, f.getDenominator());
    224
    225         f1 = new Fraction(Integer.MIN_VALUE, 3);
    226         f2 = new Fraction(1,3);
    227         f = f1.add(f2);
    228         assertEquals(Integer.MIN_VALUE+1, f.getNumerator());
    229         assertEquals(3, f.getDenominator());
    230
    231         f1 = new Fraction(Integer.MAX_VALUE - 1, 1);
    232         f2 = Fraction.ONE;
    233         f = f1.add(f2);
    234         assertEquals(Integer.MAX_VALUE, f.getNumerator());
    235         assertEquals(1, f.getDenominator());
    236
    237         try {
    238             f = f.add(Fraction.ONE); // should overflow
    239             fail("expecting ArithmeticException but got: " + f.toString());
    240         } catch (ArithmeticException ex) {}
    241
    242         // denominator should not be a multiple of 2 or 3 to trigger overflow
    243         f1 = new Fraction(Integer.MIN_VALUE, 5);
    244         f2 = new Fraction(-1,5);
    245         try {
    246             f = f1.add(f2); // should overflow
    247             fail("expecting ArithmeticException but got: " + f.toString());
    248         } catch (ArithmeticException ex) {}
    249
    250         try {
    251             f= new Fraction(-Integer.MAX_VALUE, 1);
    252             f = f.add(f);
    253             fail("expecting ArithmeticException");
    254         } catch (ArithmeticException ex) {}
    255
    256         try {
    257             f= new Fraction(-Integer.MAX_VALUE, 1);
    258             f = f.add(f);
    259             fail("expecting ArithmeticException");
    260         } catch (ArithmeticException ex) {}
    261
    262         f1 = new Fraction(3,327680);
    263         f2 = new Fraction(2,59049);
    264         try {
    265             f = f1.add(f2); // should overflow
    266             fail("expecting ArithmeticException but got: " + f.toString());
    267         } catch (ArithmeticException ex) {}
    268     }
    269
    270     public void testDivide() {
    271         Fraction a = new Fraction(1, 2);
    272         Fraction b = new Fraction(2, 3);
    273
    274         assertFraction(1, 1, a.divide(a));
    275         assertFraction(3, 4, a.divide(b));
    276         assertFraction(4, 3, b.divide(a));
    277         assertFraction(1, 1, b.divide(b));
    278
    279         Fraction f1 = new Fraction(3, 5);
    280         Fraction f2 = Fraction.ZERO;
    281         try {
    282             Fraction f = f1.divide(f2);
    283             fail("expecting ArithmeticException");
    284         } catch (ArithmeticException ex) {}
    285
    286         f1 = new Fraction(0, 5);
    287         f2 = new Fraction(2, 7);
    288         Fraction f = f1.divide(f2);
    289         assertSame(Fraction.ZERO, f);
    290
    291         f1 = new Fraction(2, 7);
    292         f2 = Fraction.ONE;
    293         f = f1.divide(f2);
    294         assertEquals(2, f.getNumerator());
    295         assertEquals(7, f.getDenominator());
    296
    297         f1 = new Fraction(1, Integer.MAX_VALUE);
    298         f = f1.divide(f1);
    299         assertEquals(1, f.getNumerator());
    300         assertEquals(1, f.getDenominator());
    301
    302         f1 = new Fraction(Integer.MIN_VALUE, Integer.MAX_VALUE);
    303         f2 = new Fraction(1, Integer.MAX_VALUE);
    304         f = f1.divide(f2);
    305         assertEquals(Integer.MIN_VALUE, f.getNumerator());
    306         assertEquals(1, f.getDenominator());
    307
    308         try {
    309             f.divide(null);
    310             fail("IllegalArgumentException");
    311         } catch (IllegalArgumentException ex) {}
    312
    313         try {
    314             f1 = new Fraction(1, Integer.MAX_VALUE);
    315             f = f1.divide(f1.reciprocal());  // should overflow
    316             fail("expecting ArithmeticException");
    317         } catch (ArithmeticException ex) {}
    318         try {
    319             f1 = new Fraction(1, -Integer.MAX_VALUE);
    320             f = f1.divide(f1.reciprocal());  // should overflow
    321             fail("expecting ArithmeticException");
    322         } catch (ArithmeticException ex) {}
    323     }
    324
    325     public void testMultiply() {
    326         Fraction a = new Fraction(1, 2);
    327         Fraction b = new Fraction(2, 3);
    328
    329         assertFraction(1, 4, a.multiply(a));
    330         assertFraction(1, 3, a.multiply(b));
    331         assertFraction(1, 3, b.multiply(a));
    332         assertFraction(4, 9, b.multiply(b));
    333
    334         Fraction f1 = new Fraction(Integer.MAX_VALUE, 1);
    335         Fraction f2 = new Fraction(Integer.MIN_VALUE, Integer.MAX_VALUE);
    336         Fraction f = f1.multiply(f2);
    337         assertEquals(Integer.MIN_VALUE, f.getNumerator());
    338         assertEquals(1, f.getDenominator());
    339
    340         try {
    341             f.multiply(null);
    342             fail("expecting IllegalArgumentException");
    343         } catch (IllegalArgumentException ex) {}
    344     }
    345
    346     public void testSubtract() {
    347         Fraction a = new Fraction(1, 2);
    348         Fraction b = new Fraction(2, 3);
    349
    350         assertFraction(0, 1, a.subtract(a));
    351         assertFraction(-1, 6, a.subtract(b));
    352         assertFraction(1, 6, b.subtract(a));
    353         assertFraction(0, 1, b.subtract(b));
    354
    355         Fraction f = new Fraction(1,1);
    356         try {
    357             f.subtract(null);
    358             fail("expecting IllegalArgumentException");
    359         } catch (IllegalArgumentException ex) {}
    360
    361         // if this fraction is subtracted naively, it will overflow.
    362         // check that it doesn't.
    363         Fraction f1 = new Fraction(1,32768*3);
    364         Fraction f2 = new Fraction(1,59049);
    365         f = f1.subtract(f2);
    366         assertEquals(-13085, f.getNumerator());
    367         assertEquals(1934917632, f.getDenominator());
    368
    369         f1 = new Fraction(Integer.MIN_VALUE, 3);
    370         f2 = new Fraction(1,3).negate();
    371         f = f1.subtract(f2);
    372         assertEquals(Integer.MIN_VALUE+1, f.getNumerator());
    373         assertEquals(3, f.getDenominator());
    374
    375         f1 = new Fraction(Integer.MAX_VALUE, 1);
    376         f2 = Fraction.ONE;
    377         f = f1.subtract(f2);
    378         assertEquals(Integer.MAX_VALUE-1, f.getNumerator());
    379         assertEquals(1, f.getDenominator());
    380
    381         try {
    382             f1 = new Fraction(1, Integer.MAX_VALUE);
    383             f2 = new Fraction(1, Integer.MAX_VALUE - 1);
    384             f = f1.subtract(f2);
    385             fail("expecting ArithmeticException");  //should overflow
    386         } catch (ArithmeticException ex) {}
    387
    388         // denominator should not be a multiple of 2 or 3 to trigger overflow
    389         f1 = new Fraction(Integer.MIN_VALUE, 5);
    390         f2 = new Fraction(1,5);
    391         try {
    392             f = f1.subtract(f2); // should overflow
    393             fail("expecting ArithmeticException but got: " + f.toString());
    394         } catch (ArithmeticException ex) {}
    395
    396         try {
    397             f= new Fraction(Integer.MIN_VALUE, 1);
    398             f = f.subtract(Fraction.ONE);
    399             fail("expecting ArithmeticException");
    400         } catch (ArithmeticException ex) {}
    401
    402         try {
    403             f= new Fraction(Integer.MAX_VALUE, 1);
    404             f = f.subtract(Fraction.ONE.negate());
    405             fail("expecting ArithmeticException");
    406         } catch (ArithmeticException ex) {}
    407
    408         f1 = new Fraction(3,327680);
    409         f2 = new Fraction(2,59049);
    410         try {
    411             f = f1.subtract(f2); // should overflow
    412             fail("expecting ArithmeticException but got: " + f.toString());
    413         } catch (ArithmeticException ex) {}
    414     }
    415
    416     public void testEqualsAndHashCode() {
    417         Fraction zero  = new Fraction(0,1);
    418         Fraction nullFraction = null;
    419         int zeroHash = zero.hashCode();
    420         assertTrue( zero.equals(zero));
    421         assertFalse(zero.equals(nullFraction));
    422         assertFalse(zero.equals(new Double(0)));
    423         Fraction zero2 = new Fraction(0,2);
    424         assertTrue(zero.equals(zero2));
    425         assertEquals(zero.hashCode(), zero2.hashCode());
    426         Fraction one = new Fraction(1,1);
    427         assertFalse((one.equals(zero) ||zero.equals(one)));
    428     }
    429
    430     public void testGetReducedFraction() {
    431         Fraction threeFourths = new Fraction(3, 4);
    432         assertTrue(threeFourths.equals(Fraction.getReducedFraction(6, 8)));
    433         assertTrue(Fraction.ZERO.equals(Fraction.getReducedFraction(0, -1)));
    434         try {
    435             Fraction f = Fraction.getReducedFraction(1, 0);
    436             fail("expecting ArithmeticException");
    437         } catch (ArithmeticException ex) {
    438             // expected
    439         }
    440         assertEquals(Fraction.getReducedFraction
    441                 (2, Integer.MIN_VALUE).getNumerator(),-1);
    442         assertEquals(Fraction.getReducedFraction
    443                 (1, -1).getNumerator(), -1);
    444     }
    445 }