You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by br...@apache.org on 2005/02/05 06:49:48 UTC

svn commit: r151479 - in jakarta/commons/proper/math/trunk: ./ src/java/org/apache/commons/math/fraction/ src/java/org/apache/commons/math/util/ src/test/org/apache/commons/math/fraction/ src/test/org/apache/commons/math/util/ xdocs/ xdocs/userguide/

Author: brentworden
Date: Fri Feb  4 21:49:45 2005
New Revision: 151479

URL: http://svn.apache.org/viewcvs?view=rev&rev=151479
Log:
added fraction class and fraction formatting classes.

Added:
    jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/fraction/
    jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/fraction/Fraction.java
    jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/fraction/FractionFormat.java
    jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/fraction/ProperFractionFormat.java
    jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/fraction/package.html
    jakarta/commons/proper/math/trunk/src/test/org/apache/commons/math/fraction/
    jakarta/commons/proper/math/trunk/src/test/org/apache/commons/math/fraction/FractionFormatTest.java
    jakarta/commons/proper/math/trunk/src/test/org/apache/commons/math/fraction/FractionTest.java
    jakarta/commons/proper/math/trunk/xdocs/userguide/fraction.xml
Modified:
    jakarta/commons/proper/math/trunk/project.properties
    jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/util/MathUtils.java
    jakarta/commons/proper/math/trunk/src/test/org/apache/commons/math/util/MathUtilsTest.java
    jakarta/commons/proper/math/trunk/xdocs/changes.xml
    jakarta/commons/proper/math/trunk/xdocs/navigation.xml
    jakarta/commons/proper/math/trunk/xdocs/tasks.xml
    jakarta/commons/proper/math/trunk/xdocs/userguide/index.xml

Modified: jakarta/commons/proper/math/trunk/project.properties
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/trunk/project.properties?view=diff&r1=151478&r2=151479
==============================================================================
--- jakarta/commons/proper/math/trunk/project.properties (original)
+++ jakarta/commons/proper/math/trunk/project.properties Fri Feb  4 21:49:45 2005
@@ -36,10 +36,7 @@
 
 maven.javadoc.links = http://java.sun.com/j2se/1.4.2/docs/api/,\
                       http://jakarta.apache.org/commons/collections/api/,\
-                      http://jakarta.apache.org/commons/beanutils/api/,\
-                      http://jakarta.apache.org/commons/lang/api/,\
-                      http://jakarta.apache.org/commons/discovery/api/,\
-                      http://jakarta.apache.org/commons/logging/api/
+                      http://jakarta.apache.org/commons/discovery/api/
 
 maven.changes.issue.template=http://issues.apache.org/bugzilla/show_bug.cgi?id=%ISSUE%
 

