commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From scolebou...@apache.org
Subject cvs commit: jakarta-commons/lang/src/java/org/apache/commons/lang/math Fraction.java
Date Sun, 22 Dec 2002 19:39:39 GMT
scolebourne    2002/12/22 11:39:39

  Modified:    lang/src/test/org/apache/commons/lang/math
                        MathTestSuite.java
  Added:       lang/src/test/org/apache/commons/lang/math FractionTest.java
               lang/src/java/org/apache/commons/lang/math Fraction.java
  Log:
  Add Fraction class and associated tests
  
  Revision  Changes    Path
  1.2       +2 -1      jakarta-commons/lang/src/test/org/apache/commons/lang/math/MathTestSuite.java
  
  Index: MathTestSuite.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/lang/src/test/org/apache/commons/lang/math/MathTestSuite.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- MathTestSuite.java	22 Dec 2002 16:20:29 -0000	1.1
  +++ MathTestSuite.java	22 Dec 2002 19:39:39 -0000	1.2
  @@ -87,6 +87,7 @@
           suite.setName("Commons-Lang-Math Tests");
           suite.addTest(DoubleRangeTest.suite());
           suite.addTest(FloatRangeTest.suite());
  +        suite.addTest(FractionTest.suite());
           suite.addTest(IntRangeTest.suite());
           suite.addTest(LongRangeTest.suite());
           suite.addTest(NumberRangeTest.suite());
  
  
  
  1.1                  jakarta-commons/lang/src/test/org/apache/commons/lang/math/FractionTest.java
  
  Index: FractionTest.java
  ===================================================================
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Commons", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.lang.math;
  
  import junit.framework.Test;
  import junit.framework.TestCase;
  import junit.framework.TestSuite;
  /**
   * Test cases for the {@link Fraction} classes.
   *
   * @author Stephen Colebourne
   * @version $Id: FractionTest.java,v 1.1 2002/12/22 19:39:39 scolebourne Exp $
   */
  public class FractionTest extends TestCase {
      
      private static final int SKIP = 10000;
  
      public FractionTest(String name) {
          super(name);
      }
  
      public static Test suite() {
          TestSuite suite = new TestSuite(FractionTest.class);
          suite.setName("Fraction Tests");
          return suite;
      }
      
      public void setUp() {
      }
  
      //--------------------------------------------------------------------------
      
      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());
      }
      
      public void testFactory_int_int() {
          Fraction f = null;
          
          // 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
          try {
              f = Fraction.getFraction(1, 0);
          } catch (ArithmeticException ex) {}
          
          try {
              f = Fraction.getFraction(2, 0);
          } catch (ArithmeticException ex) {}
          
          try {
              f = Fraction.getFraction(-3, 0);
          } catch (ArithmeticException ex) {}
      }
  
      public void testFactory_int_int_int() {
          Fraction f = null;
          
          // 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
          try {
              f = Fraction.getFraction(1, -6, -10);
          } catch (ArithmeticException ex) {}
  
          try {
              f = Fraction.getFraction(1, -6, -10);
          } catch (ArithmeticException ex) {}
  
          try {
              f = Fraction.getFraction(1, -6, -10);
          } catch (ArithmeticException ex) {}
          
          // negative whole
          f = Fraction.getFraction(-1, 6, 10);
          assertEquals(-16, f.getNumerator());
          assertEquals(10, f.getDenominator());
          
          try {
              f = Fraction.getFraction(-1, -6, 10);
          } catch (ArithmeticException ex) {}
  
          try {
              f = Fraction.getFraction(-1, 6, -10);
          } catch (ArithmeticException ex) {}
          
          try {
              f = Fraction.getFraction(-1, -6, -10);
          } catch (ArithmeticException ex) {}
          
          // zero denominator
          try {
              f = Fraction.getFraction(0, 1, 0);
          } catch (ArithmeticException ex) {}
          
          try {
              f = Fraction.getFraction(1, 2, 0);
          } catch (ArithmeticException ex) {}
          
          try {
              f = Fraction.getFraction(-1, -3, 0);
          } catch (ArithmeticException ex) {}
      }
  
      public void testReducedFactory_int_int() {
          Fraction f = null;
          
          // 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
          try {
              f = Fraction.getReducedFraction(1, 0);
          } catch (ArithmeticException ex) {}
          
          try {
              f = Fraction.getReducedFraction(2, 0);
          } catch (ArithmeticException ex) {}
          
          try {
              f = Fraction.getReducedFraction(-3, 0);
          } catch (ArithmeticException ex) {}
  
          // 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());
      }
  
      public void testFactory_double() {
          Fraction f = null;
          
          try {
              f = Fraction.getFraction(Double.NaN);
          } catch (ArithmeticException ex) {}
          
          try {
              f = Fraction.getFraction(Double.POSITIVE_INFINITY);
          } catch (ArithmeticException ex) {}
          
          try {
              f = Fraction.getFraction(Double.NEGATIVE_INFINITY);
          } catch (ArithmeticException ex) {}
          
          // zero
          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;
          int remainder, number1, number2 = 0;
          for (int i = 1; i <= 100; i++) {  // denominator
              for (int j = 1; j <= i; j++) {  // numerator
                  try {
                      f = Fraction.getFraction((double) j / (double) i);
                  } catch (ArithmeticException ex) {
                      System.err.println(j + " " + i);
                      throw ex;
                  }
                  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
                  try {
                      f = Fraction.getFraction((double) j / (double) i);
                  } catch (ArithmeticException ex) {
                      System.err.println(j + " " + i);
                      throw ex;
                  }
                  f2 = Fraction.getReducedFraction(j, i);
                  assertEquals(f2.getNumerator(), f.getNumerator());
                  assertEquals(f2.getDenominator(), f.getDenominator());
              }
          }
      }
  
      public void testFactory_String() {
          try {
              Fraction.getFraction(null);
          } catch (IllegalArgumentException ex) {}
      }
      
      public void testFactory_String_double() {
          Fraction f = null;
          
          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());
          
          try {
              f = Fraction.getFraction("2.3R");
          } catch (NumberFormatException ex) {}
          
          try {
              f = Fraction.getFraction(".");
          } catch (NumberFormatException ex) {}
      }
  
      public void testFactory_String_proper() {
          Fraction f = null;
          
          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());
          
          try {
              f = Fraction.getFraction("2 3");
          } catch (NumberFormatException ex) {}
          
          try {
              f = Fraction.getFraction("a 3");
          } catch (NumberFormatException ex) {}
          
          try {
              f = Fraction.getFraction("2 b/4");
          } catch (NumberFormatException ex) {}
          
          try {
              f = Fraction.getFraction("2 ");
          } catch (NumberFormatException ex) {}
  
          try {
              f = Fraction.getFraction(" 3");
          } catch (NumberFormatException ex) {}
          
          try {
              f = Fraction.getFraction(" ");
          } catch (NumberFormatException ex) {}
      }
  
      public void testFactory_String_improper() {
          Fraction f = null;
          
          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());
          
          try {
              f = Fraction.getFraction("2/d");
          } catch (NumberFormatException ex) {}
          
          try {
              f = Fraction.getFraction("2e/3");
          } catch (NumberFormatException ex) {}
          
          try {
              f = Fraction.getFraction("2/");
          } catch (NumberFormatException ex) {}
          
          try {
              f = Fraction.getFraction("/");
          } catch (NumberFormatException ex) {}
      }
  
      public void testGets() {
          Fraction f = null;
          
          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());
      }
              
      public void testConversions() {
          Fraction f = null;
          
          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);
      }
      
      public void testReduce() {
          Fraction f = null;
          
          f = Fraction.getFraction(50, 75);
          f = f.reduce();
          assertEquals(2, f.getNumerator());
          assertEquals(3, f.getDenominator());
      }
      
      public void testInvert() {
          Fraction f = null;
          
          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(0, 3);
          try {
              f = f.invert();
          } catch (ArithmeticException ex) {}
      }
      
      public void testNegate() {
          Fraction f = null;
          
          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());
      }
      
      public void testAbs() {
          Fraction f = null;
          
          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());
      }
      
      public void testPow() {
          Fraction f = null;
          
          f = Fraction.getFraction(3, 5);
          assertEquals(Fraction.ONE, f.pow(0));
          
          f = Fraction.getFraction(3, 5);
          assertSame(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());
      }
      
      public void testAdd() {
          Fraction f = null;
          Fraction f1 = null;
          Fraction f2 = null;
          
          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(3, 5);
          f2 = Fraction.getFraction(1, 2);
          f = f1.add(f2);
          assertEquals(11, f.getNumerator());
          assertEquals(10, 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);
          
          try {
              f.add(null);
          } catch (IllegalArgumentException ex) {}
      }
              
      public void testSubtract() {
          Fraction f = null;
          Fraction f1 = null;
          Fraction f2 = null;
          
          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(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);
          
          try {
              f.subtract(null);
          } catch (IllegalArgumentException ex) {}
      }
              
      public void testMultiply() {
          Fraction f = null;
          Fraction f1 = null;
          Fraction f2 = null;
          
          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(-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);
          
          try {
              f.multiplyBy(null);
          } catch (IllegalArgumentException ex) {}
      }
              
      public void testDivide() {
          Fraction f = null;
          Fraction f1 = null;
          Fraction f2 = null;
          
          f1 = Fraction.getFraction(3, 5);
          f2 = Fraction.getFraction(2, 5);
          f = f1.divideBy(f2);
          assertEquals(3, f.getNumerator());
          assertEquals(2, f.getDenominator());
          
          f1 = Fraction.getFraction(3, 5);
          f2 = Fraction.ZERO;
          try {
              f = f1.divideBy(f2);
          } catch (ArithmeticException ex) {}
          
          f1 = Fraction.getFraction(0, 5);
          f2 = Fraction.getFraction(2, 7);
          f = f1.divideBy(f2);
          assertSame(Fraction.ZERO, f);
          
          try {
              f.divideBy(null);
          } catch (IllegalArgumentException ex) {}
      }
              
      public void testEquals() {
          Fraction f1 = null;
          Fraction f2 = null;
          
          f1 = Fraction.getFraction(3, 5);
          assertEquals(false, f1.equals(null));
          assertEquals(false, f1.equals(new Object()));
          assertEquals(false, f1.equals(new Integer(6)));
          
          f1 = Fraction.getFraction(3, 5);
          f2 = Fraction.getFraction(2, 5);
          assertEquals(false, f1.equals(f2));
          assertEquals(true, f1.equals(f1));
          assertEquals(true, f2.equals(f2));
          
          f2 = Fraction.getFraction(3, 5);
          assertEquals(true, f1.equals(f2));
          
          f2 = Fraction.getFraction(6, 10);
          assertEquals(false, f1.equals(f2));
      }
      
      public void testHashCode() {
          Fraction f1 = Fraction.getFraction(3, 5);
          Fraction f2 = Fraction.getFraction(3, 5);
          
          assertTrue(f1.hashCode() == f2.hashCode());
          
          f2 = Fraction.getFraction(2, 5);
          assertTrue(f1.hashCode() != f2.hashCode());
          
          f2 = Fraction.getFraction(6, 10);
          assertTrue(f1.hashCode() != f2.hashCode());
      }
      
      public void testCompareTo() {
          Fraction f1 = null;
          Fraction f2 = null;
          
          f1 = Fraction.getFraction(3, 5);
          
          try {
              f1.compareTo(null);
          } catch (NullPointerException ex) {}
          
          try {
              f1.compareTo(new Object());
          } catch (ClassCastException ex) {}
          
          f2 = Fraction.getFraction(2, 5);
          assertTrue(f1.compareTo(f2) > 0);
          
          f2 = Fraction.getFraction(4, 5);
          assertTrue(f1.compareTo(f2) < 0);
          
          f2 = Fraction.getFraction(3, 5);
          assertTrue(f1.compareTo(f2) == 0);
          
          f2 = Fraction.getFraction(6, 10);
          assertTrue(f1.compareTo(f2) == 0);
      }
      
      public void testToString() {
          Fraction f = null;
  
          f = Fraction.getFraction(3, 5);
          assertEquals("3/5", 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());        
      }
      
      public void testToProperString() {
          Fraction f = null;
  
          f = Fraction.getFraction(3, 5);
          assertEquals("3/5", 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());        
      }
      
  }
  
  
  
  1.1                  jakarta-commons/lang/src/java/org/apache/commons/lang/math/Fraction.java
  
  Index: Fraction.java
  ===================================================================
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Commons", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.lang.math;
  
  import java.io.Serializable;
  
  /**
   * <p><code>Fraction</code> is a <code>Number</code> implementation that
   * stores fractions accurately.</p>
   * 
   * <p>This class is immutable, and interoperable with most methods that accept
   * a <code>Number</code>.</p>
   *
   * @author Travis Reeder
   * @author Stephen Colebourne
   * @since 2.0
   * @version $Id: Fraction.java,v 1.1 2002/12/22 19:39:39 scolebourne Exp $
   */
  public final class Fraction extends Number implements Serializable, Comparable {
      
      private static final long serialVersionUID = 65382027393090L;
      
      public static final Fraction ZERO = new Fraction(0, 1);
      public static final Fraction ONE = new Fraction(1, 1);
      
      public static final Fraction ONE_HALF = new Fraction(1, 2);
      
      public static final Fraction ONE_THIRD = new Fraction(1, 3);
      public static final Fraction TWO_THIRDS = new Fraction(2, 3);
      
      public static final Fraction ONE_QUARTER = new Fraction(1, 4);
      public static final Fraction TWO_QUARTERS = new Fraction(2, 4);
      public static final Fraction THREE_QUARTERS = new Fraction(3, 4);
      
      public static final Fraction ONE_FIFTH = new Fraction(1, 5);
      public static final Fraction TWO_FIFTHS = new Fraction(2, 5);
      public static final Fraction THREE_FIFTHS = new Fraction(3, 5);
      public static final Fraction FOUR_FIFTHS = new Fraction(4, 5);
      
  
      /** The numerator number part of the fraction (the three in three sevenths) */
      private final int numerator;
      /** The denominator number part of the fraction (the seven in three sevenths) */
      private final int denominator;
  
      /** Cached output hashCode (class is immutable) */
      private transient int hashCode = 0;
      /** Cached output toString (class is immutable) */
      private transient String toString = null;
      /** Cached output toProperString (class is immutable) */
      private transient String toProperString = null;
      
      /**
       * <p>Constructs a <code>Fraction</code> instance with the 2 parts 
       * of a fraction Y/Z.</p>
       * 
       * @param numerator  the numerator, for example the three in 'three sevenths'
       * @param denominator  the denominator, for example the seven in 'three sevenths'
       */
      private Fraction(int numerator, int denominator) {
          super();
          this.numerator = numerator;
          this.denominator = denominator;
      }
      
      /**
       * <p>Creates a <code>Fraction</code> instance with the 2 parts 
       * of a fraction Y/Z.</p>
       * 
       * <p>Any negative signs are resolved to be on the numerator.</p>
       * 
       * @param numerator  the numerator, for example the three in 'three sevenths'
       * @param denominator  the denominator, for example the seven in 'three sevenths'
       * @return a new fraction instance
       * @throws ArithmeticException if the denomiator is zero
       */
      public static Fraction getFraction(int numerator, int denominator) {
          if (denominator == 0) {
              throw new ArithmeticException("The denominator must not be zero");
          }
          if (denominator < 0) {
              numerator = -numerator;
              denominator = -denominator;
          }
          return new Fraction(numerator, denominator);
      }
  
      /**
       * <p>Creates a <code>Fraction</code> instance with the 3 parts 
       * of a fraction X Y/Z.</p>
       * 
       * <p>The negative sign must be passed in on the whole number part.</p>
       * 
       * @param whole  the whole number, for example the one in 'one and three sevenths'
       * @param numerator  the numerator, for example the three in 'one and three sevenths'
       * @param denominator  the denominator, for example the seven in 'one and three sevenths'
       * @return a new fraction instance
       * @throws ArithmeticException if the denomiator is zero
       * @throws ArithmeticException if the denomiator is negative
       * @throws ArithmeticException if the numerator is negative
       */
      public static Fraction getFraction(int whole, int numerator, int denominator) {
          if (denominator == 0) {
              throw new ArithmeticException("The denominator must not be zero");
          }
          if (denominator < 0) {
              throw new ArithmeticException("The denominator must not be negative");
          }        
          if (numerator < 0) {
              throw new ArithmeticException("The numerator must not be negative");
          }
          if (whole < 0) {
              numerator = whole * denominator - numerator;
          } else {
              numerator = whole * denominator + numerator;
          }
          return new Fraction(numerator, denominator);
      }
  
      /**
       * <p>Creates a <code>Fraction</code> instance with the 2 parts 
       * of a fraction Y/Z.</p>
       * 
       * <p>Any negative signs are resolved to be on the numerator.</p>
       * 
       * @param numerator  the numerator, for example the three in 'three sevenths'
       * @param denominator  the denominator, for example the seven in 'three sevenths'
       * @return a new fraction instance, with the numerator and denominator reduced
       * @throws ArithmeticException if the denomiator is zero
       */
      public static Fraction getReducedFraction(int numerator, int denominator) {
          if (denominator == 0) {
              throw new ArithmeticException("The denominator must not be zero");
          }
          if (denominator < 0) {
              numerator = -numerator;
              denominator = -denominator;
          }
          int gcd = greatestCommonDenominator(Math.abs(numerator), denominator);
          if (gcd == 0) {
              return new Fraction(numerator, denominator);
          }
          return new Fraction(numerator / gcd, denominator / gcd);
      }
      
      /**
       * <p>Creates a <code>Fraction</code> instance from a <code>double</code> value.</p>
       * 
       * <p>This method uses the continued fraction algorithm.</p>
       *
       * @param value  the double value to convert
       * @return a new fraction instance that is close to the value
       * @throws ArithmeticException if the value is infinite or NaN
       * @throws ArithmeticException if the calculated denomiator is zero
       */
      public static Fraction getFraction(double value) {
          if (Double.isInfinite(value) || Double.isNaN(value)) {
              throw new ArithmeticException("The value must not be infinite or NaN");
          }
          int sign = (value < 0 ? -1 : 1);
          value = Math.abs(value);
          int wholeNumber = (int) value;
          value -= wholeNumber;
          
          // http://archives.math.utk.edu/articles/atuyl/confrac/
          int numer0 = 0;  // the pre-previous
          int denom0 = 1;  // the pre-previous
          int numer1 = 1;  // the previous
          int denom1 = 0;  // the previous
          int numer2 = 0;  // the current, setup in calculation
          int denom2 = 0;  // the current, setup in calculation
          int a1 = (int) value;
          int a2 = 0;
          double x1 = 1;
          double x2 = 0;
          double y1 = value - a1;
          double y2 = 0;
          double delta1, delta2 = Double.MAX_VALUE;
          double fraction;
          int i = 1;
  //        System.out.println("---");
          do {
              delta1 = delta2;
              a2 = (int) (x1 / y1);
              x2 = y1;
              y2 = x1 - a2 * y1;
              numer2 = a1 * numer1 + numer0;
              denom2 = a1 * denom1 + denom0;
              fraction = (double) numer2 / (double) denom2;
              delta2 = Math.abs(value - fraction);
  //            System.out.println(numer2 + " " + denom2 + " " + fraction + " " + delta2 + " " + y1);
              a1 = a2;
              x1 = x2;
              y1 = y2;
              numer0 = numer1;
              denom0 = denom1;
              numer1 = numer2;
              denom1 = denom2;
              i++;
  //            System.out.println(">>" + delta1 +" "+ delta2+" "+(delta1 > delta2)+" "+i+" "+denom2);
          } while ((delta1 > delta2) && (denom2 <= 10000) && (denom2 > 0) && (i < 25));
          if (i == 25) {
              throw new ArithmeticException("Unable to convert double to fraction");
          }
          return getReducedFraction((numer0 + wholeNumber * denom0) * sign, denom0);
      }
  
      /**
       * <p>Creates a Fraction from a <code>String</code>.</p>
       * 
       * <p>The formats accepted are:</p>
       * <ol>
       * <li><code>double</code> String containing a dot
       * <li>'X Y/Z'
       * <li>'Y/Z'
       * </ol> and a .</p>
       * 
       * @param str  the string to parse, must not be <code>null</code>
       * @return the new <code>Fraction</code> instance
       * @throws IllegalArgumentException if the string is null
       * @throws NumberFormatException if the number format is invalid
       */
      public static Fraction getFraction(String str) {
          if (str == null) {
              throw new IllegalArgumentException("The string must not be null");
          }
          // parse double format
          int pos = str.indexOf('.');
          if (pos >= 0) {
              return getFraction(Double.parseDouble(str));
          }
          
          // parse X Y/Z format
          pos = str.indexOf(' ');
          if (pos > 0) {
              int whole = Integer.parseInt(str.substring(0, pos));
              str = str.substring(pos + 1);
              pos = str.indexOf('/');
              if (pos < 0) {
                  throw new NumberFormatException("The fraction could not be parsed as the format X Y/Z");
              } else {
                  int denom = Integer.parseInt(str.substring(pos + 1));
                  return getFraction(
                      Integer.parseInt(str.substring(0, pos)) + whole * denom,
                      denom
                  );
              }
          }
          
          // parse Y/Z format
          pos = str.indexOf('/');
          if (pos < 0) {
              // simple whole number
              return getFraction(Integer.parseInt(str), 1);
          } else {
              return getFraction(
                  Integer.parseInt(str.substring(0, pos)),
                  Integer.parseInt(str.substring(pos + 1))
              );
          }
      }
  
      // Accessors
      //-------------------------------------------------------------------
  
      /**
       * <p>Gets the numerator part of the fraction.</p>
       * 
       * <p>This method may return a value greater than the denominator, an
       * improper fraction, such as the seven in 7/8.</p>
       * 
       * @return the numerator fraction part
       */
      public int getNumerator() {
          return numerator;
      }
  
      /**
       * <p>Gets the denominator part of the fraction.</p>
       * 
       * @return the denominator fraction part
       */
      public int getDenominator() {
          return denominator;
      }
      
      /**
       * <p>Gets the proper numerator, always positive.</p>
       * 
       * <p>An improper fraction 7/8 can be resolved into a proper one, 1 3/4.
       * This method returns the 3 from the proper fraction.</p>
       * 
       * <p>If the fraction is negative such as -7/8, it can be resolved into
       * -1 3/4, so this method returns the positive proper numerator, 3.</p>
       * 
       * @return the numerator fraction part of a proper fraction, always positive
       */
      public int getProperNumerator() {
          return Math.abs(numerator % denominator);
      }
  
      /**
       * <p>Gets the proper whole part of the fraction.</p>
       * 
       * <p>An improper fraction 7/8 can be resolved into a proper one, 1 3/4.
       * This method returns the 1 from the proper fraction.</p>
       * 
       * <p>If the fraction is negative such as -7/8, it can be resolved into
       * -1 3/4, so this method returns the positive whole part -1.</p>
       * 
       * @return the whole fraction part of a proper fraction, that includes the sign
       */
      public int getProperWhole() {
          return numerator / denominator;
      }
  
      // Number methods
      //-------------------------------------------------------------------
  
      /**
       * <p>Gets the fraction as an <code>int</code>. This returns the whole number
       * part of the fraction.</p>
       * 
       * @return the whole number fraction part
       */
      public int intValue() {
          return (int) numerator / denominator;
      }
  
      /**
       * <p>Gets the fraction as a <code>long</code>. This returns the whole number
       * part of the fraction.</p>
       * 
       * @return the whole number fraction part
       */
      public long longValue() {
          return (long) numerator / denominator;
      }
  
      /**
       * <p>Gets the fraction as a <code>float</code>. This calculates the fraction
       * as the numerator divided by denominator.</p>
       * 
       * @return the fraction as a <code>float</code>
       */
      public float floatValue() {
          return ((float) numerator) / ((float) denominator);
      }
  
      /**
       * <p>Gets the fraction as a <code>double</code>. This calculates the fraction
       * as the numerator divided by denominator.</p>
       * 
       * @return the fraction as a <code>double</code>
       */
      public double doubleValue() {
          return ((double) numerator) / ((double) denominator);
      }
  
      // Calculations
      //-------------------------------------------------------------------
  
      /**
       * <p>Reduce the fraction to the smallest values for the numerator and 
       * denominator, returning the result..</p>
       * 
       * @return a new reduce fraction instance, or this if no simplification possible
       */
      public Fraction reduce() {
          int gcd = greatestCommonDenominator(Math.abs(numerator), denominator);
          if (gcd == 0) {
              return this;
          }
          return Fraction.getFraction(numerator / gcd, denominator / gcd);
      }
      
      /**
       * <p>Gets a fraction that is the invert (1/fraction) of this one.</p>
       * 
       * <p>The returned fraction is not reduced.</p>
       * 
       * @return a new fraction instance with the numerator and denominator inverted
       * @throws ArithmeticException if the numerator is zero
       */
      public Fraction invert() {
          if (numerator == 0) {
              throw new ArithmeticException("Unable to invert a fraction with a zero numerator");
          }
          return getFraction(denominator, numerator);
      }
      
      /**
       * <p>Gets a fraction that is the negative (-fraction) of this one.</p>
       * 
       * <p>The returned fraction is not reduced.</p>
       * 
       * @return a new fraction instance with the opposite signed numerator
       */
      public Fraction negate() {
          return getFraction(-numerator, denominator);
      }
      
      /**
       * <p>Gets a fraction that is the positive equivalent
       * (fraction >= 0 ? this : -fraction) of this one.</p>
       * 
       * <p>The returned fraction is not reduced.</p>
       * 
       * @return <code>this</code> if it is positive, or a new positive fraction
       *  instance with the opposite signed numerator
       */
      public Fraction abs() {
          if (numerator >= 0) {
              return this;
          }
          return getFraction(-numerator, denominator);
      }
  
      /**
       * <p>Gets a fraction that is raised to the passed in power.</p>
       * 
       * <p>The returned fraction is not reduced.</p>
       * 
       * @param power  the power to raise the fraction to
       * @return <code>this</code> if the power is one, <code>ONE</code> if the power 
       * is zero or a new fraction instance raised to the appropriate power
       */
      public Fraction pow(int power) {
          if (power == 1) {
              return this;
          } else if (power == 0) {
              return ONE;
          } else if (power < 0) {
              return getFraction((int) Math.pow(denominator, -power), (int) Math.pow(numerator, -power));
          }
          return getFraction((int) Math.pow(numerator, power), (int) Math.pow(denominator, power));
      }
  
      /**
       * <p>Gets the greatest common denominator of two numbers.</p>
       * 
       * @param number1  a positive number
       * @param number2  a positive number
       * @return the greatest common denominator
       */
      private static int greatestCommonDenominator(int number1, int number2) {
          int remainder = number1 % number2;
          while (remainder != 0) {
              number1 = number2;
              number2 = remainder;
              remainder = number1 % number2;
          }
          return number2;
      }
  
      // Arithmetic
      //-------------------------------------------------------------------
  
      /**
       * <p>Adds the value of this fraction to another, returning the result.</p>
       * 
       * <p>The implementation spots common cases of zero numerators and equal 
       * denominators. Otherwise, it uses <code>(a/b) + (c/d) = (a*d + b*c) / (b*d)</code>
       * and then reduces the result.</p>
       * 
       * @param the fraction to add, must not be <code>null</code>
       * @return a <code>Fraction</code> instance with the resulting values
       * @throws IllegalArgumentException if the fraction is null
       */
      public Fraction add(Fraction fraction) {
          if (fraction == null) {
              throw new IllegalArgumentException("The fraction must not be null");
          }
          if (numerator == 0) {
              return fraction;
          }
          if (fraction.numerator == 0) {
              return this;
          }
          if (denominator == fraction.denominator) {
              return getReducedFraction(numerator + fraction.numerator, denominator);
          }
          return getReducedFraction(
              numerator * fraction.denominator + denominator * fraction.numerator,
              denominator * fraction.denominator
          );
      }
  
      /**
       * <p>Subtracts the value of another fraction from the value of this one, 
       * returning the result.</p>
       * 
       * <p>The implementation spots common cases of zero numerators and equal 
       * denominators. Otherwise, it uses <code>(a/b) - (c/d) = (a*d - b*c) / (b*d)</code>
       * and then reduces the result.</p>
       * 
       * @param the fraction to subtract, must not be <code>null</code>
       * @return a <code>Fraction</code> instance with the resulting values
       * @throws IllegalArgumentException if the fraction is null
       */
      public Fraction subtract(Fraction fraction) {
          if (fraction == null) {
              throw new IllegalArgumentException("The fraction must not be null");
          }
          if (numerator == 0) {
              return fraction.negate();
          }
          if (fraction.numerator == 0) {
              return this;
          }
          if (denominator == fraction.denominator) {
              return getReducedFraction(numerator - fraction.numerator, denominator);
          }
          return getReducedFraction(
              numerator * fraction.denominator - denominator * fraction.numerator,
              denominator * fraction.denominator
          );
      }
      
      /**
       * <p>Multiplies the value of this fraction by another, returning the result.</p>
       * 
       * <p>The implementation uses <code>(a/b)*(c/d) = (a*c)/(b*d)</code>
       * and then reduces the result.</p>
       * 
       * @param the fraction to multipy by, must not be <code>null</code>
       * @return a <code>Fraction</code> instance with the resulting values
       * @throws IllegalArgumentException if the fraction is null
       */
      public Fraction multiplyBy(Fraction fraction) {
          if (fraction == null) {
              throw new IllegalArgumentException("The fraction must not be null");
          }
          if (numerator == 0 || fraction.numerator == 0) {
              return ZERO;
          }
          return getReducedFraction(
              numerator * fraction.numerator,
              denominator * fraction.denominator
          );
      }
      
      /**
       * <p>Divide the value of this fraction by another, returning the result.</p>
       * 
       * <p>The implementation uses <code>(a/b)/(c/d) = a/b * d/c = (a*d)/(b*c)</code>
       * and then reduces the result.</p>
       * 
       * @param the fraction to divide by, must not be <code>null</code>
       * @return a <code>Fraction</code> instance with the resulting values
       * @throws IllegalArgumentException if the fraction is null
       * @throws ArithmeticException if the fraction to divide by is zero
       */
      public Fraction divideBy(Fraction fraction) {
          if (fraction == null) {
              throw new IllegalArgumentException("The fraction must not be null");
          }
          if (fraction.numerator == 0) {
              throw new ArithmeticException("The fraction to divide by must not be zero");
          }
          if (numerator == 0) {
              return ZERO;
          }
          return getReducedFraction(
              numerator * fraction.denominator,
              denominator * fraction.numerator
          );
      }
  
      // Basics
      //-------------------------------------------------------------------
  
      /**
       * <p>Compares this fraction to another object to test if they are equal.</p>.
       * 
       * <p>To be equal, both values must be equal. Thus 2/4 is not equal to 1/2.</p>
       *
       * @param obj the reference object with which to compare
       * @return <code>true</code> if this object is equal
       */
      public boolean equals(Object obj) {
          if (obj == this) {
              return true;
          }
          if (obj instanceof Fraction == false) {
              return false;
          }
          Fraction other = (Fraction) obj;
          return (numerator == other.numerator &&
                  denominator == other.denominator);
      }
  
      /**
       * <p>Gets a hashCode for the fraction.</p>
       *
       * @return a hash code value for this object
       */
      public int hashCode() {
          if (hashCode == 0) {
              hashCode = 17;
              hashCode = 37 * hashCode + numerator;
              hashCode = 37 * hashCode + denominator;
          }
          return hashCode;
      }
  
      /**
       * <p>Compares this object to another based on size.</p>
       * 
       * @param object  the object to compare to
       * @return -ve if this is less, 0 if equal, +ve if greater
       * @throws ClassCastException if the object is not a <code>Fraction</code>
       * @throws NullPointerException if the object is <code>null</code>
       */
      public int compareTo(Object object) {
          Fraction other = (Fraction) object;
          if (numerator == other.numerator && denominator == other.denominator) {
              return 0;
          }
  
          // otherwise see which is less
          long first = (long) numerator * (long) other.denominator;
          long second = (long) other.numerator * (long) denominator;
          if (first == second) {
              return 0;
          } else if (first < second) {
              return -1;
          } else {
              return 1;
          }
      }
  
      /**
       * <p>Gets the fraction as a <code>String</code>.</p>
       * 
       * <p>The format used is '<i>numerator</i>/<i>denominator</i>' always.
       * 
       * @return a <code>String</code> form of the fraction
       */
      public String toString() {
          if (toString == null) {
              toString = new StringBuffer(32)
                  .append(numerator)
                  .append('/')
                  .append(denominator).toString();
          }
          return toString;
      }
  
      /**
       * <p>Gets the fraction as a proper <code>String</code> in the format X Y/Z.</p>
       * 
       * <p>The format used in '<i>wholeNumber</i> <i>numerator</i>/<i>denominator</i>'.
       * If the whole number is zero it will be ommitted. If the numerator is zero,
       * only the whole number is returned.</p>
       * 
       * @return a <code>String</code> form of the fraction
       */
      public String toProperString() {
          if (toProperString == null) {
              if (numerator == 0) {
                  toProperString = "0";
              } else if (numerator == denominator) {
                  toProperString = "1";
              } else if (Math.abs(numerator) > denominator) {
                  int properNumerator = getProperNumerator();
                  if (properNumerator == 0) {
                      toProperString = Integer.toString(getProperWhole());
                  } else {
                      toProperString = new StringBuffer(32)
                          .append(getProperWhole()).append(' ')
                          .append(properNumerator).append('/')
                          .append(denominator).toString();
                  }
              } else {
                  toProperString = new StringBuffer(32)
                      .append(numerator).append('/')
                      .append(denominator).toString();
              }
          }
          return toProperString;
      }
      
  }
  
  
  

--
To unsubscribe, e-mail:   <mailto:commons-dev-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:commons-dev-help@jakarta.apache.org>


Mime
View raw message