Added a BigFraction class that does not overflow when big numerators or denominators are used.

Jira: MATH-251

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@759543 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Luc Maisonobe 2009-03-28 18:24:11 +00:00
parent e449af6e51
commit 17f0dd2da5
7 changed files with 1724 additions and 5 deletions

View File

@ -111,6 +111,9 @@
<contributor>
<name>Paul Cowan</name>
</contributor>
<contributor>
<name>Benjamin Croizet</name>
</contributor>
<contributor>
<name>Rodrigo di Lorenzo Lopes</name>
</contributor>

View File

@ -360,6 +360,28 @@ public class MathRuntimeException extends RuntimeException {
}
/**
* Constructs a new <code>NullPointerException</code> with specified formatted detail message.
* Message formatting is delegated to {@link java.text.MessageFormat}.
* @param pattern format specifier
* @param arguments format arguments
* @return built exception
*/
public static NullPointerException createNullPointerException(final String pattern,
final Object ... arguments) {
return new NullPointerException(buildMessage(Locale.US, pattern, arguments)) {
/** Serializable version identifier. */
private static final long serialVersionUID = -3075660477939965216L;
/** {@inheritDoc} */
public String getLocalizedMessage() {
return buildMessage(Locale.getDefault(), pattern, arguments);
}
};
}
/**
* Constructs a new <code>ParseException</code> with specified
* formatted detail message.
* Message formatting is delegated to {@link java.text.MessageFormat}.

View File

@ -89,6 +89,18 @@ public class MessagesResources_fr
{ "Overflow trying to convert {0} to fraction ({1}/{2})",
"D\u00e9passement de capacit\u00e9 lors de la conversion de {0} en fraction ({1}/{2})" },
// org.apache.commons.math.fraction.BigFraction
{ "numerator is null",
"le num\u00e9rateur est null" },
{ "denimonator is null",
"le d\u00e9nominateur est null" },
{ "denominator must be different from 0",
"le d\u00e9nominateur doit \u00eatre diff\u00e9rent de 0" },
{ "cannot convert NaN value",
"les valeurs NaN ne peuvent \u00eatre converties" },
{ "cannot convert infinite value",
"les valeurs infinies ne peuvent \u00eatre converties" },
// 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}",

File diff suppressed because it is too large Load Diff

View File

@ -39,6 +39,10 @@ The <action> type attribute can be add,update,fix,remove.
</properties>
<body>
<release version="2.0" date="TBD" description="TBD">
<action dev="luc" type="add" issue="MATH-251" due-to="Benjamin Croizet">
Added a BigFraction class that does not overflow when big numerators or
denominators are used.
</action>
<action dev="luc" type="add" issue="MATH-246" due-to="Benjamin McCann">
Added an optimizer for constrained linear problems based on 2-phases standard simplex.
</action>

View File

@ -34,14 +34,20 @@
<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
org.apache.commons.math.fraction.Fraction</a> and
<a href="../apidocs/org/apache/commons/math/fraction/BigFraction.html">
org.apache.commons.math.fraction.BigFraction</a> provide fraction number
type that forms the basis for the fraction functionality found in
commons-math.
commons-math. The former one can be used for fractions whose numerators
and denominators are small enough to fit in an int (taking care of intermediate
values) while the second class should be used when there is a risk the numerator
and denominator grow very large.
</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>
A fraction number, can be built from two integer arguments representing numerator
and denominator or from a double which will be approximated:
<source>Fraction f = new Fraction(1, 3); // 1 / 3
Fraction g = new Fraction(0.25); // 1 / 4</source>
</p>
<p>
Of special note with fraction construction, when a fraction is created it is always reduced to lowest terms.

View File

@ -0,0 +1,540 @@
/*
* 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.BigDecimal;
import java.math.BigInteger;
import org.apache.commons.math.ConvergenceException;
import junit.framework.TestCase;
public class BigFractionTest extends TestCase {
private void assertFraction(int expectedNumerator, int expectedDenominator, BigFraction actual) {
assertEquals(expectedNumerator, actual.getNumeratorAsInt());
assertEquals(expectedDenominator, actual.getDenominatorAsInt());
}
private void assertFraction(long expectedNumerator, long expectedDenominator, BigFraction actual) {
assertEquals(expectedNumerator, actual.getNumeratorAsLong());
assertEquals(expectedDenominator, actual.getDenominatorAsLong());
}
public void testConstructor() {
assertFraction(0, 1, new BigFraction(0, 1));
assertFraction(0, 1, new BigFraction(0l, 2l));
assertFraction(0, 1, new BigFraction(0, -1));
assertFraction(1, 2, new BigFraction(1, 2));
assertFraction(1, 2, new BigFraction(2, 4));
assertFraction(-1, 2, new BigFraction(-1, 2));
assertFraction(-1, 2, new BigFraction(1, -2));
assertFraction(-1, 2, new BigFraction(-2, 4));
assertFraction(-1, 2, new BigFraction(2, -4));
assertFraction(11, 1, new BigFraction(11));
assertFraction(11, 1, new BigFraction(11l));
assertFraction(11, 1, new BigFraction(new BigInteger("11")));
try {
assertFraction(0, 1, new BigFraction(0.00000000000001, 1.0e-5, 100));
assertFraction(2, 5, new BigFraction(0.40000000000001, 1.0e-5, 100));
assertFraction(15, 1, new BigFraction(15.0000000000001, 1.0e-5, 100));
} catch (ConvergenceException ex) {
fail(ex.getMessage());
}
assertEquals(0.00000000000001, new BigFraction(0.00000000000001).doubleValue(), 0.0);
assertEquals(0.40000000000001, new BigFraction(0.40000000000001).doubleValue(), 0.0);
assertEquals(15.0000000000001, new BigFraction(15.0000000000001).doubleValue(), 0.0);
assertFraction(3602879701896487l, 9007199254740992l, new BigFraction(0.40000000000001));
assertFraction(1055531162664967l, 70368744177664l, new BigFraction(15.0000000000001));
try {
new BigFraction(null, BigInteger.ONE);
} catch (NullPointerException npe) {
// expected
}
try {
new BigFraction(BigInteger.ONE, null);
} catch (NullPointerException npe) {
// expected
}
try {
new BigFraction(BigInteger.ONE, BigInteger.ZERO);
} catch (ArithmeticException npe) {
// expected
}
try {
new BigFraction(2.0 * Integer.MAX_VALUE, 1.0e-5, 100000);
} catch (FractionConversionException fce) {
// expected
}
}
public void testGoldenRatio() {
try {
// the golden ratio is notoriously a difficult number for continuous
// fraction
new BigFraction((1 + Math.sqrt(5)) / 2, 1.0e-12, 25);
fail("an exception should have been thrown");
} catch (ConvergenceException ce) {
// expected behavior
} catch (Exception e) {
fail("wrong exception caught");
}
}
// MATH-179
public void testDoubleConstructor() throws ConvergenceException {
assertFraction(1, 2, new BigFraction((double) 1 / (double) 2, 1.0e-5, 100));
assertFraction(1, 3, new BigFraction((double) 1 / (double) 3, 1.0e-5, 100));
assertFraction(2, 3, new BigFraction((double) 2 / (double) 3, 1.0e-5, 100));
assertFraction(1, 4, new BigFraction((double) 1 / (double) 4, 1.0e-5, 100));
assertFraction(3, 4, new BigFraction((double) 3 / (double) 4, 1.0e-5, 100));
assertFraction(1, 5, new BigFraction((double) 1 / (double) 5, 1.0e-5, 100));
assertFraction(2, 5, new BigFraction((double) 2 / (double) 5, 1.0e-5, 100));
assertFraction(3, 5, new BigFraction((double) 3 / (double) 5, 1.0e-5, 100));
assertFraction(4, 5, new BigFraction((double) 4 / (double) 5, 1.0e-5, 100));
assertFraction(1, 6, new BigFraction((double) 1 / (double) 6, 1.0e-5, 100));
assertFraction(5, 6, new BigFraction((double) 5 / (double) 6, 1.0e-5, 100));
assertFraction(1, 7, new BigFraction((double) 1 / (double) 7, 1.0e-5, 100));
assertFraction(2, 7, new BigFraction((double) 2 / (double) 7, 1.0e-5, 100));
assertFraction(3, 7, new BigFraction((double) 3 / (double) 7, 1.0e-5, 100));
assertFraction(4, 7, new BigFraction((double) 4 / (double) 7, 1.0e-5, 100));
assertFraction(5, 7, new BigFraction((double) 5 / (double) 7, 1.0e-5, 100));
assertFraction(6, 7, new BigFraction((double) 6 / (double) 7, 1.0e-5, 100));
assertFraction(1, 8, new BigFraction((double) 1 / (double) 8, 1.0e-5, 100));
assertFraction(3, 8, new BigFraction((double) 3 / (double) 8, 1.0e-5, 100));
assertFraction(5, 8, new BigFraction((double) 5 / (double) 8, 1.0e-5, 100));
assertFraction(7, 8, new BigFraction((double) 7 / (double) 8, 1.0e-5, 100));
assertFraction(1, 9, new BigFraction((double) 1 / (double) 9, 1.0e-5, 100));
assertFraction(2, 9, new BigFraction((double) 2 / (double) 9, 1.0e-5, 100));
assertFraction(4, 9, new BigFraction((double) 4 / (double) 9, 1.0e-5, 100));
assertFraction(5, 9, new BigFraction((double) 5 / (double) 9, 1.0e-5, 100));
assertFraction(7, 9, new BigFraction((double) 7 / (double) 9, 1.0e-5, 100));
assertFraction(8, 9, new BigFraction((double) 8 / (double) 9, 1.0e-5, 100));
assertFraction(1, 10, new BigFraction((double) 1 / (double) 10, 1.0e-5, 100));
assertFraction(3, 10, new BigFraction((double) 3 / (double) 10, 1.0e-5, 100));
assertFraction(7, 10, new BigFraction((double) 7 / (double) 10, 1.0e-5, 100));
assertFraction(9, 10, new BigFraction((double) 9 / (double) 10, 1.0e-5, 100));
assertFraction(1, 11, new BigFraction((double) 1 / (double) 11, 1.0e-5, 100));
assertFraction(2, 11, new BigFraction((double) 2 / (double) 11, 1.0e-5, 100));
assertFraction(3, 11, new BigFraction((double) 3 / (double) 11, 1.0e-5, 100));
assertFraction(4, 11, new BigFraction((double) 4 / (double) 11, 1.0e-5, 100));
assertFraction(5, 11, new BigFraction((double) 5 / (double) 11, 1.0e-5, 100));
assertFraction(6, 11, new BigFraction((double) 6 / (double) 11, 1.0e-5, 100));
assertFraction(7, 11, new BigFraction((double) 7 / (double) 11, 1.0e-5, 100));
assertFraction(8, 11, new BigFraction((double) 8 / (double) 11, 1.0e-5, 100));
assertFraction(9, 11, new BigFraction((double) 9 / (double) 11, 1.0e-5, 100));
assertFraction(10, 11, new BigFraction((double) 10 / (double) 11, 1.0e-5, 100));
}
// MATH-181
public void testDigitLimitConstructor() throws ConvergenceException {
assertFraction(2, 5, new BigFraction(0.4, 9));
assertFraction(2, 5, new BigFraction(0.4, 99));
assertFraction(2, 5, new BigFraction(0.4, 999));
assertFraction(3, 5, new BigFraction(0.6152, 9));
assertFraction(8, 13, new BigFraction(0.6152, 99));
assertFraction(510, 829, new BigFraction(0.6152, 999));
assertFraction(769, 1250, new BigFraction(0.6152, 9999));
}
public void testEpsilonLimitConstructor() throws ConvergenceException {
assertFraction(2, 5, new BigFraction(0.4, 1.0e-5, 100));
assertFraction(3, 5, new BigFraction(0.6152, 0.02, 100));
assertFraction(8, 13, new BigFraction(0.6152, 1.0e-3, 100));
assertFraction(251, 408, new BigFraction(0.6152, 1.0e-4, 100));
assertFraction(251, 408, new BigFraction(0.6152, 1.0e-5, 100));
assertFraction(510, 829, new BigFraction(0.6152, 1.0e-6, 100));
assertFraction(769, 1250, new BigFraction(0.6152, 1.0e-7, 100));
}
public void testCompareTo() {
BigFraction first = new BigFraction(1, 2);
BigFraction second = new BigFraction(1, 3);
BigFraction third = new BigFraction(1, 2);
assertEquals(0, first.compareTo(first));
assertEquals(0, first.compareTo(third));
assertEquals(1, first.compareTo(second));
assertEquals(-1, second.compareTo(first));
// these two values are different approximations of PI
// the first one is approximately PI - 3.07e-18
// the second one is approximately PI + 1.936e-17
BigFraction pi1 = new BigFraction(1068966896, 340262731);
BigFraction pi2 = new BigFraction( 411557987, 131002976);
assertEquals(-1, pi1.compareTo(pi2));
assertEquals( 1, pi2.compareTo(pi1));
assertEquals(0.0, pi1.doubleValue() - pi2.doubleValue(), 1.0e-20);
}
public void testDoubleValue() {
BigFraction first = new BigFraction(1, 2);
BigFraction second = new BigFraction(1, 3);
assertEquals(0.5, first.doubleValue(), 0.0);
assertEquals(1.0 / 3.0, second.doubleValue(), 0.0);
}
public void testFloatValue() {
BigFraction first = new BigFraction(1, 2);
BigFraction second = new BigFraction(1, 3);
assertEquals(0.5f, first.floatValue(), 0.0f);
assertEquals((float) (1.0 / 3.0), second.floatValue(), 0.0f);
}
public void testIntValue() {
BigFraction first = new BigFraction(1, 2);
BigFraction second = new BigFraction(3, 2);
assertEquals(0, first.intValue());
assertEquals(1, second.intValue());
}
public void testLongValue() {
BigFraction first = new BigFraction(1, 2);
BigFraction second = new BigFraction(3, 2);
assertEquals(0L, first.longValue());
assertEquals(1L, second.longValue());
}
public void testConstructorDouble() {
assertFraction(1, 2, new BigFraction(0.5));
assertFraction(6004799503160661l, 18014398509481984l, new BigFraction(1.0 / 3.0));
assertFraction(6124895493223875l, 36028797018963968l, new BigFraction(17.0 / 100.0));
assertFraction(1784551352345559l, 562949953421312l, new BigFraction(317.0 / 100.0));
assertFraction(-1, 2, new BigFraction(-0.5));
assertFraction(-6004799503160661l, 18014398509481984l, new BigFraction(-1.0 / 3.0));
assertFraction(-6124895493223875l, 36028797018963968l, new BigFraction(17.0 / -100.0));
assertFraction(-1784551352345559l, 562949953421312l, new BigFraction(-317.0 / 100.0));
for (double v : new double[] { Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY}) {
try {
new BigFraction(v);
fail("expected exception");
} catch (IllegalArgumentException iae) {
// expected
}
}
assertEquals(1l, new BigFraction(Double.MAX_VALUE).getDenominatorAsLong());
assertEquals(1l, new BigFraction(Double.MIN_NORMAL).getNumeratorAsLong());
assertEquals(1l, new BigFraction(Double.MIN_VALUE).getNumeratorAsLong());
}
public void testAbs() {
BigFraction a = new BigFraction(10, 21);
BigFraction b = new BigFraction(-10, 21);
BigFraction c = new BigFraction(10, -21);
assertFraction(10, 21, a.abs());
assertFraction(10, 21, b.abs());
assertFraction(10, 21, c.abs());
}
public void testReciprocal() {
BigFraction f = null;
f = new BigFraction(50, 75);
f = f.reciprocal();
assertEquals(3, f.getNumeratorAsInt());
assertEquals(2, f.getDenominatorAsInt());
f = new BigFraction(4, 3);
f = f.reciprocal();
assertEquals(3, f.getNumeratorAsInt());
assertEquals(4, f.getDenominatorAsInt());
f = new BigFraction(-15, 47);
f = f.reciprocal();
assertEquals(-47, f.getNumeratorAsInt());
assertEquals(15, f.getDenominatorAsInt());
f = new BigFraction(0, 3);
try {
f = f.reciprocal();
fail("expecting ArithmeticException");
} catch (ArithmeticException ex) {
}
// large values
f = new BigFraction(Integer.MAX_VALUE, 1);
f = f.reciprocal();
assertEquals(1, f.getNumeratorAsInt());
assertEquals(Integer.MAX_VALUE, f.getDenominatorAsInt());
}
public void testNegate() {
BigFraction f = null;
f = new BigFraction(50, 75);
f = f.negate();
assertEquals(-2, f.getNumeratorAsInt());
assertEquals(3, f.getDenominatorAsInt());
f = new BigFraction(-50, 75);
f = f.negate();
assertEquals(2, f.getNumeratorAsInt());
assertEquals(3, f.getDenominatorAsInt());
// large values
f = new BigFraction(Integer.MAX_VALUE - 1, Integer.MAX_VALUE);
f = f.negate();
assertEquals(Integer.MIN_VALUE + 2, f.getNumeratorAsInt());
assertEquals(Integer.MAX_VALUE, f.getDenominatorAsInt());
}
public void testAdd() {
BigFraction a = new BigFraction(1, 2);
BigFraction b = new BigFraction(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));
BigFraction f1 = new BigFraction(Integer.MAX_VALUE - 1, 1);
BigFraction f2 = BigFraction.ONE;
BigFraction f = f1.add(f2);
assertEquals(Integer.MAX_VALUE, f.getNumeratorAsInt());
assertEquals(1, f.getDenominatorAsInt());
f1 = new BigFraction(-1, 13 * 13 * 2 * 2);
f2 = new BigFraction(-2, 13 * 17 * 2);
f = f1.add(f2);
assertEquals(13 * 13 * 17 * 2 * 2, f.getDenominatorAsInt());
assertEquals(-17 - 2 * 13 * 2, f.getNumeratorAsInt());
try {
f.add((BigFraction) null);
fail("expecting NullPointerException");
} catch (NullPointerException ex) {
}
// if this fraction is added naively, it will overflow.
// check that it doesn't.
f1 = new BigFraction(1, 32768 * 3);
f2 = new BigFraction(1, 59049);
f = f1.add(f2);
assertEquals(52451, f.getNumeratorAsInt());
assertEquals(1934917632, f.getDenominatorAsInt());
f1 = new BigFraction(Integer.MIN_VALUE, 3);
f2 = new BigFraction(1, 3);
f = f1.add(f2);
assertEquals(Integer.MIN_VALUE + 1, f.getNumeratorAsInt());
assertEquals(3, f.getDenominatorAsInt());
f1 = new BigFraction(Integer.MAX_VALUE - 1, 1);
f = f1.add(BigInteger.ONE);
assertEquals(Integer.MAX_VALUE, f.getNumeratorAsInt());
assertEquals(1, f.getDenominatorAsInt());
f = f.add(BigInteger.ZERO);
assertEquals(Integer.MAX_VALUE, f.getNumeratorAsInt());
assertEquals(1, f.getDenominatorAsInt());
f1 = new BigFraction(Integer.MAX_VALUE - 1, 1);
f = f1.add(1);
assertEquals(Integer.MAX_VALUE, f.getNumeratorAsInt());
assertEquals(1, f.getDenominatorAsInt());
f = f.add(0);
assertEquals(Integer.MAX_VALUE, f.getNumeratorAsInt());
assertEquals(1, f.getDenominatorAsInt());
f1 = new BigFraction(Integer.MAX_VALUE - 1, 1);
f = f1.add(1l);
assertEquals(Integer.MAX_VALUE, f.getNumeratorAsInt());
assertEquals(1, f.getDenominatorAsInt());
f = f.add(0l);
assertEquals(Integer.MAX_VALUE, f.getNumeratorAsInt());
assertEquals(1, f.getDenominatorAsInt());
}
public void testDivide() {
BigFraction a = new BigFraction(1, 2);
BigFraction b = new BigFraction(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));
BigFraction f1 = new BigFraction(3, 5);
BigFraction f2 = BigFraction.ZERO;
try {
f1.divide(f2);
fail("expecting ArithmeticException");
} catch (ArithmeticException ex) {
}
f1 = new BigFraction(0, 5);
f2 = new BigFraction(2, 7);
BigFraction f = f1.divide(f2);
assertSame(BigFraction.ZERO, f);
f1 = new BigFraction(2, 7);
f2 = BigFraction.ONE;
f = f1.divide(f2);
assertEquals(2, f.getNumeratorAsInt());
assertEquals(7, f.getDenominatorAsInt());
f1 = new BigFraction(1, Integer.MAX_VALUE);
f = f1.divide(f1);
assertEquals(1, f.getNumeratorAsInt());
assertEquals(1, f.getDenominatorAsInt());
f1 = new BigFraction(Integer.MIN_VALUE, Integer.MAX_VALUE);
f2 = new BigFraction(1, Integer.MAX_VALUE);
f = f1.divide(f2);
assertEquals(Integer.MIN_VALUE, f.getNumeratorAsInt());
assertEquals(1, f.getDenominatorAsInt());
try {
f.divide((BigFraction) null);
fail("expecting NullPointerException");
} catch (NullPointerException ex) {
}
f1 = new BigFraction(Integer.MIN_VALUE, Integer.MAX_VALUE);
f = f1.divide(BigInteger.valueOf(Integer.MIN_VALUE));
assertEquals(Integer.MAX_VALUE, f.getDenominatorAsInt());
assertEquals(1, f.getNumeratorAsInt());
f1 = new BigFraction(Integer.MIN_VALUE, Integer.MAX_VALUE);
f = f1.divide(Integer.MIN_VALUE);
assertEquals(Integer.MAX_VALUE, f.getDenominatorAsInt());
assertEquals(1, f.getNumeratorAsInt());
f1 = new BigFraction(Integer.MIN_VALUE, Integer.MAX_VALUE);
f = f1.divide((long) Integer.MIN_VALUE);
assertEquals(Integer.MAX_VALUE, f.getDenominatorAsInt());
assertEquals(1, f.getNumeratorAsInt());
}
public void testMultiply() {
BigFraction a = new BigFraction(1, 2);
BigFraction b = new BigFraction(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));
BigFraction f1 = new BigFraction(Integer.MAX_VALUE, 1);
BigFraction f2 = new BigFraction(Integer.MIN_VALUE, Integer.MAX_VALUE);
BigFraction f = f1.multiply(f2);
assertEquals(Integer.MIN_VALUE, f.getNumeratorAsInt());
assertEquals(1, f.getDenominatorAsInt());
f = f2.multiply(Integer.MAX_VALUE);
assertEquals(Integer.MIN_VALUE, f.getNumeratorAsInt());
assertEquals(1, f.getDenominatorAsInt());
f = f2.multiply((long) Integer.MAX_VALUE);
assertEquals(Integer.MIN_VALUE, f.getNumeratorAsInt());
assertEquals(1, f.getDenominatorAsInt());
try {
f.multiply((BigFraction) null);
fail("expecting NullPointerException");
} catch (NullPointerException ex) {
}
}
public void testSubtract() {
BigFraction a = new BigFraction(1, 2);
BigFraction b = new BigFraction(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));
BigFraction f = new BigFraction(1, 1);
try {
f.subtract((BigFraction) null);
fail("expecting NullPointerException");
} catch (NullPointerException ex) {
}
// if this fraction is subtracted naively, it will overflow.
// check that it doesn't.
BigFraction f1 = new BigFraction(1, 32768 * 3);
BigFraction f2 = new BigFraction(1, 59049);
f = f1.subtract(f2);
assertEquals(-13085, f.getNumeratorAsInt());
assertEquals(1934917632, f.getDenominatorAsInt());
f1 = new BigFraction(Integer.MIN_VALUE, 3);
f2 = new BigFraction(1, 3).negate();
f = f1.subtract(f2);
assertEquals(Integer.MIN_VALUE + 1, f.getNumeratorAsInt());
assertEquals(3, f.getDenominatorAsInt());
f1 = new BigFraction(Integer.MAX_VALUE, 1);
f2 = BigFraction.ONE;
f = f1.subtract(f2);
assertEquals(Integer.MAX_VALUE - 1, f.getNumeratorAsInt());
assertEquals(1, f.getDenominatorAsInt());
}
public void testBigDecimalValue() {
assertEquals(new BigDecimal(0.5), new BigFraction(1, 2).bigDecimalValue());
assertEquals(new BigDecimal("0.0003"), new BigFraction(3, 10000).bigDecimalValue());
assertEquals(new BigDecimal("0"), new BigFraction(1, 3).bigDecimalValue(BigDecimal.ROUND_DOWN));
assertEquals(new BigDecimal("0.333"), new BigFraction(1, 3).bigDecimalValue(3, BigDecimal.ROUND_DOWN));
}
public void testEqualsAndHashCode() {
BigFraction zero = new BigFraction(0, 1);
BigFraction nullFraction = null;
assertTrue(zero.equals(zero));
assertFalse(zero.equals(nullFraction));
assertFalse(zero.equals(Double.valueOf(0)));
BigFraction zero2 = new BigFraction(0, 2);
assertTrue(zero.equals(zero2));
assertEquals(zero.hashCode(), zero2.hashCode());
BigFraction one = new BigFraction(1, 1);
assertFalse((one.equals(zero) || zero.equals(one)));
assertTrue(one.equals(BigFraction.ONE));
}
public void testGetReducedFraction() {
BigFraction threeFourths = new BigFraction(3, 4);
assertTrue(threeFourths.equals(BigFraction.getReducedFraction(6, 8)));
assertTrue(BigFraction.ZERO.equals(BigFraction.getReducedFraction(0, -1)));
try {
BigFraction.getReducedFraction(1, 0);
fail("expecting ArithmeticException");
} catch (ArithmeticException ex) {
// expected
}
assertEquals(BigFraction.getReducedFraction(2, Integer.MIN_VALUE).getNumeratorAsInt(), -1);
assertEquals(BigFraction.getReducedFraction(1, -1).getNumeratorAsInt(), -1);
}
}