Added: jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/fraction/Fraction.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/fraction/Fraction.java?view=auto&rev=151479
==============================================================================
--- jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/fraction/Fraction.java (added)
+++ jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/fraction/Fraction.java Fri Feb  4 21:49:45 2005
@@ -0,0 +1,338 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed 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.math.fraction;
+
+import org.apache.commons.math.ConvergenceException;
+import org.apache.commons.math.util.MathUtils;
+
+/**
+ * Representation of a rational number.
+ *
+ * @author Apache Software Foundation
+ * @version $Revision: $ $Date: $
+ */
+public class Fraction extends Number implements Comparable {
+
+    /** A fraction representing "1 / 1". */
+    public static final Fraction ONE = new Fraction(1, 1);
+
+    /** A fraction representing "0 / 1". */
+    public static final Fraction ZERO = new Fraction(0, 1);
+    
+    /** Serializable version identifier */
+    static final long serialVersionUID = 65382027393090L;
+    
+    /** The denominator. */
+    private int denominator;
+    
+    /** The numerator. */
+    private int numerator;
+
+    /**
+     * Create a fraction given the double value.
+     * @param value the double value to convert to a fraction.
+     * @throws ConvergenceException if the continued fraction failed to
+     *         converge.
+     */
+    public Fraction(double value) throws ConvergenceException {
+        this(value, 1.0e-5, 100);
+    }
+
+    /**
+     * Create a fraction given the double value.
+     * <p>
+     * References:
+     * <ul>
+     * <li><a href="http://mathworld.wolfram.com/ContinuedFraction.html">
+     * Continued Fraction</a> equations (11) and (22)-(26)</li>
+     * </ul>
+     * </p>
+     * @param value the double value to convert to a fraction.
+     * @param epsilon maximum error allowed.  The resulting fraction is within
+     *        <code>epsilon</code> of <code>value</code>, in absolute terms.
+     * @param maxIterations maximum number of convergents
+     * @throws ConvergenceException if the continued fraction failed to
+     *         converge.
+     */
+    public Fraction(double value, double epsilon, int maxIterations)
+        throws ConvergenceException
+    {
+        double r0 = value;
+        int a0 = (int)Math.floor(r0);
+        
+        int p0 = 1;
+        int q0 = 0;
+        int p1 = a0;
+        int q1 = 1;
+
+        int p2 = 0;
+        int q2 = 1;
+
+        int n = 0;
+        boolean stop = false;
+        do {
+            ++n;
+            double r1 = 1.0 / (r0 - a0);
+            int a1 = (int)Math.floor(r1);
+            p2 = (a1 * p1) + p0;
+            q2 = (a1 * q1) + q0;
+            
+            double convergent = (double)p2 / (double)q2;
+            if (n < maxIterations && Math.abs(convergent - value) > epsilon) {
+                p0 = p1;
+                p1 = p2;
+                q0 = q1;
+                q1 = q2;
+                a0 = a1;
+                r0 = r1;
+            } else {
+                stop = true;
+            }
+        } while (!stop);
+
+        if (n >= maxIterations) {
+            throw new ConvergenceException(
+                    "Unable to convert double to fraction");
+        }
+        
+        this.numerator = p2;
+        this.denominator = q2;
+        reduce();
+    }
+    
+    /**
+     * Create a fraction given the numerator and denominator.  The fraction is
+     * reduced to lowest terms.
+     * @param num the numerator.
+     * @param den the denominator.
+     */
+    public Fraction(int num, int den) {
+        super();
+        this.numerator = num;
+        this.denominator = den;
+        reduce();
+    }
+    
+    /**
+     * Returns the absolute value of this fraction.
+     * @return the absolute value.
+     */
+    public Fraction abs() {
+        Fraction ret;
+        if (numerator >= 0) {
+            ret = this;
+        } else {
+            ret = negate();
+        }
+        return ret;        
+    }
+    
+    /**
+     * Return the sum of this fraction and the given fraction.  The returned
+     * fraction is reduced to lowest terms.
+     *
+     * @param rhs the other fraction.
+     * @return the fraction sum in lowest terms.
+     */
+    public Fraction add(Fraction rhs) {
+        int den = MathUtils.lcm(denominator, rhs.denominator);
+        int num = (numerator * (den / denominator)) +
+            (rhs.numerator * (den / rhs.denominator));
+        return new Fraction(num, den);
+    }
+    
+    /**
+     * Compares this object to another based on size.
+     * @param object the object to compare to
+     * @return -1 if this is less than <tt>object</tt>, +1 if this is greater
+     *         than <tt>object</tt>, 0 if they are equal.
+     */
+    public int compareTo(Object object) {
+        int ret = 0;
+        
+        if (this != object) { 
+            Fraction other = (Fraction)object;
+            double first = doubleValue();
+            double second = other.doubleValue();
+            
+            if (first < second) {
+                ret = -1;
+            } else if (first > second) {
+                ret = 1;
+            }
+        }
+        
+        return ret;
+    }
+
+    /**
+     * Return the quotient of this fraction and the given fraction.  The
+     * returned fraction is reduced to lowest terms.
+     * @param rhs the other fraction.
+     * @return the fraction quotient in lowest terms.
+     */
+    public Fraction divide(Fraction rhs) {
+        return multiply(rhs.reciprocal());
+    }
+    
+    /**
+     * Gets the fraction as a <tt>double</tt>. This calculates the fraction as
+     * the numerator divided by denominator.
+     * @return the fraction as a <tt>double</tt>
+     */
+    public double doubleValue() {
+        return (double)numerator / (double)denominator;
+    }
+    
+    /**
+     * Test for the equality of two fractions.  If the lowest term
+     * numerator and denominators are the same for both fractions, the two
+     * fractions are considered to be equal.
+     * @param other fraction to test for equality to this fraction
+     * @return true if two fractions are equal, false if object is
+     *         <tt>null</tt>, not an instance of {@link Fraction}, or not equal
+     *         to this fraction instance.
+     */
+    public boolean equals(Object other) {
+        boolean ret;
+        
+        if (this == other) { 
+            ret = true;
+        } else if (other == null) {
+            ret = false;
+        } else {
+            try {
+                // since fractions are always in lowest terms, numerators and
+                // denominators can be compared directly for equality.
+                Fraction rhs = (Fraction)other;
+                ret = (numerator == rhs.numerator) &&
+                    (denominator == rhs.denominator);
+            } catch (ClassCastException ex) {
+                // ignore exception
+                ret = false;
+            }
+        }
+        
+        return ret;
+    }
+    
+    /**
+     * Gets the fraction as a <tt>float</tt>. This calculates the fraction as
+     * the numerator divided by denominator.
+     * @return the fraction as a <tt>float</tt>
+     */
+    public float floatValue() {
+        return (float)doubleValue();
+    }
+    
+    /**
+     * Access the denominator.
+     * @return the denominator.
+     */
+    public int getDenominator() {
+        return denominator;
+    }
+    
+    /**
+     * Access the numerator.
+     * @return the numerator.
+     */
+    public int getNumerator() {
+        return numerator;
+    }
+    
+    /**
+     * Gets a hashCode for the fraction.
+     * @return a hash code value for this object
+     */
+    public int hashCode() {
+        return 37 * (37 * 17 + getNumerator()) + getDenominator();
+    }
+    
+    /**
+     * Gets the fraction as an <tt>int</tt>. This returns the whole number part
+     * of the fraction.
+     * @return the whole number fraction part
+     */
+    public int intValue() {
+        return (int)doubleValue();
+    }
+    
+    /**
+     * Gets the fraction as a <tt>long</tt>. This returns the whole number part
+     * of the fraction.
+     * @return the whole number fraction part
+     */
+    public long longValue() {
+        return (long)doubleValue();
+    }
+    
+    /**
+     * Return the product of this fraction and the given fraction.  The returned
+     * fraction is reduced to lowest terms.
+     * @param rhs the other fraction.
+     * @return the fraction product in lowest terms.
+     */
+    public Fraction multiply(Fraction rhs) {
+        return new Fraction(numerator * rhs.numerator, 
+                denominator * rhs.denominator);
+    }
+    
+    /**
+     * Return the additive inverse of this fraction.
+     * @return the negation of this fraction.
+     */
+    public Fraction negate() {
+        return new Fraction(-numerator, denominator);
+    }
+
+    /**
+     * Return the multiplicative inverse of this fraction.
+     * @return the reciprocal fraction
+     */
+    public Fraction reciprocal() {
+        return new Fraction(denominator, numerator);
+    }
+    
+    /**
+     * Return the difference between this fraction and the given fraction.  The
+     * returned fraction is reduced to lowest terms.
+     * @param rhs the other fraction.
+     * @return the fraction difference in lowest terms.
+     */
+    public Fraction subtract(Fraction rhs) {
+        return add(rhs.negate());
+    }
+    
+    /**
+     * Reduce this fraction to lowest terms.  This is accomplished by dividing
+     * both numerator and denominator by their greatest common divisor.
+     */
+    private void reduce() {
+        // reduce numerator and denominator by greatest common denominator.
+        int d = MathUtils.gcd(numerator, denominator);
+        if (d > 1) {
+            numerator /= d;
+            denominator /= d;
+        }
+
+        // move sign to numerator.
+        if (denominator < 0) {
+            numerator *= -1;
+            denominator *= -1;
+        }
+    }
+}

