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:
parent
e449af6e51
commit
17f0dd2da5
3
pom.xml
3
pom.xml
|
@ -111,6 +111,9 @@
|
|||
<contributor>
|
||||
<name>Paul Cowan</name>
|
||||
</contributor>
|
||||
<contributor>
|
||||
<name>Benjamin Croizet</name>
|
||||
</contributor>
|
||||
<contributor>
|
||||
<name>Rodrigo di Lorenzo Lopes</name>
|
||||
</contributor>
|
||||
|
|
|
@ -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}.
|
||||
|
|
|
@ -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
|
@ -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>
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue