diff --git a/src/java/org/apache/commons/math/MessagesResources_fr.java b/src/java/org/apache/commons/math/MessagesResources_fr.java
index 41ef83d63..640c81e21 100644
--- a/src/java/org/apache/commons/math/MessagesResources_fr.java
+++ b/src/java/org/apache/commons/math/MessagesResources_fr.java
@@ -101,6 +101,28 @@ public class MessagesResources_fr
{ "cannot convert infinite value",
"les valeurs infinies ne peuvent \u00eatre converties" },
+ // org.apache.commons.math.fraction.AbstractFormat
+ { "denominator format can not be null",
+ "le format du d\u00e9nominateur ne doit pas \u00eatre nul" },
+ { "numerator format can not be null",
+ "le format du num\u00e9rateur ne doit pas \u00eatre nul" },
+
+ // org.apache.commons.math.fraction.FractionFormat
+ { "cannot convert given object to a fraction number: {0}",
+ "impossible de convertir l''objet sous forme d''un nombre rationnel : {0}" },
+
+ // org.apache.commons.math.fraction.FractionFormat
+ // org.apache.commons.math.fraction.BigFractionFormat
+ { "unparseable fraction number: \"{0}\"",
+ "\u00e9chec d''analyse du nombre rationnel \"{0}\"" },
+ { "cannot format given object as a fraction number",
+ "impossible de formater l''objet sous forme d''un nombre rationnel" },
+
+ // org.apache.commons.math.fraction.ProperFractionFormat
+ // org.apache.commons.math.fraction.ProperBigFractionFormat
+ { "whole format can not be null",
+ "le format complet ne doit pas \u00eatre nul" },
+
// org.apache.commons.math.analysis.solvers.UnivariateRealSolverUtils
{ "Number of iterations={0}, maximum iterations={1}, initial={2}, lower bound={3}, upper bound={4}," +
" final a value={5}, final b value={6}, f(a)={7}, f(b)={8}",
@@ -315,10 +337,6 @@ public class MessagesResources_fr
{ "unparseable complex number: \"{0}\"",
"\u00e9chec d''analyse du nombre complexe \"{0}\"" },
- // org.apache.commons.math.fraction.FractionFormat
- { "unparseable fraction number: \"{0}\"",
- "\u00e9chec d''analyse du nombre rationnel \"{0}\"" },
-
// org.apache.commons.math.geometry.Vector3DFormat
{ "unparseable 3D vector: \"{0}\"",
"\u00e9chec d''analyse du vecteur de dimension 3 \"{0}\"" },
diff --git a/src/java/org/apache/commons/math/fraction/AbstractFormat.java b/src/java/org/apache/commons/math/fraction/AbstractFormat.java
new file mode 100644
index 000000000..aa3c4104d
--- /dev/null
+++ b/src/java/org/apache/commons/math/fraction/AbstractFormat.java
@@ -0,0 +1,206 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.math.fraction;
+
+import java.io.Serializable;
+import java.text.FieldPosition;
+import java.text.NumberFormat;
+import java.text.ParsePosition;
+import java.util.Locale;
+
+import org.apache.commons.math.MathRuntimeException;
+
+public abstract class AbstractFormat extends NumberFormat implements Serializable {
+
+ /** Serializable version identifier. */
+ private static final long serialVersionUID = -6981118387974191891L;
+
+ /** The format used for the denominator. */
+ protected NumberFormat denominatorFormat;
+
+ /** The format used for the numerator. */
+ protected NumberFormat numeratorFormat;
+
+ /**
+ * Create an improper formatting instance with the default number format
+ * for the numerator and denominator.
+ */
+ protected AbstractFormat() {
+ 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.
+ */
+ protected AbstractFormat(final 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.
+ */
+ protected AbstractFormat(final NumberFormat numeratorFormat,
+ final NumberFormat denominatorFormat) {
+ this.numeratorFormat = numeratorFormat;
+ this.denominatorFormat = denominatorFormat;
+ }
+
+ /**
+ * Create a default number format. The default number format is based on
+ * {@link NumberFormat#getNumberInstance(java.util.Locale)} with the only
+ * customizing is the maximum number of BigFraction digits, which is set to 0.
+ * @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#getNumberInstance(java.util.Locale)} with the only
+ * customizing is the maximum number of BigFraction digits, which is set to 0.
+ * @param locale the specific locale used by the format.
+ * @return the default number format specific to the given locale.
+ */
+ protected static NumberFormat getDefaultNumberFormat(final Locale locale) {
+ final NumberFormat nf = NumberFormat.getNumberInstance(locale);
+ nf.setMaximumFractionDigits(0);
+ nf.setParseIntegerOnly(true);
+ return nf;
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Modify the denominator format.
+ * @param format the new denominator format value.
+ * @throws IllegalArgumentException if format
is
+ * null
.
+ */
+ public void setDenominatorFormat(final NumberFormat format) {
+ if (format == null) {
+ throw MathRuntimeException.createIllegalArgumentException(
+ "denominator format can not be null");
+ }
+ this.denominatorFormat = format;
+ }
+
+ /**
+ * Modify the numerator format.
+ * @param format the new numerator format value.
+ * @throws IllegalArgumentException if format
is
+ * null
.
+ */
+ public void setNumeratorFormat(final NumberFormat format) {
+ if (format == null) {
+ throw MathRuntimeException.createIllegalArgumentException(
+ "numerator format can not be null");
+ }
+ this.numeratorFormat = format;
+ }
+
+ /**
+ * Parses source
until a non-whitespace character is found.
+ * @param source the string to parse
+ * @param pos input/ouput parsing parameter. On output, pos
+ * holds the index of the next non-whitespace character.
+ */
+ protected static void parseAndIgnoreWhitespace(final String source,
+ final ParsePosition pos) {
+ parseNextCharacter(source, pos);
+ pos.setIndex(pos.getIndex() - 1);
+ }
+
+ /**
+ * Parses source
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(final String source,
+ final ParsePosition pos) {
+ int index = pos.getIndex();
+ final 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;
+ }
+
+ /**
+ * Formats a double value as a fraction and appends the result to a StringBuffer.
+ *
+ * @param value the double value to format
+ * @param buffer StringBuffer to append to
+ * @param position On input: an alignment field, if desired. On output: the
+ * offsets of the alignment field
+ * @return a reference to the appended buffer
+ * @see {@link #format(Object, StringBuffer, FieldPosition)}
+ */
+ public StringBuffer format(final double value,
+ final StringBuffer buffer, final FieldPosition position) {
+ return format(Double.valueOf(value), buffer, position);
+ }
+
+
+ /**
+ * Formats a long value as a fraction and appends the result to a StringBuffer.
+ *
+ * @param value the long value to format
+ * @param buffer StringBuffer to append to
+ * @param position On input: an alignment field, if desired. On output: the
+ * offsets of the alignment field
+ * @return a reference to the appended buffer
+ * @see {@link #format(Object, StringBuffer, FieldPosition)}
+ */
+ public StringBuffer format(final long value,
+ final StringBuffer buffer, final FieldPosition position) {
+ return format(Long.valueOf(value), buffer, position);
+ }
+
+}
\ No newline at end of file
diff --git a/src/java/org/apache/commons/math/fraction/BigFractionFormat.java b/src/java/org/apache/commons/math/fraction/BigFractionFormat.java
new file mode 100644
index 000000000..3aa586981
--- /dev/null
+++ b/src/java/org/apache/commons/math/fraction/BigFractionFormat.java
@@ -0,0 +1,287 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.math.fraction;
+
+import java.io.Serializable;
+import java.math.BigInteger;
+import java.text.FieldPosition;
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.text.ParsePosition;
+import java.util.Locale;
+
+import org.apache.commons.math.MathRuntimeException;
+
+/**
+ * Formats a BigFraction number in proper format or improper format.
+ *
+ * The number format for each of the whole number, numerator and, + * denominator can be configured. + *
+ * + * @since 2.0 + * @version $Revision$ $Date$ + */ +public class BigFractionFormat extends AbstractFormat implements Serializable { + + /** Serializable version identifier */ + private static final long serialVersionUID = -2932167925527338976L; + + /** + * Create an improper formatting instance with the default number format + * for the numerator and denominator. + */ + public BigFractionFormat() { + } + + /** + * 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 BigFractionFormat(final NumberFormat format) { + super(format); + } + + /** + * 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 BigFractionFormat(final NumberFormat numeratorFormat, + final NumberFormat denominatorFormat) { + super(numeratorFormat, denominatorFormat); + } + + /** + * 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(); + } + + /** + * This static method calls formatBigFraction() on a default instance of + * BigFractionFormat. + * + * @param f BigFraction object to format + * @return A formatted BigFraction in proper form. + */ + public static String formatBigFraction(final BigFraction f) { + return getImproperInstance().format(f); + } + + /** + * Returns the default complex format for the current locale. + * @return the default complex format. + */ + public static BigFractionFormat 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 BigFractionFormat getImproperInstance(final Locale locale) { + return new BigFractionFormat(getDefaultNumberFormat(locale)); + } + + /** + * Returns the default complex format for the current locale. + * @return the default complex format. + */ + public static BigFractionFormat 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 BigFractionFormat getProperInstance(final Locale locale) { + return new ProperBigFractionFormat(getDefaultNumberFormat(locale)); + } + + /** + * Formats a {@link BigFraction} object to produce a string. The BigFraction is + * output in improper format. + * + * @param BigFraction 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(final BigFraction BigFraction, + final StringBuffer toAppendTo, final FieldPosition pos) { + + pos.setBeginIndex(0); + pos.setEndIndex(0); + + getNumeratorFormat().format(BigFraction.getNumerator(), toAppendTo, pos); + toAppendTo.append(" / "); + getDenominatorFormat().format(BigFraction.getDenominator(), toAppendTo, pos); + + return toAppendTo; + } + + /** + * Formats an object and appends the result to a StringBuffer. + *obj
must be either a {@link BigFraction} object or a
+ * {@link BigInteger} 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 obj
is not a valid type.
+ */
+ public StringBuffer format(final Object obj,
+ final StringBuffer toAppendTo, final FieldPosition pos) {
+
+ final StringBuffer ret;
+ if (obj instanceof BigFraction) {
+ ret = format((BigFraction) obj, toAppendTo, pos);
+ } else if (obj instanceof BigInteger) {
+ ret = format(new BigFraction((BigInteger) obj), toAppendTo, pos);
+ } else if (obj instanceof Number) {
+ ret = format(new BigFraction(((Number) obj).doubleValue()),
+ toAppendTo, pos);
+ } else {
+ throw MathRuntimeException.createIllegalArgumentException(
+ "cannot format given object as a fraction number");
+ }
+
+ return ret;
+ }
+
+ /**
+ * Parses a string to produce a {@link BigFraction} object.
+ * @param source the string to parse
+ * @return the parsed {@link BigFraction} object.
+ * @exception ParseException if the beginning of the specified string
+ * cannot be parsed.
+ */
+ public BigFraction parse(final String source) throws ParseException {
+ final ParsePosition parsePosition = new ParsePosition(0);
+ final BigFraction result = parse(source, parsePosition);
+ if (parsePosition.getIndex() == 0) {
+ throw MathRuntimeException.createParseException(
+ parsePosition.getErrorIndex(),
+ "unparseable fraction number: \"{0}\"", source);
+ }
+ return result;
+ }
+
+ /**
+ * Parses a string to produce a {@link BigFraction} object.
+ * This method expects the string to be formatted as an improper BigFraction.
+ * @param source the string to parse
+ * @param pos input/ouput parsing parameter.
+ * @return the parsed {@link BigFraction} object.
+ */
+ public BigFraction parse(final String source, final ParsePosition pos) {
+ final int initialIndex = pos.getIndex();
+
+ // parse whitespace
+ parseAndIgnoreWhitespace(source, pos);
+
+ // parse numerator
+ final BigInteger num = parseNextBigInteger(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 '/'
+ final int startIndex = pos.getIndex();
+ final char c = parseNextCharacter(source, pos);
+ switch (c) {
+ case 0 :
+ // no '/'
+ // return num as a BigFraction
+ return new BigFraction(num);
+ 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
+ final BigInteger den = parseNextBigInteger(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 BigFraction(num, den);
+ }
+
+ /**
+ * Parses a string to produce a BigInteger
.
+ * @param source the string to parse
+ * @param pos input/ouput parsing parameter.
+ * @return a parsed BigInteger
or null if string does not
+ * contain a BigInteger at the specified position
+ */
+ protected BigInteger parseNextBigInteger(final String source,
+ final ParsePosition pos) {
+
+ final int start = pos.getIndex();
+ int end = (source.charAt(start) == '-') ? (start + 1) : start;
+ while((end < source.length()) &&
+ Character.isDigit(source.charAt(end))) {
+ ++end;
+ }
+
+ try {
+ BigInteger n = new BigInteger(source.substring(start, end));
+ pos.setIndex(end);
+ return n;
+ } catch (NumberFormatException nfe) {
+ pos.setErrorIndex(start);
+ return null;
+ }
+
+ }
+
+}
diff --git a/src/java/org/apache/commons/math/fraction/FractionFormat.java b/src/java/org/apache/commons/math/fraction/FractionFormat.java
index cf25b03d4..78d93053d 100644
--- a/src/java/org/apache/commons/math/fraction/FractionFormat.java
+++ b/src/java/org/apache/commons/math/fraction/FractionFormat.java
@@ -17,7 +17,6 @@
package org.apache.commons.math.fraction;
-import java.io.Serializable;
import java.text.FieldPosition;
import java.text.NumberFormat;
import java.text.ParseException;
@@ -35,23 +34,16 @@ import org.apache.commons.math.MathRuntimeException;
* @since 1.1
* @version $Revision$ $Date$
*/
-public class FractionFormat extends NumberFormat implements Serializable {
+public class FractionFormat extends AbstractFormat {
/** Serializable version identifier */
- private static final long serialVersionUID = -6337346779577272306L;
+ private static final long serialVersionUID = 3008655719530972611L;
- /** 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());
}
/**
@@ -59,8 +51,8 @@ public class FractionFormat extends NumberFormat implements Serializable {
* 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());
+ public FractionFormat(final NumberFormat format) {
+ super(format);
}
/**
@@ -69,12 +61,18 @@ public class FractionFormat extends NumberFormat implements Serializable {
* @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;
+ public FractionFormat(final NumberFormat numeratorFormat,
+ final NumberFormat denominatorFormat) {
+ super(numeratorFormat, denominatorFormat);
+ }
+
+ /**
+ * 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();
}
/**
@@ -88,15 +86,6 @@ public class FractionFormat extends NumberFormat implements Serializable {
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.
@@ -110,9 +99,8 @@ public class FractionFormat extends NumberFormat implements Serializable {
* @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);
+ public static FractionFormat getImproperInstance(final Locale locale) {
+ return new FractionFormat(getDefaultNumberFormat(locale));
}
/**
@@ -128,9 +116,8 @@ public class FractionFormat extends NumberFormat implements Serializable {
* @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);
+ public static FractionFormat getProperInstance(final Locale locale) {
+ return new ProperFractionFormat(getDefaultNumberFormat(locale));
}
/**
@@ -143,20 +130,6 @@ public class FractionFormat extends NumberFormat implements Serializable {
return getDefaultNumberFormat(Locale.getDefault());
}
- /**
- * Create a default number format. The default number format is based on
- * {@link NumberFormat#getNumberInstance(java.util.Locale)} with the only
- * customizing is the maximum number of fraction digits, which is set to 0.
- * @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.getNumberInstance(locale);
- nf.setMaximumFractionDigits(0);
- nf.setParseIntegerOnly(true);
- return nf;
- }
-
/**
* Formats a {@link Fraction} object to produce a string. The fraction is
* output in improper format.
@@ -167,8 +140,8 @@ public class FractionFormat extends NumberFormat implements Serializable {
* offsets of the alignment field
* @return the value passed in as toAppendTo.
*/
- public StringBuffer format(Fraction fraction, StringBuffer toAppendTo,
- FieldPosition pos) {
+ public StringBuffer format(final Fraction fraction,
+ final StringBuffer toAppendTo, final FieldPosition pos) {
pos.setBeginIndex(0);
pos.setEndIndex(0);
@@ -194,45 +167,29 @@ public class FractionFormat extends NumberFormat implements Serializable {
* @see java.text.Format#format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition)
* @throws IllegalArgumentException is obj
is not a valid type.
*/
- public StringBuffer format(Object obj, StringBuffer toAppendTo,
- FieldPosition pos)
- {
+ public StringBuffer format(final Object obj,
+ final StringBuffer toAppendTo, final FieldPosition pos) {
StringBuffer ret = null;
if (obj instanceof Fraction) {
- ret = format( (Fraction)obj, toAppendTo, pos);
+ ret = format((Fraction) obj, toAppendTo, pos);
} else if (obj instanceof Number) {
try {
- ret = format( new Fraction(((Number)obj).doubleValue()),
- toAppendTo, pos);
+ ret = format(new Fraction(((Number) obj).doubleValue()),
+ toAppendTo, pos);
} catch (ConvergenceException ex) {
- throw new IllegalArgumentException(
- "Cannot convert given object to a fraction.");
+ throw MathRuntimeException.createIllegalArgumentException(
+ "cannot convert given object to a fraction number: {0}",
+ ex.getLocalizedMessage());
}
} else {
- throw new IllegalArgumentException(
- "Cannot format given object as a fraction");
+ throw MathRuntimeException.createIllegalArgumentException(
+ "cannot format given object as a fraction number");
}
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
@@ -240,9 +197,9 @@ public class FractionFormat extends NumberFormat implements Serializable {
* @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);
+ public Fraction parse(final String source) throws ParseException {
+ final ParsePosition parsePosition = new ParsePosition(0);
+ final Fraction result = parse(source, parsePosition);
if (parsePosition.getIndex() == 0) {
throw MathRuntimeException.createParseException(
parsePosition.getErrorIndex(),
@@ -258,14 +215,14 @@ public class FractionFormat extends NumberFormat implements Serializable {
* @param pos input/ouput parsing parameter.
* @return the parsed {@link Fraction} object.
*/
- public Fraction parse(String source, ParsePosition pos) {
- int initialIndex = pos.getIndex();
+ public Fraction parse(final String source, final ParsePosition pos) {
+ final int initialIndex = pos.getIndex();
// parse whitespace
parseAndIgnoreWhitespace(source, pos);
// parse numerator
- Number num = getNumeratorFormat().parse(source, pos);
+ final Number num = getNumeratorFormat().parse(source, pos);
if (num == null) {
// invalid integer number
// set index back to initial, error index should already be set
@@ -275,8 +232,8 @@ public class FractionFormat extends NumberFormat implements Serializable {
}
// parse '/'
- int startIndex = pos.getIndex();
- char c = parseNextCharacter(source, pos);
+ final int startIndex = pos.getIndex();
+ final char c = parseNextCharacter(source, pos);
switch (c) {
case 0 :
// no '/'
@@ -298,7 +255,7 @@ public class FractionFormat extends NumberFormat implements Serializable {
parseAndIgnoreWhitespace(source, pos);
// parse denominator
- Number den = getDenominatorFormat().parse(source, pos);
+ final Number den = getDenominatorFormat().parse(source, pos);
if (den == null) {
// invalid integer number
// set index back to initial, error index should already be set
@@ -310,100 +267,4 @@ public class FractionFormat extends NumberFormat implements Serializable {
return new Fraction(num.intValue(), den.intValue());
}
- /**
- * Modify the denominator format.
- * @param format the new denominator format value.
- * @throws IllegalArgumentException if format
is
- * null
.
- */
- 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 format
is
- * null
.
- */
- public void setNumeratorFormat(NumberFormat format) {
- if (format == null) {
- throw new IllegalArgumentException(
- "numerator format can not be null.");
- }
- this.numeratorFormat = format;
- }
-
- /**
- * Parses source
until a non-whitespace character is found.
- * @param source the string to parse
- * @param pos input/ouput parsing parameter. On output, pos
- * 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 source
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;
- }
-
- /**
- * Formats a double value as a fraction and appends the result to a StringBuffer.
- *
- * @param value the double value to format
- * @param buffer StringBuffer to append to
- * @param position On input: an alignment field, if desired. On output: the
- * offsets of the alignment field
- * @return a reference to the appended buffer
- * @see {@link #format(Object, StringBuffer, FieldPosition)}
- */
- public StringBuffer format(double value, StringBuffer buffer,
- FieldPosition position) {
- return format(Double.valueOf(value), buffer, position);
- }
-
-
- /**
- * Formats a long value as a fraction and appends the result to a StringBuffer.
- *
- * @param value the long value to format
- * @param buffer StringBuffer to append to
- * @param position On input: an alignment field, if desired. On output: the
- * offsets of the alignment field
- * @return a reference to the appended buffer
- * @see {@link #format(Object, StringBuffer, FieldPosition)}
- */
- public StringBuffer format(long value, StringBuffer buffer, FieldPosition position) {
- return format(Long.valueOf(value), buffer, position);
- }
}
diff --git a/src/java/org/apache/commons/math/fraction/ProperBigFractionFormat.java b/src/java/org/apache/commons/math/fraction/ProperBigFractionFormat.java
new file mode 100644
index 000000000..ab2916e57
--- /dev/null
+++ b/src/java/org/apache/commons/math/fraction/ProperBigFractionFormat.java
@@ -0,0 +1,239 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.math.fraction;
+
+import java.math.BigInteger;
+import java.text.FieldPosition;
+import java.text.NumberFormat;
+import java.text.ParsePosition;
+
+import org.apache.commons.math.MathRuntimeException;
+
+/**
+ * Formats a BigFraction number in proper format. The number format for each of
+ * the whole number, numerator and, denominator can be configured.
+ *
+ * Minus signs are only allowed in the whole number part - i.e.,
+ * "-3 1/2" is legitimate and denotes -7/2, but "-3 -1/2" is invalid and
+ * will result in a ParseException
.
+ * Minus signs are only allowed in the whole number part - i.e.,
+ * "-3 1/2" is legitimate and denotes -7/2, but "-3 -1/2" is invalid and
+ * will result in a ParseException
.
format
is
+ * null
.
+ */
+ public void setWholeFormat(final NumberFormat format) {
+ if (format == null) {
+ throw MathRuntimeException.createIllegalArgumentException(
+ "whole format can not be null");
+ }
+ this.wholeFormat = format;
+ }
+
+}
diff --git a/src/java/org/apache/commons/math/fraction/ProperFractionFormat.java b/src/java/org/apache/commons/math/fraction/ProperFractionFormat.java
index 01d20ea0f..715060b6f 100644
--- a/src/java/org/apache/commons/math/fraction/ProperFractionFormat.java
+++ b/src/java/org/apache/commons/math/fraction/ProperFractionFormat.java
@@ -20,6 +20,7 @@ import java.text.FieldPosition;
import java.text.NumberFormat;
import java.text.ParsePosition;
+import org.apache.commons.math.MathRuntimeException;
import org.apache.commons.math.util.MathUtils;
/**
@@ -36,8 +37,8 @@ import org.apache.commons.math.util.MathUtils;
public class ProperFractionFormat extends FractionFormat {
/** Serializable version identifier */
- private static final long serialVersionUID = -6337346779577272307L;
-
+ private static final long serialVersionUID = 760934726031766749L;
+
/** The format used for the whole number. */
private NumberFormat wholeFormat;
@@ -222,8 +223,8 @@ public class ProperFractionFormat extends FractionFormat {
*/
public void setWholeFormat(NumberFormat format) {
if (format == null) {
- throw new IllegalArgumentException(
- "whole format can not be null.");
+ throw MathRuntimeException.createIllegalArgumentException(
+ "whole format can not be null");
}
this.wholeFormat = format;
}
diff --git a/src/test/org/apache/commons/math/fraction/BigFractionFormatTest.java b/src/test/org/apache/commons/math/fraction/BigFractionFormatTest.java
new file mode 100644
index 000000000..c7e6edf4f
--- /dev/null
+++ b/src/test/org/apache/commons/math/fraction/BigFractionFormatTest.java
@@ -0,0 +1,301 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.math.fraction;
+
+import java.math.BigInteger;
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.util.Locale;
+
+import junit.framework.TestCase;
+
+public class BigFractionFormatTest extends TestCase {
+
+ BigFractionFormat properFormat = null;
+ BigFractionFormat improperFormat = null;
+
+ protected Locale getLocale() {
+ return Locale.getDefault();
+ }
+
+ protected void setUp() throws Exception {
+ properFormat = BigFractionFormat.getProperInstance(getLocale());
+ improperFormat = BigFractionFormat.getImproperInstance(getLocale());
+ }
+
+ public void testFormat() {
+ BigFraction c = new BigFraction(1, 2);
+ String expected = "1 / 2";
+
+ String actual = properFormat.format(c);
+ assertEquals(expected, actual);
+
+ actual = improperFormat.format(c);
+ assertEquals(expected, actual);
+ }
+
+ public void testFormatNegative() {
+ BigFraction c = new BigFraction(-1, 2);
+ String expected = "-1 / 2";
+
+ String actual = properFormat.format(c);
+ assertEquals(expected, actual);
+
+ actual = improperFormat.format(c);
+ assertEquals(expected, actual);
+ }
+
+ public void testFormatZero() {
+ BigFraction c = new BigFraction(0, 1);
+ String expected = "0 / 1";
+
+ String actual = properFormat.format(c);
+ assertEquals(expected, actual);
+
+ actual = improperFormat.format(c);
+ assertEquals(expected, actual);
+ }
+
+ public void testFormatImproper() {
+ BigFraction c = new BigFraction(5, 3);
+
+ String actual = properFormat.format(c);
+ assertEquals("1 2 / 3", actual);
+
+ actual = improperFormat.format(c);
+ assertEquals("5 / 3", actual);
+ }
+
+ public void testFormatImproperNegative() {
+ BigFraction c = new BigFraction(-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 {
+ BigFraction c = properFormat.parse(source);
+ assertNotNull(c);
+ assertEquals(BigInteger.ONE, c.getNumerator());
+ assertEquals(BigInteger.valueOf(2l), c.getDenominator());
+
+ c = improperFormat.parse(source);
+ assertNotNull(c);
+ assertEquals(BigInteger.ONE, c.getNumerator());
+ assertEquals(BigInteger.valueOf(2l), c.getDenominator());
+ } catch (ParseException ex) {
+ fail(ex.getMessage());
+ }
+ }
+
+ public void testParseInteger() {
+ String source = "10";
+ try {
+ BigFraction c = properFormat.parse(source);
+ assertNotNull(c);
+ assertEquals(BigInteger.TEN, c.getNumerator());
+ assertEquals(BigInteger.ONE, c.getDenominator());
+ } catch (ParseException ex) {
+ fail(ex.getMessage());
+ }
+ try {
+ BigFraction c = improperFormat.parse(source);
+ assertNotNull(c);
+ assertEquals(BigInteger.TEN, c.getNumerator());
+ assertEquals(BigInteger.ONE, c.getDenominator());
+ } catch (ParseException ex) {
+ fail(ex.getMessage());
+ }
+ }
+
+ public void testParseInvalid() {
+ String source = "a";
+ String msg = "should not be able to parse '10 / a'.";
+ try {
+ properFormat.parse(source);
+ fail(msg);
+ } catch (ParseException ex) {
+ // success
+ }
+ try {
+ improperFormat.parse(source);
+ fail(msg);
+ } catch (ParseException ex) {
+ // success
+ }
+ }
+
+ public void testParseInvalidDenominator() {
+ String source = "10 / a";
+ String msg = "should not be able to parse '10 / a'.";
+ try {
+ properFormat.parse(source);
+ fail(msg);
+ } catch (ParseException ex) {
+ // success
+ }
+ try {
+ improperFormat.parse(source);
+ fail(msg);
+ } catch (ParseException ex) {
+ // success
+ }
+ }
+
+ public void testParseNegative() {
+
+ try {
+ String source = "-1 / 2";
+ BigFraction c = properFormat.parse(source);
+ assertNotNull(c);
+ assertEquals(-1, c.getNumeratorAsInt());
+ assertEquals(2, c.getDenominatorAsInt());
+
+ c = improperFormat.parse(source);
+ assertNotNull(c);
+ assertEquals(-1, c.getNumeratorAsInt());
+ assertEquals(2, c.getDenominatorAsInt());
+
+ source = "1 / -2";
+ c = properFormat.parse(source);
+ assertNotNull(c);
+ assertEquals(-1, c.getNumeratorAsInt());
+ assertEquals(2, c.getDenominatorAsInt());
+
+ c = improperFormat.parse(source);
+ assertNotNull(c);
+ assertEquals(-1, c.getNumeratorAsInt());
+ assertEquals(2, c.getDenominatorAsInt());
+ } catch (ParseException ex) {
+ fail(ex.getMessage());
+ }
+ }
+
+ public void testParseProper() {
+ String source = "1 2 / 3";
+
+ try {
+ BigFraction c = properFormat.parse(source);
+ assertNotNull(c);
+ assertEquals(5, c.getNumeratorAsInt());
+ assertEquals(3, c.getDenominatorAsInt());
+ } 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 {
+ BigFraction c = properFormat.parse(source);
+ assertNotNull(c);
+ assertEquals(-5, c.getNumeratorAsInt());
+ assertEquals(3, c.getDenominatorAsInt());
+ } catch (ParseException ex) {
+ fail(ex.getMessage());
+ }
+
+ try {
+ improperFormat.parse(source);
+ fail("invalid improper fraction.");
+ } catch (ParseException ex) {
+ // success
+ }
+ }
+
+ public void testParseProperInvalidMinus() {
+ String source = "2 -2 / 3";
+ try {
+ properFormat.parse(source);
+ fail("invalid minus in improper fraction.");
+ } catch (ParseException ex) {
+ // expected
+ }
+ source = "2 2 / -3";
+ try {
+ properFormat.parse(source);
+ fail("invalid minus in improper fraction.");
+ } catch (ParseException ex) {
+ // expected
+ }
+ }
+
+ public void testNumeratorFormat() {
+ NumberFormat old = properFormat.getNumeratorFormat();
+ NumberFormat nf = NumberFormat.getInstance();
+ nf.setParseIntegerOnly(true);
+ properFormat.setNumeratorFormat(nf);
+ assertEquals(nf, properFormat.getNumeratorFormat());
+ properFormat.setNumeratorFormat(old);
+
+ old = improperFormat.getNumeratorFormat();
+ nf = NumberFormat.getInstance();
+ nf.setParseIntegerOnly(true);
+ improperFormat.setNumeratorFormat(nf);
+ assertEquals(nf, improperFormat.getNumeratorFormat());
+ improperFormat.setNumeratorFormat(old);
+ }
+
+ public void testDenominatorFormat() {
+ NumberFormat old = properFormat.getDenominatorFormat();
+ NumberFormat nf = NumberFormat.getInstance();
+ nf.setParseIntegerOnly(true);
+ properFormat.setDenominatorFormat(nf);
+ assertEquals(nf, properFormat.getDenominatorFormat());
+ properFormat.setDenominatorFormat(old);
+
+ old = improperFormat.getDenominatorFormat();
+ nf = NumberFormat.getInstance();
+ nf.setParseIntegerOnly(true);
+ improperFormat.setDenominatorFormat(nf);
+ assertEquals(nf, improperFormat.getDenominatorFormat());
+ improperFormat.setDenominatorFormat(old);
+ }
+
+ public void testWholeFormat() {
+ ProperBigFractionFormat format = (ProperBigFractionFormat)properFormat;
+
+ NumberFormat old = format.getWholeFormat();
+ NumberFormat nf = NumberFormat.getInstance();
+ nf.setParseIntegerOnly(true);
+ format.setWholeFormat(nf);
+ assertEquals(nf, format.getWholeFormat());
+ format.setWholeFormat(old);
+ }
+
+ public void testLongFormat() {
+ assertEquals("10 / 1", improperFormat.format(10l));
+ }
+
+ public void testDoubleFormat() {
+ assertEquals("1 / 16", improperFormat.format(0.0625));
+ }
+}