Added: jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/fraction/FractionFormat.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/fraction/FractionFormat.java?view=auto&rev=151479
==============================================================================
--- jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/fraction/FractionFormat.java (added)
+++ jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/fraction/FractionFormat.java Fri Feb  4 21:49:45 2005
@@ -0,0 +1,386 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed 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.math.fraction;
+
+import java.io.Serializable;
+import java.text.FieldPosition;
+import java.text.Format;
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.text.ParsePosition;
+import java.util.Locale;
+
+import org.apache.commons.math.ConvergenceException;
+
+/**
+ * Formats a Fraction number in proper format or improper format.  The number
+ * format for each of the whole number, numerator and, denominator can be
+ * configured.
+ *
+ * @author Apache Software Foundation
+ * @version $Revision: 1.10 $ $Date: 2004-09-20 23:45:55 -0500 (Mon, 20 Sep 2004) $
+ */
+public class FractionFormat extends Format implements Serializable {
+    
+    /** Serializable version identifier */
+    static final long serialVersionUID = -6337346779577272306L;
+
+    /** The format used for the denominator. */
+    private NumberFormat denominatorFormat;
+
+    /** The format used for the numerator. */
+    private NumberFormat numeratorFormat;
+    
+    /**
+     * Create an improper formatting instance with the default number format
+     * for the numerator and denominator.  
+     */
+    public FractionFormat() {
+        this(getDefaultNumberFormat());
+    }
+
+    /**
+     * Create an improper formatting instance with a custom number format for
+     * both the numerator and denominator.
+     * @param format the custom format for both the numerator and denominator.
+     */
+    public FractionFormat(NumberFormat format) {
+        this(format, (NumberFormat)format.clone());
+    }
+
+    /**
+     * Create an improper formatting instance with a custom number format for
+     * the numerator and a custom number format for the denominator.
+     * @param numeratorFormat the custom format for the numerator.
+     * @param denominatorFormat the custom format for the denominator.
+     */
+    public FractionFormat(NumberFormat numeratorFormat,
+            NumberFormat denominatorFormat)
+    {
+        super();
+        this.numeratorFormat = numeratorFormat;
+        this.denominatorFormat = denominatorFormat;
+    }
+
+    /**
+     * This static method calls formatFraction() on a default instance of
+     * FractionFormat.
+     *
+     * @param f Fraction object to format
+     * @return A formatted fraction in proper form.
+     */
+    public static String formatFraction(Fraction f) {
+    	return getImproperInstance().format(f);
+    }
+    
+    /**
+     * Get the set of locales for which complex formats are available.  This
+     * is the same set as the {@link NumberFormat} set. 
+     * @return available complex format locales.
+     */
+    public static Locale[] getAvailableLocales() {
+        return NumberFormat.getAvailableLocales();
+    }
+    
+    /**
+     * Returns the default complex format for the current locale.
+     * @return the default complex format.
+     */
+    public static FractionFormat getImproperInstance() {
+        return getImproperInstance(Locale.getDefault());
+    }
+    
+    /**
+     * Returns the default complex format for the given locale.
+     * @param locale the specific locale used by the format.
+     * @return the complex format specific to the given locale.
+     */
+    public static FractionFormat getImproperInstance(Locale locale) {
+        NumberFormat f = getDefaultNumberFormat(locale);
+        return new FractionFormat(f);
+    }
+    
+    /**
+     * Returns the default complex format for the current locale.
+     * @return the default complex format.
+     */
+    public static FractionFormat getProperInstance() {
+        return getProperInstance(Locale.getDefault());
+    }
+    
+    /**
+     * Returns the default complex format for the given locale.
+     * @param locale the specific locale used by the format.
+     * @return the complex format specific to the given locale.
+     */
+    public static FractionFormat getProperInstance(Locale locale) {
+        NumberFormat f = getDefaultNumberFormat(locale);
+        return new ProperFractionFormat(f);
+    }
+    
+    /**
+     * Create a default number format.  The default number format is based on
+     * {@link NumberFormat#getInstance()} with the only customizing is the
+     * maximum number of fraction digits, which is set to 2.  
+     * @return the default number format.
+     */
+    protected static NumberFormat getDefaultNumberFormat() {
+        return getDefaultNumberFormat(Locale.getDefault());
+    }
+    
+    /**
+     * Create a default number format.  The default number format is based on
+     * {@link NumberFormat#getInstance(java.util.Locale)} with the only
+     * customizing is the maximum number of fraction digits, which is set to 2.  
+     * @param locale the specific locale used by the format.
+     * @return the default number format specific to the given locale.
+     */
+    private static NumberFormat getDefaultNumberFormat(Locale locale) {
+        NumberFormat nf = NumberFormat.getIntegerInstance(locale);
+        return nf;
+    }
+    
+    /**
+     * Formats a {@link Fraction} object to produce a string.  The fraction is
+     * output in improper format.
+     *
+     * @param fraction the object to format.
+     * @param toAppendTo where the text is to be appended
+     * @param pos On input: an alignment field, if desired. On output: the
+     *            offsets of the alignment field
+     * @return the value passed in as toAppendTo.
+     */
+    public StringBuffer format(Fraction fraction, StringBuffer toAppendTo,
+            FieldPosition pos) {
+        
+        pos.setBeginIndex(0);
+        pos.setEndIndex(0);
+
+        getNumeratorFormat().format(fraction.getNumerator(), toAppendTo, pos);
+        toAppendTo.append(" / ");
+        getDenominatorFormat().format(fraction.getDenominator(), toAppendTo,
+            pos);
+        
+        return toAppendTo;
+    }
+    
+    /**
+     * Formats a object to produce a string.  <code>obj</code> must be either a 
+     * {@link Fraction} object or a {@link Number} object.  Any other type of
+     * object will result in an {@link IllegalArgumentException} being thrown.
+     *
+     * @param obj the object to format.
+     * @param toAppendTo where the text is to be appended
+     * @param pos On input: an alignment field, if desired. On output: the
+     *            offsets of the alignment field
+     * @return the value passed in as toAppendTo.
+     * @see java.text.Format#format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition)
+     * @throws IllegalArgumentException is <code>obj</code> is not a valid type.
+     */
+    public StringBuffer format(Object obj, StringBuffer toAppendTo,
+            FieldPosition pos)
+    {
+        StringBuffer ret = null;
+        
+        if (obj instanceof Fraction) {
+            ret = format( (Fraction)obj, toAppendTo, pos);
+        } else if (obj instanceof Number) {
+            try {
+                ret = format( new Fraction(((Number)obj).doubleValue()),
+                    toAppendTo, pos);
+            } catch (ConvergenceException ex) {
+                throw new IllegalArgumentException(
+                    "Cannot convert given object to a fraction.");
+            }
+        } else { 
+            throw new IllegalArgumentException(
+                "Cannot format given object as a fraction");
+        }
+        
+        return ret;
+    }
+
+    /**
+     * Access the denominator format.
+     * @return the denominator format.
+     */
+    public NumberFormat getDenominatorFormat() {
+        return denominatorFormat;
+    }
+    
+    /**
+     * Access the numerator format.
+     * @return the numerator format.
+     */
+    public NumberFormat getNumeratorFormat() {
+        return numeratorFormat;
+    }
+
+    /**
+     * Parses a string to produce a {@link Fraction} object.
+     * @param source the string to parse
+     * @return the parsed {@link Fraction} object.
+     * @exception ParseException if the beginning of the specified string
+     *            cannot be parsed.
+     */
+    public Fraction parse(String source) throws ParseException {
+        ParsePosition parsePosition = new ParsePosition(0);
+        Fraction result = parse(source, parsePosition);
+        if (parsePosition.getIndex() == 0) {
+            throw new ParseException("Unparseable fraction number: \"" +
+                source + "\"", parsePosition.getErrorIndex());
+        }
+        return result;
+    }
+    
+    /**
+     * Parses a string to produce a {@link Fraction} object.  This method
+     * expects the string to be formatted as an improper fraction.  
+     * @param source the string to parse
+     * @param pos input/ouput parsing parameter.
+     * @return the parsed {@link Fraction} object.
+     */
+    public Fraction parse(String source, ParsePosition pos) {
+        int initialIndex = pos.getIndex();
+
+        // parse whitespace
+        parseAndIgnoreWhitespace(source, pos);
+
+        // parse numerator
+        Number num = getNumeratorFormat().parse(source, pos);
+        if (num == null) {
+            // invalid integer number
+            // set index back to initial, error index should already be set
+            // character examined.
+            pos.setIndex(initialIndex);
+            return null;
+        }
+
+        // parse '/'
+        int startIndex = pos.getIndex();
+        char c = parseNextCharacter(source, pos);
+        switch (c) {
+        case 0 :
+            // no '/'
+            // return num as a fraction
+            return new Fraction(num.intValue(), 1);
+        case '/' :
+            // found '/', continue parsing denominator
+            break;
+        default :
+            // invalid '/'
+            // set index back to initial, error index should be the last
+            // character examined.
+            pos.setIndex(initialIndex);
+            pos.setErrorIndex(startIndex);
+            return null;
+        }
+
+        // parse whitespace
+        parseAndIgnoreWhitespace(source, pos);
+
+        // parse denominator
+        Number den = getDenominatorFormat().parse(source, pos);
+        if (den == null) {
+            // invalid integer number
+            // set index back to initial, error index should already be set
+            // character examined.
+            pos.setIndex(initialIndex);
+            return null;
+        }
+
+        return new Fraction(num.intValue(), den.intValue());
+    }
+
+    /**
+     * Parses a string to produce a object.
+     * @param source the string to parse
+     * @param pos input/ouput parsing parameter.
+     * @return the parsed object.
+     * @see java.text.Format#parseObject(java.lang.String, java.text.ParsePosition)
+     */
+    public Object parseObject(String source, ParsePosition pos) {
+        return parse(source, pos);
+    }
+    
+    /**
+     * Modify the denominator format.
+     * @param format the new denominator format value.
+     * @throws IllegalArgumentException if <code>format</code> is
+     *         <code>null</code>.
+     */
+    public void setDenominatorFormat(NumberFormat format) {
+        if (format == null) {
+            throw new IllegalArgumentException(
+                "denominator format can not be null.");
+        }
+        this.denominatorFormat = format;
+    }
+    
+    /**
+     * Modify the numerator format.
+     * @param format the new numerator format value.
+     * @throws IllegalArgumentException if <code>format</code> is
+     *         <code>null</code>.
+     */
+    public void setNumeratorFormat(NumberFormat format) {
+        if (format == null) {
+            throw new IllegalArgumentException(
+                "numerator format can not be null.");
+        }
+        this.numeratorFormat = format;
+    }
+     
+    /**
+     * Parses <code>source</code> until a non-whitespace character is found.
+     * @param source the string to parse
+     * @param pos input/ouput parsing parameter.  On output, <code>pos</code>
+     *        holds the index of the next non-whitespace character.
+     */
+    protected static void parseAndIgnoreWhitespace(
+        String source, ParsePosition pos)
+    {
+        parseNextCharacter(source, pos);
+        pos.setIndex(pos.getIndex() - 1);
+    }
+
+    /**
+     * Parses <code>source</code> until a non-whitespace character is found.
+     * @param source the string to parse
+     * @param pos input/ouput parsing parameter.
+     * @return the first non-whitespace character.
+     */
+    protected static char parseNextCharacter(String source, ParsePosition pos) {
+         int index = pos.getIndex();
+         int n = source.length();
+         char ret = 0;
+
+         if (index < n) {
+             char c;
+             do {
+                 c = source.charAt(index++);
+             } while (Character.isWhitespace(c) && index < n);
+             pos.setIndex(index);
+         
+             if (index < n) {
+                 ret = c;
+             }
+         }
+         
+         return ret;
+    }
+}

Added: jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/fraction/ProperFractionFormat.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/fraction/ProperFractionFormat.java?view=auto&rev=151479
==============================================================================
--- jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/fraction/ProperFractionFormat.java (added)
+++ jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/fraction/ProperFractionFormat.java Fri Feb  4 21:49:45 2005
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed 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.math.fraction;
+
+import java.text.FieldPosition;
+import java.text.NumberFormat;
+import java.text.ParsePosition;
+
+import org.apache.commons.math.util.MathUtils;
+
+/**
+ * Formats a Fraction number in proper format.  The number format for each of
+ * the whole number, numerator and, denominator can be configured.
+ * 
+ * @author Apache Software Foundation
+ * @version $Revision: $ $Date: $
+ */
+public class ProperFractionFormat extends FractionFormat {
+    
+    /** Serializable version identifier */
+    static final long serialVersionUID = -6337346779577272307L;
+    
+    /** The format used for the whole number. */
+    private NumberFormat wholeFormat;
+
+    /**
+     * Create a proper formatting instance with the default number format for
+     * the whole, numerator, and denominator.  
+     */
+    public ProperFractionFormat() {
+        this(getDefaultNumberFormat());
+    }
+    
+    /**
+     * Create a proper formatting instance with a custom number format for the
+     * whole, numerator, and denominator.
+     * @param format the custom format for the whole, numerator, and
+     *        denominator.
+     */
+    public ProperFractionFormat(NumberFormat format) {
+        this(format, (NumberFormat)format.clone(), (NumberFormat)format.clone());
+    }
+    
+    /**
+     * Create a proper formatting instance with a custom number format for each
+     * of the whole, numerator, and denominator.
+     * @param wholeFormat the custom format for the whole.
+     * @param numeratorFormat the custom format for the numerator.
+     * @param denominatorFormat the custom format for the denominator.
+     */
+    public ProperFractionFormat(NumberFormat wholeFormat,
+            NumberFormat numeratorFormat,
+            NumberFormat denominatorFormat)
+    {
+        super(numeratorFormat, denominatorFormat);
+        setWholeFormat(wholeFormat);
+    }
+    
+    /**
+     * Formats a {@link Fraction} object to produce a string.  The fraction
+     * is output in proper format.
+     *
+     * @param fraction the object to format.
+     * @param toAppendTo where the text is to be appended
+     * @param pos On input: an alignment field, if desired. On output: the
+     *            offsets of the alignment field
+     * @return the value passed in as toAppendTo.
+     */
+    public StringBuffer format(Fraction fraction, StringBuffer toAppendTo,
+            FieldPosition pos) {
+        
+        pos.setBeginIndex(0);
+        pos.setEndIndex(0);
+
+        int num = fraction.getNumerator();
+        int den = fraction.getDenominator();
+        int whole = num / den;
+        num = num % den;
+        
+        if (whole != 0) {
+            getWholeFormat().format(whole, toAppendTo, pos);
+            toAppendTo.append(' ');
+            num = Math.abs(num);
+        }
+        getNumeratorFormat().format(num, toAppendTo, pos);
+        toAppendTo.append(" / ");
+        getDenominatorFormat().format(den, toAppendTo,
+            pos);
+        
+        return toAppendTo;
+    }
+
+    /**
+     * Access the whole format.
+     * @return the whole format.
+     */
+    public NumberFormat getWholeFormat() {
+        return wholeFormat;
+    }
+    
+    /**
+     * Parses a string to produce a {@link Fraction} object.  This method
+     * expects the string to be formatted as a proper fraction.
+     * @param source the string to parse
+     * @param pos input/ouput parsing parameter.
+     * @return the parsed {@link Fraction} object.
+     */
+    public Fraction parse(String source, ParsePosition pos) {
+        // try to parse improper fraction
+        Fraction ret = super.parse(source, pos);
+        if (ret != null) {
+            return ret;
+        }
+        
+        int initialIndex = pos.getIndex();
+
+        // parse whitespace
+        parseAndIgnoreWhitespace(source, pos);
+
+        // parse whole
+        Number whole = getWholeFormat().parse(source, pos);
+        if (whole == null) {
+            // invalid integer number
+            // set index back to initial, error index should already be set
+            // character examined.
+            pos.setIndex(initialIndex);
+            return null;
+        }
+
+        // parse whitespace
+        parseAndIgnoreWhitespace(source, pos);
+        
+        // parse numerator
+        Number num = getNumeratorFormat().parse(source, pos);
+        if (num == null) {
+            // invalid integer number
+            // set index back to initial, error index should already be set
+            // character examined.
+            pos.setIndex(initialIndex);
+            return null;
+        }
+
+        // parse '/'
+        int startIndex = pos.getIndex();
+        char c = parseNextCharacter(source, pos);
+        switch (c) {
+        case 0 :
+            // no '/'
+            // return num as a fraction
+            return new Fraction(num.intValue(), 1);
+        case '/' :
+            // found '/', continue parsing denominator
+            break;
+        default :
+            // invalid '/'
+            // set index back to initial, error index should be the last
+            // character examined.
+            pos.setIndex(initialIndex);
+            pos.setErrorIndex(startIndex);
+            return null;
+        }
+
+        // parse whitespace
+        parseAndIgnoreWhitespace(source, pos);
+
+        // parse denominator
+        Number den = getDenominatorFormat().parse(source, pos);
+        if (den == null) {
+            // invalid integer number
+            // set index back to initial, error index should already be set
+            // character examined.
+            pos.setIndex(initialIndex);
+            return null;
+        }
+
+        int w = whole.intValue();
+        int n = num.intValue();
+        int d = den.intValue();
+        return new Fraction(((Math.abs(w) * d) + n) * MathUtils.sign(w), d);
+    }
+    
+    /**
+     * Modify the whole format.
+     * @param format The new whole format value.
+     * @throws IllegalArgumentException if <code>format</code> is
+     *         <code>null</code>.
+     */
+    public void setWholeFormat(NumberFormat format) {
+        if (format == null) {
+            throw new IllegalArgumentException(
+                "whole format can not be null.");
+        }
+        this.wholeFormat = format;
+    }
+}

Added: jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/fraction/package.html
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/fraction/package.html?view=auto&rev=151479
==============================================================================
--- jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/fraction/package.html (added)
+++ jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/fraction/package.html Fri Feb  4 21:49:45 2005
@@ -0,0 +1,21 @@
+<html>
+<!--
+   Copyright 2005 The Apache Software Foundation
+
+   Licensed 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.
+  -->
+	<!-- $Revision: 1.1 $ $Date: 2004/04/26 18:28:16 $ -->
+  <body>
+    Fraction number type and fraction number formatting.
+  </body>
+</html>
\ No newline at end of file

Modified: jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/util/MathUtils.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/util/MathUtils.java?view=diff&r1=151478&r2=151479
==============================================================================
--- jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/util/MathUtils.java (original)
+++ jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/util/MathUtils.java Fri Feb  4 21:49:45 2005
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2004 The Apache Software Foundation.
+ * Copyright 2003-2005 The Apache Software Foundation.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,7 +19,7 @@
 /**
  * Some useful additions to the built-in functions in {@link Math}.
  *
- * @version $Revision: 1.20 $ $Date: 2004/10/14 04:01:04 $
+ * @version $Revision: 1.20 $ $Date$
  */
 public final class MathUtils {
     
@@ -467,5 +467,44 @@
      */
     public static boolean equals(double x, double y) {
         return ((Double.isNaN(x) && Double.isNaN(y)) || x == y);
+    }
+
+    /**
+     * Returns the least common multiple between two integer values.
+     * @param a the first integer value.
+     * @param b the second integer value.
+     * @return the least common multiple between a and b.
+     */
+    public static int lcm(int a, int b) {
+        return Math.abs(a / gcd(a, b) * b);
+    }
+
+    /**
+     * Returns the greatest common divisor between two integer values.
+     * @param a the first integer value.
+     * @param b the second integer value.
+     * @return the greatest common divisor between a and b.
+     */
+    public static int gcd(int a, int b) {
+        int ret;
+        
+        if (a == 0) {
+            ret = Math.abs(b);
+        } else if (b == 0) {
+            ret = Math.abs(a);
+        } else if (a < 0) {
+            ret = gcd(-a, b);
+        } else if (b < 0) {
+            ret = gcd(a, -b);
+        } else {
+            int r = 0;
+            while(b > 0){
+                r = a % b;
+                a = b;
+                b = r;
+            }
+            ret = a;
+        }
+        return ret;
     }
 }

Added: jakarta/commons/proper/math/trunk/src/test/org/apache/commons/math/fraction/FractionFormatTest.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/trunk/src/test/org/apache/commons/math/fraction/FractionFormatTest.java?view=auto&rev=151479
==============================================================================
--- jakarta/commons/proper/math/trunk/src/test/org/apache/commons/math/fraction/FractionFormatTest.java (added)
+++ jakarta/commons/proper/math/trunk/src/test/org/apache/commons/math/fraction/FractionFormatTest.java Fri Feb  4 21:49:45 2005
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.math.fraction;
+
+import java.text.ParseException;
+import java.util.Locale;
+
+import junit.framework.TestCase;
+
+public class FractionFormatTest extends TestCase {
+ 
+	FractionFormat properFormat = null;
+	FractionFormat improperFormat = null;
+
+    protected Locale getLocale() {
+        return Locale.getDefault();
+    }
+
+	protected void setUp() throws Exception {
+		properFormat = FractionFormat.getProperInstance(getLocale());
+		improperFormat = FractionFormat.getImproperInstance(getLocale());
+	}
+   
+    public void testFormat() {
+        Fraction c = new Fraction(1, 2);
+        String expected = "1 / 2";
+        
+        String actual = properFormat.format(c); 
+        assertEquals(expected, actual);
+
+        actual = improperFormat.format(c);
+        assertEquals(expected, actual);
+    }
+
+	public void testFormatNegative() {
+        Fraction c = new Fraction(-1, 2);
+        String expected = "-1 / 2";
+
+        String actual = properFormat.format(c); 
+        assertEquals(expected, actual);
+
+        actual = improperFormat.format(c); 
+        assertEquals(expected, actual);
+	}
+
+	public void testFormatZero() {
+        Fraction c = new Fraction(0, 1);
+        String expected = "0 / 1";
+
+        String actual = properFormat.format(c); 
+        assertEquals(expected, actual);
+
+        actual = improperFormat.format(c); 
+        assertEquals(expected, actual);
+	}
+    
+    public void testFormatImproper() {
+        Fraction c = new Fraction(5, 3);
+
+        String actual = properFormat.format(c); 
+        assertEquals("1 2 / 3", actual);
+
+        actual = improperFormat.format(c); 
+        assertEquals("5 / 3", actual);
+    }
+    
+    public void testFormatImproperNegative() {
+        Fraction c = new Fraction(-5, 3);
+
+        String actual = properFormat.format(c); 
+        assertEquals("-1 2 / 3", actual);
+
+        actual = improperFormat.format(c); 
+        assertEquals("-5 / 3", actual);
+    }
+    
+    public void testParse() {
+        String source = "1 / 2";
+
+        try {
+            Fraction c = properFormat.parse(source);
+            assertNotNull(c);
+            assertEquals(1, c.getNumerator());
+            assertEquals(2, c.getDenominator());
+            
+            c = improperFormat.parse(source);
+            assertNotNull(c);
+            assertEquals(1, c.getNumerator());
+            assertEquals(2, c.getDenominator());
+        } catch (ParseException ex) {
+            fail(ex.getMessage());
+        }
+    }
+    
+    public void testParseNegative() {
+
+        try {
+            String source = "-1 / 2";
+            Fraction c = properFormat.parse(source);
+            assertNotNull(c);
+            assertEquals(-1, c.getNumerator());
+            assertEquals(2, c.getDenominator());
+            
+            c = improperFormat.parse(source);
+            assertNotNull(c);
+            assertEquals(-1, c.getNumerator());
+            assertEquals(2, c.getDenominator());
+
+            source = "1 / -2";
+            c = properFormat.parse(source);
+            assertNotNull(c);
+            assertEquals(-1, c.getNumerator());
+            assertEquals(2, c.getDenominator());
+            
+            c = improperFormat.parse(source);
+            assertNotNull(c);
+            assertEquals(-1, c.getNumerator());
+            assertEquals(2, c.getDenominator());
+        } catch (ParseException ex) {
+            fail(ex.getMessage());
+        }
+    }
+    
+    public void testParseProper() {
+        String source = "1 2 / 3";
+
+        try {
+            Fraction c = properFormat.parse(source);
+            assertNotNull(c);
+            assertEquals(5, c.getNumerator());
+            assertEquals(3, c.getDenominator());
+        } catch (ParseException ex) {
+            fail(ex.getMessage());
+        }
+        
+        try {
+            improperFormat.parse(source);
+            fail("invalid improper fraction.");
+        } catch (ParseException ex) {
+            // success
+        }
+    }
+    
+    public void testParseProperNegative() {
+        String source = "-1 2 / 3";
+        try {
+            Fraction c = properFormat.parse(source);
+            assertNotNull(c);
+            assertEquals(-5, c.getNumerator());
+            assertEquals(3, c.getDenominator());
+        } catch (ParseException ex) {
+            fail(ex.getMessage());
+        }
+        
+        try {
+            improperFormat.parse(source);
+            fail("invalid improper fraction.");
+        } catch (ParseException ex) {
+            // success
+        }
+    }
+}

Added: jakarta/commons/proper/math/trunk/src/test/org/apache/commons/math/fraction/FractionTest.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/trunk/src/test/org/apache/commons/math/fraction/FractionTest.java?view=auto&rev=151479
==============================================================================
--- jakarta/commons/proper/math/trunk/src/test/org/apache/commons/math/fraction/FractionTest.java (added)
+++ jakarta/commons/proper/math/trunk/src/test/org/apache/commons/math/fraction/FractionTest.java Fri Feb  4 21:49:45 2005
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed 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.math.fraction;
+
+import org.apache.commons.math.ConvergenceException;
+
+import junit.framework.TestCase;
+
+/**
+ * @version $Revision: $ $Date: $
+ */
+public class FractionTest extends TestCase {
+
+    private void assertFraction(int expectedNumerator, int expectedDenominator, Fraction actual) {
+        assertEquals(expectedNumerator, actual.getNumerator());
+        assertEquals(expectedDenominator, actual.getDenominator());
+    }
+    
+    public void testConstructor() {
+        assertFraction(0, 1, new Fraction(0, 1));
+        assertFraction(0, 1, new Fraction(0, 2));
+        assertFraction(0, 1, new Fraction(0, -1));
+        assertFraction(1, 2, new Fraction(1, 2));
+        assertFraction(1, 2, new Fraction(2, 4));
+        assertFraction(-1, 2, new Fraction(-1, 2));
+        assertFraction(-1, 2, new Fraction(1, -2));
+        assertFraction(-1, 2, new Fraction(-2, 4));
+        assertFraction(-1, 2, new Fraction(2, -4));
+    }
+    
+    public void testConstructorDouble() {
+        try {
+            assertFraction(1, 2, new Fraction(0.5));
+            assertFraction(1, 3, new Fraction(1.0 / 3.0));
+            assertFraction(17, 100, new Fraction(17.0 / 100.0));
+            assertFraction(317, 100, new Fraction(317.0 / 100.0));
+            assertFraction(-1, 2, new Fraction(-0.5));
+            assertFraction(-1, 3, new Fraction(-1.0 / 3.0));
+            assertFraction(-17, 100, new Fraction(17.0 / -100.0));
+            assertFraction(-317, 100, new Fraction(-317.0 / 100.0));
+        } catch (ConvergenceException ex) {
+            fail(ex.getMessage());
+        }
+    }
+    
+    public void testAbs() {
+        Fraction a = new Fraction(10, 21);
+        Fraction b = new Fraction(-10, 21);
+        Fraction c = new Fraction(10, -21);
+        
+        assertFraction(10, 21, a.abs());
+        assertFraction(10, 21, b.abs());
+        assertFraction(10, 21, c.abs());
+    }
+    
+    public void testAdd() {
+        Fraction a = new Fraction(1, 2);
+        Fraction b = new Fraction(2, 3);
+        
+        assertFraction(1, 1, a.add(a));
+        assertFraction(7, 6, a.add(b));
+        assertFraction(7, 6, b.add(a));
+        assertFraction(4, 3, b.add(b));
+    }
+    
+    public void testDivide() {
+        Fraction a = new Fraction(1, 2);
+        Fraction b = new Fraction(2, 3);
+        
+        assertFraction(1, 1, a.divide(a));
+        assertFraction(3, 4, a.divide(b));
+        assertFraction(4, 3, b.divide(a));
+        assertFraction(1, 1, b.divide(b));
+    }
+    
+    public void testMultiply() {
+        Fraction a = new Fraction(1, 2);
+        Fraction b = new Fraction(2, 3);
+        
+        assertFraction(1, 4, a.multiply(a));
+        assertFraction(1, 3, a.multiply(b));
+        assertFraction(1, 3, b.multiply(a));
+        assertFraction(4, 9, b.multiply(b));
+    }
+    
+    public void testSubtract() {
+        Fraction a = new Fraction(1, 2);
+        Fraction b = new Fraction(2, 3);
+        
+        assertFraction(0, 1, a.subtract(a));
+        assertFraction(-1, 6, a.subtract(b));
+        assertFraction(1, 6, b.subtract(a));
+        assertFraction(0, 1, b.subtract(b));
+    }
+}

Modified: jakarta/commons/proper/math/trunk/src/test/org/apache/commons/math/util/MathUtilsTest.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/trunk/src/test/org/apache/commons/math/util/MathUtilsTest.java?view=diff&r1=151478&r2=151479
==============================================================================
--- jakarta/commons/proper/math/trunk/src/test/org/apache/commons/math/util/MathUtilsTest.java (original)
+++ jakarta/commons/proper/math/trunk/src/test/org/apache/commons/math/util/MathUtilsTest.java Fri Feb  4 21:49:45 2005
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2004 The Apache Software Foundation.
+ * Copyright 2003-2005 The Apache Software Foundation.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -22,9 +22,8 @@
 /**
  * Test cases for the MathUtils class.
  *
- * @version $Revision: 1.15 $ $Date: 2004/10/14 04:01:04 $
+ * @version $Revision: 1.15 $ $Date$
  */
-
 public final class MathUtilsTest extends TestCase {
 
     public MathUtilsTest(String name) {
@@ -388,5 +387,43 @@
                 }
             }
         } 
+    }
+    
+    public void testGcd() {
+        int a = 30;
+        int b = 50;
+        int c = 77;
+
+        assertEquals(0, MathUtils.gcd(0, 0));
+        
+        assertEquals(b, MathUtils.gcd( 0,  b));
+        assertEquals(a, MathUtils.gcd( a,  0));
+        assertEquals(b, MathUtils.gcd( 0, -b));
+        assertEquals(a, MathUtils.gcd(-a,  0));
+        
+        assertEquals(10, MathUtils.gcd( a,  b));
+        assertEquals(10, MathUtils.gcd(-a,  b));
+        assertEquals(10, MathUtils.gcd( a, -b));
+        assertEquals(10, MathUtils.gcd(-a, -b));
+        
+        assertEquals(1, MathUtils.gcd( a,  c));
+        assertEquals(1, MathUtils.gcd(-a,  c));
+        assertEquals(1, MathUtils.gcd( a, -c));
+        assertEquals(1, MathUtils.gcd(-a, -c));
+    }
+    
+    public void testLcm() {
+        int a = 30;
+        int b = 50;
+        int c = 77;
+        
+        assertEquals(0, MathUtils.lcm(0, b));
+        assertEquals(0, MathUtils.lcm(a, 0));
+        assertEquals(b, MathUtils.lcm(1, b));
+        assertEquals(a, MathUtils.lcm(a, 1));
+        assertEquals(150, MathUtils.lcm(a, b));
+        assertEquals(150, MathUtils.lcm(-a, b));
+        assertEquals(150, MathUtils.lcm(a, -b));
+        assertEquals(2310, MathUtils.lcm(a, c));
     }
 }

Modified: jakarta/commons/proper/math/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/trunk/xdocs/changes.xml?view=diff&r1=151478&r2=151479
==============================================================================
--- jakarta/commons/proper/math/trunk/xdocs/changes.xml (original)
+++ jakarta/commons/proper/math/trunk/xdocs/changes.xml Fri Feb  4 21:49:45 2005
@@ -37,6 +37,14 @@
     <title>Commons Math Release Notes</title>
   </properties>
   <body>
+    <release version="1.1" date="In Development"  
+       description="Jakarta Commons Math 1.1 - Development">
+      <action dev="brentworden" type="add" due-to="C. Scott Ananian">
+        Added Fraction class based on commons-lang implementation.  With the
+        fraction class, FractionFormat and ProperFractionFormat classes were
+        added to provide fraction formatting and parsing.
+      </action>
+    </release>  
     <release version="1.0" date="2004-12-06"  
        description="Jakarta Commons Math 1.0 - General Availability Release">
       <action dev="psteitz" type="fix" due-to="Hans van der Heijden" issue="32531">

Modified: jakarta/commons/proper/math/trunk/xdocs/navigation.xml
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/trunk/xdocs/navigation.xml?view=diff&r1=151478&r2=151479
==============================================================================
--- jakarta/commons/proper/math/trunk/xdocs/navigation.xml (original)
+++ jakarta/commons/proper/math/trunk/xdocs/navigation.xml Fri Feb  4 21:49:45 2005
@@ -50,6 +50,7 @@
       <item name="Utilities"               href="/userguide/utilities.html"/>
       <item name="Complex Numbers"         href="/userguide/complex.html"/>
       <item name="Distributions"           href="/userguide/distribution.html"/>
+      <item name="Fractions"           href="/userguide/fraction.html"/>
     </menu>
     
     &common-menus;

Modified: jakarta/commons/proper/math/trunk/xdocs/tasks.xml
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/trunk/xdocs/tasks.xml?view=diff&r1=151478&r2=151479
==============================================================================
--- jakarta/commons/proper/math/trunk/xdocs/tasks.xml (original)
+++ jakarta/commons/proper/math/trunk/xdocs/tasks.xml Fri Feb  4 21:49:45 2005
@@ -17,7 +17,7 @@
   -->
   
 <?xml-stylesheet type="text/xsl" href="xdoc.xsl"?>
-<!-- $Revision: 1.24 $ $Date: 2004/07/25 15:13:47 $ -->
+<!-- $Revision: 1.24 $ $Date$ -->
 <document>
   <properties>
     <title>Tasks: To Do</title>
@@ -77,12 +77,6 @@
               <li>More matrix decompositions (Cholesky, QR, SVD) and framework
                to support.</li>
               <li>Sparse matrices</li>
-            </ul>
-          </dd> 
-          <dt>Math</dt>
-          <dd>
-            <ul>
-              <li>Rational Number (or Fraction) class</li>
             </ul>
           </dd> 
         </dl> 

Added: jakarta/commons/proper/math/trunk/xdocs/userguide/fraction.xml
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/trunk/xdocs/userguide/fraction.xml?view=auto&rev=151479
==============================================================================
--- jakarta/commons/proper/math/trunk/xdocs/userguide/fraction.xml (added)
+++ jakarta/commons/proper/math/trunk/xdocs/userguide/fraction.xml Fri Feb  4 21:49:45 2005
@@ -0,0 +1,105 @@
+<?xml version="1.0"?>
+
+<!--
+   Copyright 2005 The Apache Software Foundation
+
+   Licensed 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.
+  -->
+  
+<?xml-stylesheet type="text/xsl" href="./xdoc.xsl"?>
+<!-- $Revision: 1.4 $ $Date: 2004-11-07 19:03:43 -0600 (Sun, 07 Nov 2004) $ -->
+<document url="stat.html">
+  <properties>
+    <title>The Commons Math User Guide - Fractions</title>
+  </properties>
+  <body>
+    <section name="9 Fractions">
+      <subsection name="9.1 Overview" href="overview">
+        <p>
+          The fraction packages provides a fraction number type as well as
+          fraction number formatting.
+        </p>
+      </subsection>
+      <subsection name="9.2 Fraction Numbers" href="fraction">
+        <p>
+		  <a href="../apidocs/org/apache/commons/math/fraction/Fraction.html">
+		  org.apache.commons.math.fraction.Fraction</a> provides a fraction number
+		  type that forms the basis for the fraction functionality found in 
+		  commons-math.
+        </p>
+        <p>
+          To create a fraction number, simply call the constructor passing in two
+          integer arguments, the first being the numerator of the fraction and the second being the denominator:
+          <source>Fraction f = new Fraction(1, 3); // 1 / 3</source>
+        </p>
+        <p>
+          Of special note with fraction construction, when a fraction is created it is always reduced to lowest terms.
+        </p>
+        <p>
+          The <code>Fraction</code> class provides many unary and binary
+          fraction operations.  These operations provide the means to add,
+          subtract, multiple and, divide fractions along with other functions similar to the real number functions found in
+          <code>java.math.BigDecimal</code>:
+          <source>Fraction lhs = new Fraction(1, 3);
+Fraction rhs = new Fraction(2, 5);
+
+Fraction answer = lhs.add(rhs);     // add two fractions
+        answer = lhs.subtract(rhs); // subtract two fractions
+        answer = lhs.abs();         // absolute value
+        answer = lhs.reciprocal();  // reciprocal of lhs</source>
+        </p>
+        <p>
+          Like fraction construction, for each of the fraction functions, the resulting fraction is reduced to lowest terms.
+        </p>
+      </subsection>
+      <subsection name="9.3 Fraction Formatting and Parsing" href="formatting">
+        <p>
+          <code>Fraction</code> instances can be converted to and from strings
+          using the<a href="../apidocs/org/apache/commons/math/fraction/FractionFormat.html">
+		  org.apache.commons.math.fraction.FractionFormat</a> class.
+		  <code>FractionFormat</code> is a <code>java.text.Format</code>
+		  extension and, as such, is used like other formatting objects (e.g.
+		  <code>java.text.SimpleDateFormat</code>):
+		  <source>FractionFormat format = new FractionFormat(); // default format
+Fraction f = new Fraction(2, 4);
+String s = format.format(f); // s contains "1 / 2", note the reduced fraction</source>
+        </p>
+        <p>
+          To customize the formatting output, one or two
+          <code>java.text.NumberFormat</code> instances can be used to construct
+          a <code>FractionFormat</code>.  These number formats control the
+          formatting of the numerator and denominator of the fraction:
+          <source>NumberFormat nf = NumberFormat.getInstance(Locale.FRANCE);
+// create fraction format with custom number format
+// when one number format is used, both numerator and
+// denominator are formatted the same
+FractionFormat format = new FractionFormat(nf);
+Fraction f = new Fraction(2000, 3333);
+String s = format.format(c); // s contains "2.000 / 3.333"
+
+NumberFormat nf2 = NumberFormat.getInstance(Locale.US);
+// create fraction format with custom number formats
+format = new FractionFormat(nf, nf2);
+s = format.format(f); // s contains "2.000 / 3,333"</source>
+		</p>
+		<p>
+		  Formatting's inverse operation, parsing, can also be performed by
+		  <code>FractionFormat</code>.  To parse a fraction from a string,
+		  simply call the <code>parse</code> method:
+		  <source>FractionFormat ff = new FractionFormat();
+Fraction f = ff.parse("-10 / 21");</source>
+		</p>
+      </subsection>
+    </section>
+  </body>
+</document>

Modified: jakarta/commons/proper/math/trunk/xdocs/userguide/index.xml
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/trunk/xdocs/userguide/index.xml?view=diff&r1=151478&r2=151479
==============================================================================
--- jakarta/commons/proper/math/trunk/xdocs/userguide/index.xml (original)
+++ jakarta/commons/proper/math/trunk/xdocs/userguide/index.xml Fri Feb  4 21:49:45 2005
@@ -17,7 +17,7 @@
   -->
   
 <?xml-stylesheet type="text/xsl" href="./xdoc.xsl"?>
-<!-- $Revision: 1.13 $ $Date: 2004/11/09 02:26:55 $ -->
+<!-- $Revision: 1.13 $ $Date$ -->
 <document url="index.html">
   <properties>
     <title>The Commons Math User Guide - Table of Contents</title>
@@ -91,6 +91,12 @@
                 <li><a href="distribution.html#overview">8.1 Overview</a></li>
                 <li><a href="distribution.html#distributions">8.2 Distribution Framework</a></li>
                 <li><a href="distribution.html#userdefined">8.3 User Defined Distributions</a></li>
+                </ul></li>                                 
+        <li><a href="fraction.html">9. Fractions</a>
+                <ul>
+                <li><a href="fraction.html#overview">9.1 Overview</a></li>
+                <li><a href="fraction.html#fraction">9.2 Fraction Numbers</a></li>
+                <li><a href="fraction.html#formatting">9.3 Fraction Formatting and Parsing</a></li>
                 </ul></li>                                 
         </ul>
       </section>



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