Fixed numeric problems reported in PR #29294
Submitted by: C. Scott Ananian Reviewed by: Phil Steitz git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/lang/trunk@137879 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
02dde889ee
commit
13ae992c23
|
@ -16,6 +16,7 @@
|
||||||
package org.apache.commons.lang.math;
|
package org.apache.commons.lang.math;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p><code>Fraction</code> is a <code>Number</code> implementation that
|
* <p><code>Fraction</code> is a <code>Number</code> implementation that
|
||||||
|
@ -28,8 +29,9 @@ import java.io.Serializable;
|
||||||
* @author Stephen Colebourne
|
* @author Stephen Colebourne
|
||||||
* @author Tim O'Brien
|
* @author Tim O'Brien
|
||||||
* @author Pete Gieser
|
* @author Pete Gieser
|
||||||
|
* @author C. Scott Ananian
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
* @version $Id: Fraction.java,v 1.13 2004/02/18 22:56:13 ggregory Exp $
|
* @version $Id: Fraction.java,v 1.14 2004/07/11 23:20:17 psteitz Exp $
|
||||||
*/
|
*/
|
||||||
public final class Fraction extends Number implements Serializable, Comparable {
|
public final class Fraction extends Number implements Serializable, Comparable {
|
||||||
|
|
||||||
|
@ -137,6 +139,10 @@ public final class Fraction extends Number implements Serializable, Comparable {
|
||||||
throw new ArithmeticException("The denominator must not be zero");
|
throw new ArithmeticException("The denominator must not be zero");
|
||||||
}
|
}
|
||||||
if (denominator < 0) {
|
if (denominator < 0) {
|
||||||
|
if (numerator==Integer.MIN_VALUE ||
|
||||||
|
denominator==Integer.MIN_VALUE) {
|
||||||
|
throw new ArithmeticException("overflow: can't negate");
|
||||||
|
}
|
||||||
numerator = -numerator;
|
numerator = -numerator;
|
||||||
denominator = -denominator;
|
denominator = -denominator;
|
||||||
}
|
}
|
||||||
|
@ -154,7 +160,7 @@ public final class Fraction extends Number implements Serializable, Comparable {
|
||||||
* @param denominator the denominator, for example the seven in 'one and three sevenths'
|
* @param denominator the denominator, for example the seven in 'one and three sevenths'
|
||||||
* @return a new fraction instance
|
* @return a new fraction instance
|
||||||
* @throws ArithmeticException if the denomiator is <code>zero</code>
|
* @throws ArithmeticException if the denomiator is <code>zero</code>
|
||||||
* @throws ArithmeticException if the denomiator is negative
|
* @throws ArithmeticException if the denominator is negative
|
||||||
* @throws ArithmeticException if the numerator is negative
|
* @throws ArithmeticException if the numerator is negative
|
||||||
* @throws ArithmeticException if the resulting numerator exceeds
|
* @throws ArithmeticException if the resulting numerator exceeds
|
||||||
* <code>Integer.MAX_VALUE</code>
|
* <code>Integer.MAX_VALUE</code>
|
||||||
|
@ -169,13 +175,14 @@ public final class Fraction extends Number implements Serializable, Comparable {
|
||||||
if (numerator < 0) {
|
if (numerator < 0) {
|
||||||
throw new ArithmeticException("The numerator must not be negative");
|
throw new ArithmeticException("The numerator must not be negative");
|
||||||
}
|
}
|
||||||
double numeratorValue = 0;
|
long numeratorValue;
|
||||||
if (whole < 0) {
|
if (whole < 0) {
|
||||||
numeratorValue = (double) whole * denominator - numerator;
|
numeratorValue = whole * (long)denominator - numerator;
|
||||||
} else {
|
} else {
|
||||||
numeratorValue = (double) whole * denominator + numerator;
|
numeratorValue = whole * (long)denominator + numerator;
|
||||||
}
|
}
|
||||||
if (Math.abs(numeratorValue) > Integer.MAX_VALUE) {
|
if (numeratorValue < Integer.MIN_VALUE ||
|
||||||
|
numeratorValue > Integer.MAX_VALUE) {
|
||||||
throw new ArithmeticException("Numerator too large to represent as an Integer.");
|
throw new ArithmeticException("Numerator too large to represent as an Integer.");
|
||||||
}
|
}
|
||||||
return new Fraction((int) numeratorValue, denominator);
|
return new Fraction((int) numeratorValue, denominator);
|
||||||
|
@ -190,18 +197,32 @@ public final class Fraction extends Number implements Serializable, Comparable {
|
||||||
* @param numerator the numerator, for example the three in 'three sevenths'
|
* @param numerator the numerator, for example the three in 'three sevenths'
|
||||||
* @param denominator the denominator, for example the seven in 'three sevenths'
|
* @param denominator the denominator, for example the seven in 'three sevenths'
|
||||||
* @return a new fraction instance, with the numerator and denominator reduced
|
* @return a new fraction instance, with the numerator and denominator reduced
|
||||||
* @throws ArithmeticException if the denomiator is <code>zero</code>
|
* @throws ArithmeticException if the denominator is <code>zero</code>
|
||||||
*/
|
*/
|
||||||
public static Fraction getReducedFraction(int numerator, int denominator) {
|
public static Fraction getReducedFraction(int numerator, int denominator) {
|
||||||
if (denominator == 0) {
|
if (denominator == 0) {
|
||||||
throw new ArithmeticException("The denominator must not be zero");
|
throw new ArithmeticException("The denominator must not be zero");
|
||||||
}
|
}
|
||||||
|
if (numerator==0) {
|
||||||
|
return ZERO; // normalize zero.
|
||||||
|
}
|
||||||
|
// allow 2^k/-2^31 as a valid fraction (where k>0)
|
||||||
|
if (denominator==Integer.MIN_VALUE && (numerator&1)==0) {
|
||||||
|
numerator/=2; denominator/=2;
|
||||||
|
}
|
||||||
if (denominator < 0) {
|
if (denominator < 0) {
|
||||||
|
if (numerator==Integer.MIN_VALUE ||
|
||||||
|
denominator==Integer.MIN_VALUE) {
|
||||||
|
throw new ArithmeticException("overflow: can't negate");
|
||||||
|
}
|
||||||
numerator = -numerator;
|
numerator = -numerator;
|
||||||
denominator = -denominator;
|
denominator = -denominator;
|
||||||
}
|
}
|
||||||
int gcd = greatestCommonDivisor(Math.abs(numerator), denominator);
|
// simplify fraction.
|
||||||
return new Fraction(numerator / gcd, denominator / gcd);
|
int gcd = greatestCommonDivisor(numerator, denominator);
|
||||||
|
numerator /= gcd;
|
||||||
|
denominator /= gcd;
|
||||||
|
return new Fraction(numerator, denominator);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -215,7 +236,7 @@ public final class Fraction extends Number implements Serializable, Comparable {
|
||||||
* @return a new fraction instance that is close to the value
|
* @return a new fraction instance that is close to the value
|
||||||
* @throws ArithmeticException if <code>|value| > Integer.MAX_VALUE</code>
|
* @throws ArithmeticException if <code>|value| > Integer.MAX_VALUE</code>
|
||||||
* or <code>value = NaN</code>
|
* or <code>value = NaN</code>
|
||||||
* @throws ArithmeticException if the calculated denomiator is <code>zero</code>
|
* @throws ArithmeticException if the calculated denominator is <code>zero</code>
|
||||||
* @throws ArithmeticException if the the algorithm does not converge
|
* @throws ArithmeticException if the the algorithm does not converge
|
||||||
*/
|
*/
|
||||||
public static Fraction getFraction(double value) {
|
public static Fraction getFraction(double value) {
|
||||||
|
@ -275,11 +296,11 @@ public final class Fraction extends Number implements Serializable, Comparable {
|
||||||
*
|
*
|
||||||
* <p>The formats accepted are:</p>
|
* <p>The formats accepted are:</p>
|
||||||
*
|
*
|
||||||
* <p>
|
|
||||||
* <ol>
|
* <ol>
|
||||||
* <li><code>double</code> String containing a dot</li>
|
* <li><code>double</code> String containing a dot</li>
|
||||||
* <li>'X Y/Z'</li>
|
* <li>'X Y/Z'</li>
|
||||||
* <li>'Y/Z'</li>
|
* <li>'Y/Z'</li>
|
||||||
|
* <li>'X' (a simple whole number)</li>
|
||||||
* </ol>
|
* </ol>
|
||||||
* and a .</p>
|
* and a .</p>
|
||||||
*
|
*
|
||||||
|
@ -307,11 +328,9 @@ public final class Fraction extends Number implements Serializable, Comparable {
|
||||||
if (pos < 0) {
|
if (pos < 0) {
|
||||||
throw new NumberFormatException("The fraction could not be parsed as the format X Y/Z");
|
throw new NumberFormatException("The fraction could not be parsed as the format X Y/Z");
|
||||||
} else {
|
} else {
|
||||||
|
int numer = Integer.parseInt(str.substring(0, pos));
|
||||||
int denom = Integer.parseInt(str.substring(pos + 1));
|
int denom = Integer.parseInt(str.substring(pos + 1));
|
||||||
return getFraction(
|
return getFraction(whole, numer, denom);
|
||||||
Integer.parseInt(str.substring(0, pos)) + whole * denom,
|
|
||||||
denom
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,10 +340,9 @@ public final class Fraction extends Number implements Serializable, Comparable {
|
||||||
// simple whole number
|
// simple whole number
|
||||||
return getFraction(Integer.parseInt(str), 1);
|
return getFraction(Integer.parseInt(str), 1);
|
||||||
} else {
|
} else {
|
||||||
return getFraction(
|
int numer = Integer.parseInt(str.substring(0, pos));
|
||||||
Integer.parseInt(str.substring(0, pos)),
|
int denom = Integer.parseInt(str.substring(pos + 1));
|
||||||
Integer.parseInt(str.substring(pos + 1))
|
return getFraction(numer, denom);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,18 +458,26 @@ public final class Fraction extends Number implements Serializable, Comparable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Gets a fraction that is the invert (1/fraction) of this one.</p>
|
* <p>Gets a fraction that is the inverse (1/fraction) of this one.</p>
|
||||||
*
|
*
|
||||||
* <p>The returned fraction is not reduced.</p>
|
* <p>The returned fraction is not reduced.</p>
|
||||||
*
|
*
|
||||||
* @return a new fraction instance with the numerator and denominator inverted
|
* @return a new fraction instance with the numerator and denominator
|
||||||
* @throws ArithmeticException if the numerator is <code>zero</code>
|
* inverted.
|
||||||
|
* @throws ArithmeticException if the fraction represents zero.
|
||||||
*/
|
*/
|
||||||
public Fraction invert() {
|
public Fraction invert() {
|
||||||
if (numerator == 0) {
|
if (numerator == 0) {
|
||||||
throw new ArithmeticException("Unable to invert a fraction with a zero numerator");
|
throw new ArithmeticException("Unable to invert zero.");
|
||||||
|
}
|
||||||
|
if (numerator==Integer.MIN_VALUE) {
|
||||||
|
throw new ArithmeticException("overflow: can't negate numerator");
|
||||||
|
}
|
||||||
|
if (numerator<0) {
|
||||||
|
return new Fraction(-denominator, -numerator);
|
||||||
|
} else {
|
||||||
|
return new Fraction(denominator, numerator);
|
||||||
}
|
}
|
||||||
return getFraction(denominator, numerator);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -462,12 +488,16 @@ public final class Fraction extends Number implements Serializable, Comparable {
|
||||||
* @return a new fraction instance with the opposite signed numerator
|
* @return a new fraction instance with the opposite signed numerator
|
||||||
*/
|
*/
|
||||||
public Fraction negate() {
|
public Fraction negate() {
|
||||||
return getFraction(-numerator, denominator);
|
// the positive range is one smaller than the negative range of an int.
|
||||||
|
if (numerator==Integer.MIN_VALUE) {
|
||||||
|
throw new ArithmeticException("overflow: too large to negate");
|
||||||
|
}
|
||||||
|
return new Fraction(-numerator, denominator);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Gets a fraction that is the positive equivalent of this one.</p>
|
* <p>Gets a fraction that is the positive equivalent of this one.</p>
|
||||||
* <p>More precisely: <pre>(fraction >= 0 ? this : -fraction)</pre></p>
|
* <p>More precisely: <code>(fraction >= 0 ? this : -fraction)</code></p>
|
||||||
*
|
*
|
||||||
* <p>The returned fraction is not reduced.</p>
|
* <p>The returned fraction is not reduced.</p>
|
||||||
*
|
*
|
||||||
|
@ -478,13 +508,13 @@ public final class Fraction extends Number implements Serializable, Comparable {
|
||||||
if (numerator >= 0) {
|
if (numerator >= 0) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
return getFraction(-numerator, denominator);
|
return negate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Gets a fraction that is raised to the passed in power.</p>
|
* <p>Gets a fraction that is raised to the passed in power.</p>
|
||||||
*
|
*
|
||||||
* <p>The returned fraction is not reduced.</p>
|
* <p>The returned fraction is in reduced form.</p>
|
||||||
*
|
*
|
||||||
* @param power the power to raise the fraction to
|
* @param power the power to raise the fraction to
|
||||||
* @return <code>this</code> if the power is one, <code>ONE</code> if the power
|
* @return <code>this</code> if the power is one, <code>ONE</code> if the power
|
||||||
|
@ -498,44 +528,150 @@ public final class Fraction extends Number implements Serializable, Comparable {
|
||||||
return this;
|
return this;
|
||||||
} else if (power == 0) {
|
} else if (power == 0) {
|
||||||
return ONE;
|
return ONE;
|
||||||
|
} else if (power < 0) {
|
||||||
|
if (power==Integer.MIN_VALUE) { // MIN_VALUE can't be negated.
|
||||||
|
return this.invert().pow(2).pow(-(power/2));
|
||||||
|
}
|
||||||
|
return this.invert().pow(-power);
|
||||||
} else {
|
} else {
|
||||||
double denominatorValue = Math.pow(denominator, power);
|
Fraction f = this.multiplyBy(this);
|
||||||
double numeratorValue = Math.pow(numerator, power);
|
if ((power % 2) == 0) { // if even...
|
||||||
if (numeratorValue > Integer.MAX_VALUE || denominatorValue > Integer.MAX_VALUE) {
|
return f.pow(power/2);
|
||||||
throw new ArithmeticException("Integer overflow");
|
} else { // if odd...
|
||||||
|
return f.pow(power/2).multiplyBy(this);
|
||||||
}
|
}
|
||||||
if (power < 0) {
|
|
||||||
return getFraction((int) Math.pow(denominator, -power),
|
|
||||||
(int) Math.pow(numerator, -power));
|
|
||||||
}
|
|
||||||
return getFraction((int) Math.pow(numerator, power),
|
|
||||||
(int) Math.pow(denominator, power));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Gets the greatest common divisor of two numbers.</p>
|
* <p>Gets the greatest common divisor of the absolute value of
|
||||||
|
* two numbers, using the "binary gcd" method which avoids
|
||||||
|
* division and modulo operations. See Knuth 4.5.2 algorithm B.
|
||||||
|
* This algorithm is due to Josef Stein (1961).</p>
|
||||||
*
|
*
|
||||||
* @param number1 a positive number
|
* @param u a non-zero number
|
||||||
* @param number2 a positive number
|
* @param v a non-zero number
|
||||||
* @return the greatest common divisor, never zero
|
* @return the greatest common divisor, never zero
|
||||||
*/
|
*/
|
||||||
private static int greatestCommonDivisor(int number1, int number2) {
|
private static int greatestCommonDivisor(int u, int v) {
|
||||||
int remainder = number1 % number2;
|
// keep u and v negative, as negative integers range down to
|
||||||
while (remainder != 0) {
|
// -2^31, while positive numbers can only be as large as 2^31-1
|
||||||
number1 = number2;
|
// (i.e. we can't necessarily negate a negative number without
|
||||||
number2 = remainder;
|
// overflow)
|
||||||
remainder = number1 % number2;
|
/* assert u!=0 && v!=0; */
|
||||||
|
if (u>0) { u=-u; } // make u negative
|
||||||
|
if (v>0) { v=-v; } // make v negative
|
||||||
|
// B1. [Find power of 2]
|
||||||
|
int k=0;
|
||||||
|
while ((u&1)==0 && (v&1)==0 && k<31) { // while u and v are both even...
|
||||||
|
u/=2; v/=2; k++; // cast out twos.
|
||||||
}
|
}
|
||||||
return number2;
|
if (k==31) {
|
||||||
|
throw new ArithmeticException("overflow: gcd is 2^31");
|
||||||
|
}
|
||||||
|
// B2. Initialize: u and v have been divided by 2^k and at least
|
||||||
|
// one is odd.
|
||||||
|
int t = ((u&1)==1) ? v : -(u/2)/*B3*/;
|
||||||
|
// t negative: u was odd, v may be even (t replaces v)
|
||||||
|
// t positive: u was even, v is odd (t replaces u)
|
||||||
|
do {
|
||||||
|
/* assert u<0 && v<0; */
|
||||||
|
// B4/B3: cast out twos from t.
|
||||||
|
while ((t&1)==0) { // while t is even..
|
||||||
|
t/=2; // cast out twos
|
||||||
|
}
|
||||||
|
// B5 [reset max(u,v)]
|
||||||
|
if (t>0) {
|
||||||
|
u = -t;
|
||||||
|
} else {
|
||||||
|
v = t;
|
||||||
|
}
|
||||||
|
// B6/B3. at this point both u and v should be odd.
|
||||||
|
t = (v - u)/2;
|
||||||
|
// |u| larger: t positive (replace u)
|
||||||
|
// |v| larger: t negative (replace v)
|
||||||
|
} while (t!=0);
|
||||||
|
return -u*(1<<k); // gcd is u*2^k
|
||||||
}
|
}
|
||||||
|
|
||||||
// Arithmetic
|
// Arithmetic
|
||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Adds the value of this fraction to another, returning the result in
|
* Multiply two integers, checking for overflow.
|
||||||
* reduced form.</p>
|
*
|
||||||
|
* @param x a factor
|
||||||
|
* @param y a factor
|
||||||
|
* @return the product <code>x*y</code>
|
||||||
|
* @throws ArithmeticException if the result can not be represented as
|
||||||
|
* an int
|
||||||
|
*/
|
||||||
|
private static int mulAndCheck(int x, int y) {
|
||||||
|
long m = ((long)x)*((long)y);
|
||||||
|
if (m < Integer.MIN_VALUE ||
|
||||||
|
m > Integer.MAX_VALUE) {
|
||||||
|
throw new ArithmeticException("overflow: mul");
|
||||||
|
}
|
||||||
|
return (int)m;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multiply two non-negative integers, checking for overflow.
|
||||||
|
*
|
||||||
|
* @param x a non-negative factor
|
||||||
|
* @param y a non-negative factor
|
||||||
|
* @return the product <code>x*y</code>
|
||||||
|
* @throws ArithmeticException if the result can not be represented as
|
||||||
|
* an int
|
||||||
|
*/
|
||||||
|
private static int mulPosAndCheck(int x, int y) {
|
||||||
|
/* assert x>=0 && y>=0; */
|
||||||
|
long m = ((long)x)*((long)y);
|
||||||
|
if (m > Integer.MAX_VALUE) {
|
||||||
|
throw new ArithmeticException("overflow: mulPos");
|
||||||
|
}
|
||||||
|
return (int)m;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add two integers, checking for overflow.
|
||||||
|
*
|
||||||
|
* @param x an addend
|
||||||
|
* @param y an addend
|
||||||
|
* @return the sum <code>x+y</code>
|
||||||
|
* @throws ArithmeticException if the result can not be represented as
|
||||||
|
* an int
|
||||||
|
*/
|
||||||
|
private static int addAndCheck(int x, int y) {
|
||||||
|
long s = (long)x+(long)y;
|
||||||
|
if (s < Integer.MIN_VALUE ||
|
||||||
|
s > Integer.MAX_VALUE) {
|
||||||
|
throw new ArithmeticException("overflow: add");
|
||||||
|
}
|
||||||
|
return (int)s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subtract two integers, checking for overflow.
|
||||||
|
*
|
||||||
|
* @param x the minuend
|
||||||
|
* @param y the subtrahend
|
||||||
|
* @return the difference <code>x-y</code>
|
||||||
|
* @throws ArithmeticException if the result can not be represented as
|
||||||
|
* an int
|
||||||
|
*/
|
||||||
|
private static int subAndCheck(int x, int y) {
|
||||||
|
long s = (long)x-(long)y;
|
||||||
|
if (s < Integer.MIN_VALUE ||
|
||||||
|
s > Integer.MAX_VALUE) {
|
||||||
|
throw new ArithmeticException("overflow: add");
|
||||||
|
}
|
||||||
|
return (int)s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Adds the value of this fraction to another, returning the result in reduced form.
|
||||||
|
* The algorithm follows Knuth, 4.5.1.</p>
|
||||||
*
|
*
|
||||||
* @param fraction the fraction to add, must not be <code>null</code>
|
* @param fraction the fraction to add, must not be <code>null</code>
|
||||||
* @return a <code>Fraction</code> instance with the resulting values
|
* @return a <code>Fraction</code> instance with the resulting values
|
||||||
|
@ -544,26 +680,7 @@ public final class Fraction extends Number implements Serializable, Comparable {
|
||||||
* <code>Integer.MAX_VALUE</code>
|
* <code>Integer.MAX_VALUE</code>
|
||||||
*/
|
*/
|
||||||
public Fraction add(Fraction fraction) {
|
public Fraction add(Fraction fraction) {
|
||||||
if (fraction == null) {
|
return addSub(fraction, true /* add */);
|
||||||
throw new IllegalArgumentException("The fraction must not be null");
|
|
||||||
}
|
|
||||||
if (numerator == 0) {
|
|
||||||
return fraction;
|
|
||||||
}
|
|
||||||
if (fraction.numerator == 0) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
// Compute lcd explicitly to limit overflow
|
|
||||||
int gcd = greatestCommonDivisor(Math.abs(fraction.denominator), Math.abs(denominator));
|
|
||||||
int thisResidue = denominator/gcd;
|
|
||||||
int thatResidue = fraction.denominator/gcd;
|
|
||||||
double denominatorValue = Math.abs((double) gcd * thisResidue * thatResidue);
|
|
||||||
double numeratorValue = (double) numerator * thatResidue + fraction.numerator * thisResidue;
|
|
||||||
if (Math.abs(numeratorValue) > Integer.MAX_VALUE ||
|
|
||||||
Math.abs(denominatorValue) > Integer.MAX_VALUE) {
|
|
||||||
throw new ArithmeticException("Integer overflow");
|
|
||||||
}
|
|
||||||
return Fraction.getReducedFraction((int) numeratorValue, (int) denominatorValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -573,19 +690,72 @@ public final class Fraction extends Number implements Serializable, Comparable {
|
||||||
* @param fraction the fraction to subtract, must not be <code>null</code>
|
* @param fraction the fraction to subtract, must not be <code>null</code>
|
||||||
* @return a <code>Fraction</code> instance with the resulting values
|
* @return a <code>Fraction</code> instance with the resulting values
|
||||||
* @throws IllegalArgumentException if the fraction is <code>null</code>
|
* @throws IllegalArgumentException if the fraction is <code>null</code>
|
||||||
* @throws ArithmeticException if the resulting numerator or denominator exceeds
|
* @throws ArithmeticException if the resulting numerator or denominator
|
||||||
* <code>Integer.MAX_VALUE</code>
|
* cannot be represented in an <code>int</code>.
|
||||||
*/
|
*/
|
||||||
public Fraction subtract(Fraction fraction) {
|
public Fraction subtract(Fraction fraction) {
|
||||||
if (fraction == null) {
|
return addSub(fraction, false /* subtract */);
|
||||||
throw new IllegalArgumentException("The fraction must not be null");
|
|
||||||
}
|
|
||||||
return add(fraction.negate());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Multiplies the value of this fraction by another, returning the result
|
* Implement add and subtract using algorithm described in Knuth 4.5.1.
|
||||||
* in reduced form.</p>
|
*
|
||||||
|
* @param fraction the fraction to subtract, must not be <code>null</code>
|
||||||
|
* @param isAdd true to add, false to subtract
|
||||||
|
* @return a <code>Fraction</code> instance with the resulting values
|
||||||
|
* @throws IllegalArgumentException if the fraction is <code>null</code>
|
||||||
|
* @throws ArithmeticException if the resulting numerator or denominator
|
||||||
|
* cannot be represented in an <code>int</code>.
|
||||||
|
*/
|
||||||
|
private Fraction addSub(Fraction fraction, boolean isAdd) {
|
||||||
|
if (fraction == null) {
|
||||||
|
throw new IllegalArgumentException("The fraction must not be null");
|
||||||
|
}
|
||||||
|
// zero is identity for addition.
|
||||||
|
if (numerator == 0) {
|
||||||
|
return isAdd ? fraction : fraction.negate();
|
||||||
|
}
|
||||||
|
if (fraction.numerator == 0) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
// if denominators are randomly distributed, d1 will be 1 about 61%
|
||||||
|
// of the time.
|
||||||
|
int d1 = greatestCommonDivisor(denominator, fraction.denominator);
|
||||||
|
if (d1==1) {
|
||||||
|
// result is ( (u*v' +/- u'v) / u'v')
|
||||||
|
int uvp = mulAndCheck(numerator, fraction.denominator);
|
||||||
|
int upv = mulAndCheck(fraction.numerator, denominator);
|
||||||
|
return new Fraction
|
||||||
|
(isAdd ? addAndCheck(uvp, upv) : subAndCheck(uvp, upv),
|
||||||
|
mulPosAndCheck(denominator, fraction.denominator));
|
||||||
|
}
|
||||||
|
// the quantity 't' requires 65 bits of precision; see knuth 4.5.1
|
||||||
|
// exercise 7. we're going to use a BigInteger.
|
||||||
|
// t = u(v'/d1) +/- v(u'/d1)
|
||||||
|
BigInteger uvp = BigInteger.valueOf(numerator)
|
||||||
|
.multiply(BigInteger.valueOf(fraction.denominator/d1));
|
||||||
|
BigInteger upv = BigInteger.valueOf(fraction.numerator)
|
||||||
|
.multiply(BigInteger.valueOf(denominator/d1));
|
||||||
|
BigInteger t = isAdd ? uvp.add(upv) : uvp.subtract(upv);
|
||||||
|
// but d2 doesn't need extra precision because
|
||||||
|
// d2 = gcd(t,d1) = gcd(t mod d1, d1)
|
||||||
|
int tmodd1 = t.mod(BigInteger.valueOf(d1)).intValue();
|
||||||
|
int d2 = (tmodd1==0)?d1:greatestCommonDivisor(tmodd1, d1);
|
||||||
|
|
||||||
|
// result is (t/d2) / (u'/d1)(v'/d2)
|
||||||
|
BigInteger w = t.divide(BigInteger.valueOf(d2));
|
||||||
|
if (w.bitLength() > 31) {
|
||||||
|
throw new ArithmeticException
|
||||||
|
("overflow: numerator too large after multiply");
|
||||||
|
}
|
||||||
|
return new Fraction
|
||||||
|
(w.intValue(),
|
||||||
|
mulPosAndCheck(denominator/d1, fraction.denominator/d2));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Multiplies the value of this fraction by another, returning the
|
||||||
|
* result in reduced form.</p>
|
||||||
*
|
*
|
||||||
* @param fraction the fraction to multiply by, must not be <code>null</code>
|
* @param fraction the fraction to multiply by, must not be <code>null</code>
|
||||||
* @return a <code>Fraction</code> instance with the resulting values
|
* @return a <code>Fraction</code> instance with the resulting values
|
||||||
|
@ -600,18 +770,17 @@ public final class Fraction extends Number implements Serializable, Comparable {
|
||||||
if (numerator == 0 || fraction.numerator == 0) {
|
if (numerator == 0 || fraction.numerator == 0) {
|
||||||
return ZERO;
|
return ZERO;
|
||||||
}
|
}
|
||||||
double numeratorValue = (double) numerator * fraction.numerator;
|
// knuth 4.5.1
|
||||||
double denominatorValue = (double) denominator * fraction.denominator;
|
// make sure we don't overflow unless the result *must* overflow.
|
||||||
if (Math.abs(numeratorValue) > Integer.MAX_VALUE ||
|
int d1 = greatestCommonDivisor(numerator, fraction.denominator);
|
||||||
Math.abs(denominatorValue) > Integer.MAX_VALUE) {
|
int d2 = greatestCommonDivisor(fraction.numerator, denominator);
|
||||||
throw new ArithmeticException("Integer overflow");
|
return getReducedFraction
|
||||||
}
|
(mulAndCheck(numerator/d1, fraction.numerator/d2),
|
||||||
return getReducedFraction((int) numeratorValue, (int) denominatorValue);
|
mulPosAndCheck(denominator/d2, fraction.denominator/d1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Divide the value of this fraction by another, returning the result
|
* <p>Divide the value of this fraction by another.</p>
|
||||||
* in reduced form.</p>
|
|
||||||
*
|
*
|
||||||
* @param fraction the fraction to divide by, must not be <code>null</code>
|
* @param fraction the fraction to divide by, must not be <code>null</code>
|
||||||
* @return a <code>Fraction</code> instance with the resulting values
|
* @return a <code>Fraction</code> instance with the resulting values
|
||||||
|
@ -627,16 +796,7 @@ public final class Fraction extends Number implements Serializable, Comparable {
|
||||||
if (fraction.numerator == 0) {
|
if (fraction.numerator == 0) {
|
||||||
throw new ArithmeticException("The fraction to divide by must not be zero");
|
throw new ArithmeticException("The fraction to divide by must not be zero");
|
||||||
}
|
}
|
||||||
if (numerator == 0) {
|
return multiplyBy(fraction.invert());
|
||||||
return ZERO;
|
|
||||||
}
|
|
||||||
double numeratorValue = (double) numerator * fraction.denominator;
|
|
||||||
double denominatorValue = (double) denominator * fraction.numerator;
|
|
||||||
if (Math.abs(numeratorValue) > Integer.MAX_VALUE ||
|
|
||||||
Math.abs(denominatorValue) > Integer.MAX_VALUE) {
|
|
||||||
throw new ArithmeticException("Integer overflow");
|
|
||||||
}
|
|
||||||
return getReducedFraction((int) numeratorValue, (int) denominatorValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Basics
|
// Basics
|
||||||
|
@ -658,8 +818,8 @@ public final class Fraction extends Number implements Serializable, Comparable {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Fraction other = (Fraction) obj;
|
Fraction other = (Fraction) obj;
|
||||||
return (numerator == other.numerator &&
|
return (getNumerator() == other.getNumerator() &&
|
||||||
denominator == other.denominator);
|
getDenominator() == other.getDenominator());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -669,9 +829,8 @@ public final class Fraction extends Number implements Serializable, Comparable {
|
||||||
*/
|
*/
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
if (hashCode == 0) {
|
if (hashCode == 0) {
|
||||||
hashCode = 17;
|
// hashcode update should be atomic.
|
||||||
hashCode = 37 * hashCode + numerator;
|
hashCode = 37 * (37 * 17 + getNumerator()) + getDenominator();
|
||||||
hashCode = 37 * hashCode + denominator;
|
|
||||||
}
|
}
|
||||||
return hashCode;
|
return hashCode;
|
||||||
}
|
}
|
||||||
|
@ -686,6 +845,9 @@ public final class Fraction extends Number implements Serializable, Comparable {
|
||||||
*/
|
*/
|
||||||
public int compareTo(Object object) {
|
public int compareTo(Object object) {
|
||||||
Fraction other = (Fraction) object;
|
Fraction other = (Fraction) object;
|
||||||
|
if (this==other) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (numerator == other.numerator && denominator == other.denominator) {
|
if (numerator == other.numerator && denominator == other.denominator) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -712,9 +874,9 @@ public final class Fraction extends Number implements Serializable, Comparable {
|
||||||
public String toString() {
|
public String toString() {
|
||||||
if (toString == null) {
|
if (toString == null) {
|
||||||
toString = new StringBuffer(32)
|
toString = new StringBuffer(32)
|
||||||
.append(numerator)
|
.append(getNumerator())
|
||||||
.append('/')
|
.append('/')
|
||||||
.append(denominator).toString();
|
.append(getDenominator()).toString();
|
||||||
}
|
}
|
||||||
return toString;
|
return toString;
|
||||||
}
|
}
|
||||||
|
@ -734,7 +896,11 @@ public final class Fraction extends Number implements Serializable, Comparable {
|
||||||
toProperString = "0";
|
toProperString = "0";
|
||||||
} else if (numerator == denominator) {
|
} else if (numerator == denominator) {
|
||||||
toProperString = "1";
|
toProperString = "1";
|
||||||
} else if (Math.abs(numerator) > denominator) {
|
} else if ((numerator>0?-numerator:numerator) < -denominator) {
|
||||||
|
// note that we do the magnitude comparison test above with
|
||||||
|
// NEGATIVE (not positive) numbers, since negative numbers
|
||||||
|
// have a larger range. otherwise numerator==Integer.MIN_VALUE
|
||||||
|
// is handled incorrectly.
|
||||||
int properNumerator = getProperNumerator();
|
int properNumerator = getProperNumerator();
|
||||||
if (properNumerator == 0) {
|
if (properNumerator == 0) {
|
||||||
toProperString = Integer.toString(getProperWhole());
|
toProperString = Integer.toString(getProperWhole());
|
||||||
|
@ -742,15 +908,14 @@ public final class Fraction extends Number implements Serializable, Comparable {
|
||||||
toProperString = new StringBuffer(32)
|
toProperString = new StringBuffer(32)
|
||||||
.append(getProperWhole()).append(' ')
|
.append(getProperWhole()).append(' ')
|
||||||
.append(properNumerator).append('/')
|
.append(properNumerator).append('/')
|
||||||
.append(denominator).toString();
|
.append(getDenominator()).toString();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
toProperString = new StringBuffer(32)
|
toProperString = new StringBuffer(32)
|
||||||
.append(numerator).append('/')
|
.append(getNumerator()).append('/')
|
||||||
.append(denominator).toString();
|
.append(getDenominator()).toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return toProperString;
|
return toProperString;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,15 +18,21 @@ package org.apache.commons.lang.math;
|
||||||
import junit.framework.Test;
|
import junit.framework.Test;
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
import junit.framework.TestSuite;
|
import junit.framework.TestSuite;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
/**
|
/**
|
||||||
* Test cases for the {@link Fraction} classes.
|
* Test cases for the {@link Fraction} class
|
||||||
*
|
*
|
||||||
* @author Stephen Colebourne
|
* @author Stephen Colebourne
|
||||||
* @version $Id: FractionTest.java,v 1.6 2004/02/18 23:02:38 ggregory Exp $
|
* @author C. Scott Ananian
|
||||||
|
* @version $Id: FractionTest.java,v 1.7 2004/07/11 23:20:17 psteitz Exp $
|
||||||
*/
|
*/
|
||||||
public class FractionTest extends TestCase {
|
public class FractionTest extends TestCase {
|
||||||
|
|
||||||
private static final int SKIP = 53;
|
private static final int SKIP = 500; //53
|
||||||
|
|
||||||
public FractionTest(String name) {
|
public FractionTest(String name) {
|
||||||
super(name);
|
super(name);
|
||||||
|
@ -139,6 +145,16 @@ public class FractionTest extends TestCase {
|
||||||
f = Fraction.getFraction(-3, 0);
|
f = Fraction.getFraction(-3, 0);
|
||||||
fail("expecting ArithmeticException");
|
fail("expecting ArithmeticException");
|
||||||
} catch (ArithmeticException ex) {}
|
} catch (ArithmeticException ex) {}
|
||||||
|
|
||||||
|
// very large: can't represent as unsimplified fraction, although
|
||||||
|
try {
|
||||||
|
f = Fraction.getFraction(4, Integer.MIN_VALUE);
|
||||||
|
fail("expecting ArithmeticException");
|
||||||
|
} catch (ArithmeticException ex) {}
|
||||||
|
try {
|
||||||
|
f = Fraction.getFraction(1, Integer.MIN_VALUE);
|
||||||
|
fail("expecting ArithmeticException");
|
||||||
|
} catch (ArithmeticException ex) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testFactory_int_int_int() {
|
public void testFactory_int_int_int() {
|
||||||
|
@ -223,8 +239,26 @@ public class FractionTest extends TestCase {
|
||||||
f = Fraction.getFraction(-Integer.MAX_VALUE, 1, 2);
|
f = Fraction.getFraction(-Integer.MAX_VALUE, 1, 2);
|
||||||
fail("expecting ArithmeticException");
|
fail("expecting ArithmeticException");
|
||||||
} catch (ArithmeticException ex) {}
|
} catch (ArithmeticException ex) {}
|
||||||
}
|
|
||||||
|
|
||||||
|
// very large
|
||||||
|
f = Fraction.getFraction(-1, 0, Integer.MAX_VALUE);
|
||||||
|
assertEquals(-Integer.MAX_VALUE, f.getNumerator());
|
||||||
|
assertEquals(Integer.MAX_VALUE, f.getDenominator());
|
||||||
|
|
||||||
|
try {
|
||||||
|
// negative denominators not allowed in this constructor.
|
||||||
|
f = Fraction.getFraction(0, 4, Integer.MIN_VALUE);
|
||||||
|
fail("expecting ArithmeticException");
|
||||||
|
} catch (ArithmeticException ex) {}
|
||||||
|
try {
|
||||||
|
f = Fraction.getFraction(1, 1, Integer.MAX_VALUE);
|
||||||
|
fail("expecting ArithmeticException");
|
||||||
|
} catch (ArithmeticException ex) {}
|
||||||
|
try {
|
||||||
|
f = Fraction.getFraction(-1, 2, Integer.MAX_VALUE);
|
||||||
|
fail("expecting ArithmeticException");
|
||||||
|
} catch (ArithmeticException ex) {}
|
||||||
|
}
|
||||||
public void testReducedFactory_int_int() {
|
public void testReducedFactory_int_int() {
|
||||||
Fraction f = null;
|
Fraction f = null;
|
||||||
|
|
||||||
|
@ -296,6 +330,18 @@ public class FractionTest extends TestCase {
|
||||||
f = Fraction.getReducedFraction(121, 22);
|
f = Fraction.getReducedFraction(121, 22);
|
||||||
assertEquals(11, f.getNumerator());
|
assertEquals(11, f.getNumerator());
|
||||||
assertEquals(2, f.getDenominator());
|
assertEquals(2, f.getDenominator());
|
||||||
|
|
||||||
|
// Extreme values
|
||||||
|
// OK, can reduce before negating
|
||||||
|
f = Fraction.getReducedFraction(-2, Integer.MIN_VALUE);
|
||||||
|
assertEquals(1, f.getNumerator());
|
||||||
|
assertEquals(-(Integer.MIN_VALUE / 2), f.getDenominator());
|
||||||
|
|
||||||
|
// Can't reduce, negation will throw
|
||||||
|
try {
|
||||||
|
f = Fraction.getReducedFraction(-7, Integer.MIN_VALUE);
|
||||||
|
fail("Expecting ArithmeticException");
|
||||||
|
} catch (ArithmeticException ex) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testFactory_double() {
|
public void testFactory_double() {
|
||||||
|
@ -391,7 +437,7 @@ public class FractionTest extends TestCase {
|
||||||
public void testFactory_String() {
|
public void testFactory_String() {
|
||||||
try {
|
try {
|
||||||
Fraction.getFraction(null);
|
Fraction.getFraction(null);
|
||||||
fail("expecting ArithmeticException");
|
fail("expecting IllegalArgumentException");
|
||||||
} catch (IllegalArgumentException ex) {}
|
} catch (IllegalArgumentException ex) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,6 +463,7 @@ public class FractionTest extends TestCase {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
f = Fraction.getFraction("2.3R");
|
f = Fraction.getFraction("2.3R");
|
||||||
|
fail("Expecting NumberFormatException");
|
||||||
} catch (NumberFormatException ex) {}
|
} catch (NumberFormatException ex) {}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -426,6 +473,7 @@ public class FractionTest extends TestCase {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
f = Fraction.getFraction(".");
|
f = Fraction.getFraction(".");
|
||||||
|
fail("Expecting NumberFormatException");
|
||||||
} catch (NumberFormatException ex) {}
|
} catch (NumberFormatException ex) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,34 +496,42 @@ public class FractionTest extends TestCase {
|
||||||
assertEquals(6, f.getNumerator());
|
assertEquals(6, f.getNumerator());
|
||||||
assertEquals(4, f.getDenominator());
|
assertEquals(4, f.getDenominator());
|
||||||
|
|
||||||
|
f = Fraction.getFraction("-7 1/2");
|
||||||
|
assertEquals(-15, f.getNumerator());
|
||||||
|
assertEquals(2, f.getDenominator());
|
||||||
|
|
||||||
|
f = Fraction.getFraction("-1 2/4");
|
||||||
|
assertEquals(-6, f.getNumerator());
|
||||||
|
assertEquals(4, f.getDenominator());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
f = Fraction.getFraction("2 3");
|
f = Fraction.getFraction("2 3");
|
||||||
fail("expecting NumberFomatException");
|
fail("expecting NumberFormatException");
|
||||||
} catch (NumberFormatException ex) {}
|
} catch (NumberFormatException ex) {}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
f = Fraction.getFraction("a 3");
|
f = Fraction.getFraction("a 3");
|
||||||
fail("expecting NumberFomatException");
|
fail("expecting NumberFormatException");
|
||||||
} catch (NumberFormatException ex) {}
|
} catch (NumberFormatException ex) {}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
f = Fraction.getFraction("2 b/4");
|
f = Fraction.getFraction("2 b/4");
|
||||||
fail("expecting NumberFomatException");
|
fail("expecting NumberFormatException");
|
||||||
} catch (NumberFormatException ex) {}
|
} catch (NumberFormatException ex) {}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
f = Fraction.getFraction("2 ");
|
f = Fraction.getFraction("2 ");
|
||||||
fail("expecting NumberFomatException");
|
fail("expecting NumberFormatException");
|
||||||
} catch (NumberFormatException ex) {}
|
} catch (NumberFormatException ex) {}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
f = Fraction.getFraction(" 3");
|
f = Fraction.getFraction(" 3");
|
||||||
fail("expecting NumberFomatException");
|
fail("expecting NumberFormatException");
|
||||||
} catch (NumberFormatException ex) {}
|
} catch (NumberFormatException ex) {}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
f = Fraction.getFraction(" ");
|
f = Fraction.getFraction(" ");
|
||||||
fail("expecting NumberFomatException");
|
fail("expecting NumberFormatException");
|
||||||
} catch (NumberFormatException ex) {}
|
} catch (NumberFormatException ex) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,22 +564,22 @@ public class FractionTest extends TestCase {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
f = Fraction.getFraction("2/d");
|
f = Fraction.getFraction("2/d");
|
||||||
fail("expecting NumberFomatException");
|
fail("expecting NumberFormatException");
|
||||||
} catch (NumberFormatException ex) {}
|
} catch (NumberFormatException ex) {}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
f = Fraction.getFraction("2e/3");
|
f = Fraction.getFraction("2e/3");
|
||||||
fail("expecting NumberFomatException");
|
fail("expecting NumberFormatException");
|
||||||
} catch (NumberFormatException ex) {}
|
} catch (NumberFormatException ex) {}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
f = Fraction.getFraction("2/");
|
f = Fraction.getFraction("2/");
|
||||||
fail("expecting NumberFomatException");
|
fail("expecting NumberFormatException");
|
||||||
} catch (NumberFormatException ex) {}
|
} catch (NumberFormatException ex) {}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
f = Fraction.getFraction("/");
|
f = Fraction.getFraction("/");
|
||||||
fail("expecting NumberFomatException");
|
fail("expecting NumberFormatException");
|
||||||
} catch (NumberFormatException ex) {}
|
} catch (NumberFormatException ex) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -541,6 +597,12 @@ public class FractionTest extends TestCase {
|
||||||
assertEquals(-3, f.getProperWhole());
|
assertEquals(-3, f.getProperWhole());
|
||||||
assertEquals(5, f.getProperNumerator());
|
assertEquals(5, f.getProperNumerator());
|
||||||
assertEquals(6, f.getDenominator());
|
assertEquals(6, f.getDenominator());
|
||||||
|
|
||||||
|
f = Fraction.getFraction(Integer.MIN_VALUE, 0, 1);
|
||||||
|
assertEquals(Integer.MIN_VALUE, f.getNumerator());
|
||||||
|
assertEquals(Integer.MIN_VALUE, f.getProperWhole());
|
||||||
|
assertEquals(0, f.getProperNumerator());
|
||||||
|
assertEquals(1, f.getDenominator());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testConversions() {
|
public void testConversions() {
|
||||||
|
@ -560,6 +622,11 @@ public class FractionTest extends TestCase {
|
||||||
f = f.reduce();
|
f = f.reduce();
|
||||||
assertEquals(2, f.getNumerator());
|
assertEquals(2, f.getNumerator());
|
||||||
assertEquals(3, f.getDenominator());
|
assertEquals(3, f.getDenominator());
|
||||||
|
|
||||||
|
f = Fraction.getFraction(2, 3);
|
||||||
|
f = f.reduce();
|
||||||
|
assertEquals(2, f.getNumerator());
|
||||||
|
assertEquals(3, f.getDenominator());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testInvert() {
|
public void testInvert() {
|
||||||
|
@ -575,10 +642,28 @@ public class FractionTest extends TestCase {
|
||||||
assertEquals(3, f.getNumerator());
|
assertEquals(3, f.getNumerator());
|
||||||
assertEquals(4, f.getDenominator());
|
assertEquals(4, f.getDenominator());
|
||||||
|
|
||||||
|
f = Fraction.getFraction(-15, 47);
|
||||||
|
f = f.invert();
|
||||||
|
assertEquals(-47, f.getNumerator());
|
||||||
|
assertEquals(15, f.getDenominator());
|
||||||
|
|
||||||
f = Fraction.getFraction(0, 3);
|
f = Fraction.getFraction(0, 3);
|
||||||
try {
|
try {
|
||||||
f = f.invert();
|
f = f.invert();
|
||||||
|
fail("expecting ArithmeticException");
|
||||||
} catch (ArithmeticException ex) {}
|
} catch (ArithmeticException ex) {}
|
||||||
|
|
||||||
|
// large values
|
||||||
|
f = Fraction.getFraction(Integer.MIN_VALUE, 1);
|
||||||
|
try {
|
||||||
|
f = f.invert();
|
||||||
|
fail("expecting ArithmeticException");
|
||||||
|
} catch (ArithmeticException ex) {}
|
||||||
|
|
||||||
|
f = Fraction.getFraction(Integer.MAX_VALUE, 1);
|
||||||
|
f = f.invert();
|
||||||
|
assertEquals(1, f.getNumerator());
|
||||||
|
assertEquals(Integer.MAX_VALUE, f.getDenominator());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testNegate() {
|
public void testNegate() {
|
||||||
|
@ -593,6 +678,18 @@ public class FractionTest extends TestCase {
|
||||||
f = f.negate();
|
f = f.negate();
|
||||||
assertEquals(50, f.getNumerator());
|
assertEquals(50, f.getNumerator());
|
||||||
assertEquals(75, f.getDenominator());
|
assertEquals(75, f.getDenominator());
|
||||||
|
|
||||||
|
// large values
|
||||||
|
f = Fraction.getFraction(Integer.MAX_VALUE-1, Integer.MAX_VALUE);
|
||||||
|
f = f.negate();
|
||||||
|
assertEquals(Integer.MIN_VALUE+2, f.getNumerator());
|
||||||
|
assertEquals(Integer.MAX_VALUE, f.getDenominator());
|
||||||
|
|
||||||
|
f = Fraction.getFraction(Integer.MIN_VALUE, 1);
|
||||||
|
try {
|
||||||
|
f = f.negate();
|
||||||
|
fail("expecting ArithmeticException");
|
||||||
|
} catch (ArithmeticException ex) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testAbs() {
|
public void testAbs() {
|
||||||
|
@ -607,6 +704,22 @@ public class FractionTest extends TestCase {
|
||||||
f = f.abs();
|
f = f.abs();
|
||||||
assertEquals(50, f.getNumerator());
|
assertEquals(50, f.getNumerator());
|
||||||
assertEquals(75, f.getDenominator());
|
assertEquals(75, f.getDenominator());
|
||||||
|
|
||||||
|
f = Fraction.getFraction(Integer.MAX_VALUE, 1);
|
||||||
|
f = f.abs();
|
||||||
|
assertEquals(Integer.MAX_VALUE, f.getNumerator());
|
||||||
|
assertEquals(1, f.getDenominator());
|
||||||
|
|
||||||
|
f = Fraction.getFraction(Integer.MAX_VALUE, -1);
|
||||||
|
f = f.abs();
|
||||||
|
assertEquals(Integer.MAX_VALUE, f.getNumerator());
|
||||||
|
assertEquals(1, f.getDenominator());
|
||||||
|
|
||||||
|
f = Fraction.getFraction(Integer.MIN_VALUE, 1);
|
||||||
|
try {
|
||||||
|
f = f.abs();
|
||||||
|
fail("expecting ArithmeticException");
|
||||||
|
} catch (ArithmeticException ex) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPow() {
|
public void testPow() {
|
||||||
|
@ -617,6 +730,7 @@ public class FractionTest extends TestCase {
|
||||||
|
|
||||||
f = Fraction.getFraction(3, 5);
|
f = Fraction.getFraction(3, 5);
|
||||||
assertSame(f, f.pow(1));
|
assertSame(f, f.pow(1));
|
||||||
|
assertEquals(f, f.pow(1));
|
||||||
|
|
||||||
f = Fraction.getFraction(3, 5);
|
f = Fraction.getFraction(3, 5);
|
||||||
f = f.pow(2);
|
f = f.pow(2);
|
||||||
|
@ -638,7 +752,82 @@ public class FractionTest extends TestCase {
|
||||||
assertEquals(25, f.getNumerator());
|
assertEquals(25, f.getNumerator());
|
||||||
assertEquals(9, f.getDenominator());
|
assertEquals(9, f.getDenominator());
|
||||||
|
|
||||||
f = Fraction.getFraction(Integer.MAX_VALUE);
|
// check unreduced fractions stay that way.
|
||||||
|
f = Fraction.getFraction(6, 10);
|
||||||
|
assertEquals(Fraction.ONE, f.pow(0));
|
||||||
|
|
||||||
|
f = Fraction.getFraction(6, 10);
|
||||||
|
assertEquals(f, f.pow(1));
|
||||||
|
assertFalse(f.pow(1).equals(Fraction.getFraction(3,5)));
|
||||||
|
|
||||||
|
f = Fraction.getFraction(6, 10);
|
||||||
|
f = f.pow(2);
|
||||||
|
assertEquals(9, f.getNumerator());
|
||||||
|
assertEquals(25, f.getDenominator());
|
||||||
|
|
||||||
|
f = Fraction.getFraction(6, 10);
|
||||||
|
f = f.pow(3);
|
||||||
|
assertEquals(27, f.getNumerator());
|
||||||
|
assertEquals(125, f.getDenominator());
|
||||||
|
|
||||||
|
f = Fraction.getFraction(6, 10);
|
||||||
|
f = f.pow(-1);
|
||||||
|
assertEquals(10, f.getNumerator());
|
||||||
|
assertEquals(6, f.getDenominator());
|
||||||
|
|
||||||
|
f = Fraction.getFraction(6, 10);
|
||||||
|
f = f.pow(-2);
|
||||||
|
assertEquals(25, f.getNumerator());
|
||||||
|
assertEquals(9, f.getDenominator());
|
||||||
|
|
||||||
|
// zero to any positive power is still zero.
|
||||||
|
f = Fraction.getFraction(0, 1231);
|
||||||
|
f = f.pow(1);
|
||||||
|
assertTrue(0==f.compareTo(Fraction.ZERO));
|
||||||
|
assertEquals(0, f.getNumerator());
|
||||||
|
assertEquals(1231, f.getDenominator());
|
||||||
|
f = f.pow(2);
|
||||||
|
assertTrue(0==f.compareTo(Fraction.ZERO));
|
||||||
|
assertEquals(0, f.getNumerator());
|
||||||
|
assertEquals(1, f.getDenominator());
|
||||||
|
|
||||||
|
// zero to negative powers should throw an exception
|
||||||
|
try {
|
||||||
|
f = f.pow(-1);
|
||||||
|
fail("expecting ArithmeticException");
|
||||||
|
} catch (ArithmeticException ex) {}
|
||||||
|
try {
|
||||||
|
f = f.pow(Integer.MIN_VALUE);
|
||||||
|
fail("expecting ArithmeticException");
|
||||||
|
} catch (ArithmeticException ex) {}
|
||||||
|
|
||||||
|
// one to any power is still one.
|
||||||
|
f = Fraction.getFraction(1, 1);
|
||||||
|
f = f.pow(0);
|
||||||
|
assertEquals(f, Fraction.ONE);
|
||||||
|
f = f.pow(1);
|
||||||
|
assertEquals(f, Fraction.ONE);
|
||||||
|
f = f.pow(-1);
|
||||||
|
assertEquals(f, Fraction.ONE);
|
||||||
|
f = f.pow(Integer.MAX_VALUE);
|
||||||
|
assertEquals(f, Fraction.ONE);
|
||||||
|
f = f.pow(Integer.MIN_VALUE);
|
||||||
|
assertEquals(f, Fraction.ONE);
|
||||||
|
|
||||||
|
f = Fraction.getFraction(Integer.MAX_VALUE, 1);
|
||||||
|
try {
|
||||||
|
f = f.pow(2);
|
||||||
|
fail("expecting ArithmeticException");
|
||||||
|
} catch (ArithmeticException ex) {}
|
||||||
|
|
||||||
|
// Numerator growing too negative during the pow operation.
|
||||||
|
f = Fraction.getFraction(Integer.MIN_VALUE, 1);
|
||||||
|
try {
|
||||||
|
f = f.pow(3);
|
||||||
|
fail("expecting ArithmeticException");
|
||||||
|
} catch (ArithmeticException ex) {}
|
||||||
|
|
||||||
|
f = Fraction.getFraction(65536, 1);
|
||||||
try {
|
try {
|
||||||
f = f.pow(2);
|
f = f.pow(2);
|
||||||
fail("expecting ArithmeticException");
|
fail("expecting ArithmeticException");
|
||||||
|
@ -699,11 +888,31 @@ public class FractionTest extends TestCase {
|
||||||
f = f2.add(f1);
|
f = f2.add(f1);
|
||||||
assertSame(f2, f);
|
assertSame(f2, f);
|
||||||
|
|
||||||
|
f1 = Fraction.getFraction(-1, 13*13*2*2);
|
||||||
|
f2 = Fraction.getFraction(-2, 13*17*2);
|
||||||
|
f = f1.add(f2);
|
||||||
|
assertEquals(13*13*17*2*2, f.getDenominator());
|
||||||
|
assertEquals(-17 - 2*13*2, f.getNumerator());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
f.add(null);
|
f.add(null);
|
||||||
fail("expecting IllegalArgumentException");
|
fail("expecting IllegalArgumentException");
|
||||||
} catch (IllegalArgumentException ex) {}
|
} catch (IllegalArgumentException ex) {}
|
||||||
|
|
||||||
|
// if this fraction is added naively, it will overflow.
|
||||||
|
// check that it doesn't.
|
||||||
|
f1 = Fraction.getFraction(1,32768*3);
|
||||||
|
f2 = Fraction.getFraction(1,59049);
|
||||||
|
f = f1.add(f2);
|
||||||
|
assertEquals(52451, f.getNumerator());
|
||||||
|
assertEquals(1934917632, f.getDenominator());
|
||||||
|
|
||||||
|
f1 = Fraction.getFraction(Integer.MIN_VALUE, 3);
|
||||||
|
f2 = Fraction.ONE_THIRD;
|
||||||
|
f = f1.add(f2);
|
||||||
|
assertEquals(Integer.MIN_VALUE+1, f.getNumerator());
|
||||||
|
assertEquals(3, f.getDenominator());
|
||||||
|
|
||||||
f1 = Fraction.getFraction(Integer.MAX_VALUE - 1, 1);
|
f1 = Fraction.getFraction(Integer.MAX_VALUE - 1, 1);
|
||||||
f2 = Fraction.ONE;
|
f2 = Fraction.ONE;
|
||||||
f = f1.add(f2);
|
f = f1.add(f2);
|
||||||
|
@ -715,12 +924,32 @@ public class FractionTest extends TestCase {
|
||||||
fail("expecting ArithmeticException but got: " + f.toString());
|
fail("expecting ArithmeticException but got: " + f.toString());
|
||||||
} catch (ArithmeticException ex) {}
|
} catch (ArithmeticException ex) {}
|
||||||
|
|
||||||
|
// denominator should not be a multiple of 2 or 3 to trigger overflow
|
||||||
|
f1 = Fraction.getFraction(Integer.MIN_VALUE, 5);
|
||||||
|
f2 = Fraction.getFraction(-1,5);
|
||||||
|
try {
|
||||||
|
f = f1.add(f2); // should overflow
|
||||||
|
fail("expecting ArithmeticException but got: " + f.toString());
|
||||||
|
} catch (ArithmeticException ex) {}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
f= Fraction.getFraction(-Integer.MAX_VALUE, 1);
|
f= Fraction.getFraction(-Integer.MAX_VALUE, 1);
|
||||||
f = f.add(f);
|
f = f.add(f);
|
||||||
fail("expecting ArithmeticException");
|
fail("expecting ArithmeticException");
|
||||||
} catch (ArithmeticException ex) {}
|
} catch (ArithmeticException ex) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
f= Fraction.getFraction(-Integer.MAX_VALUE, 1);
|
||||||
|
f = f.add(f);
|
||||||
|
fail("expecting ArithmeticException");
|
||||||
|
} catch (ArithmeticException ex) {}
|
||||||
|
|
||||||
|
f1 = Fraction.getFraction(3,327680);
|
||||||
|
f2 = Fraction.getFraction(2,59049);
|
||||||
|
try {
|
||||||
|
f = f1.add(f2); // should overflow
|
||||||
|
fail("expecting ArithmeticException but got: " + f.toString());
|
||||||
|
} catch (ArithmeticException ex) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSubtract() {
|
public void testSubtract() {
|
||||||
|
@ -780,6 +1009,26 @@ public class FractionTest extends TestCase {
|
||||||
fail("expecting IllegalArgumentException");
|
fail("expecting IllegalArgumentException");
|
||||||
} catch (IllegalArgumentException ex) {}
|
} catch (IllegalArgumentException ex) {}
|
||||||
|
|
||||||
|
// if this fraction is subtracted naively, it will overflow.
|
||||||
|
// check that it doesn't.
|
||||||
|
f1 = Fraction.getFraction(1,32768*3);
|
||||||
|
f2 = Fraction.getFraction(1,59049);
|
||||||
|
f = f1.subtract(f2);
|
||||||
|
assertEquals(-13085, f.getNumerator());
|
||||||
|
assertEquals(1934917632, f.getDenominator());
|
||||||
|
|
||||||
|
f1 = Fraction.getFraction(Integer.MIN_VALUE, 3);
|
||||||
|
f2 = Fraction.ONE_THIRD.negate();
|
||||||
|
f = f1.subtract(f2);
|
||||||
|
assertEquals(Integer.MIN_VALUE+1, f.getNumerator());
|
||||||
|
assertEquals(3, f.getDenominator());
|
||||||
|
|
||||||
|
f1 = Fraction.getFraction(Integer.MAX_VALUE, 1);
|
||||||
|
f2 = Fraction.ONE;
|
||||||
|
f = f1.subtract(f2);
|
||||||
|
assertEquals(Integer.MAX_VALUE-1, f.getNumerator());
|
||||||
|
assertEquals(1, f.getDenominator());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
f1 = Fraction.getFraction(1, Integer.MAX_VALUE);
|
f1 = Fraction.getFraction(1, Integer.MAX_VALUE);
|
||||||
f2 = Fraction.getFraction(1, Integer.MAX_VALUE - 1);
|
f2 = Fraction.getFraction(1, Integer.MAX_VALUE - 1);
|
||||||
|
@ -787,6 +1036,32 @@ public class FractionTest extends TestCase {
|
||||||
fail("expecting ArithmeticException"); //should overflow
|
fail("expecting ArithmeticException"); //should overflow
|
||||||
} catch (ArithmeticException ex) {}
|
} catch (ArithmeticException ex) {}
|
||||||
|
|
||||||
|
// denominator should not be a multiple of 2 or 3 to trigger overflow
|
||||||
|
f1 = Fraction.getFraction(Integer.MIN_VALUE, 5);
|
||||||
|
f2 = Fraction.getFraction(1,5);
|
||||||
|
try {
|
||||||
|
f = f1.subtract(f2); // should overflow
|
||||||
|
fail("expecting ArithmeticException but got: " + f.toString());
|
||||||
|
} catch (ArithmeticException ex) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
f= Fraction.getFraction(Integer.MIN_VALUE, 1);
|
||||||
|
f = f.subtract(Fraction.ONE);
|
||||||
|
fail("expecting ArithmeticException");
|
||||||
|
} catch (ArithmeticException ex) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
f= Fraction.getFraction(Integer.MAX_VALUE, 1);
|
||||||
|
f = f.subtract(Fraction.ONE.negate());
|
||||||
|
fail("expecting ArithmeticException");
|
||||||
|
} catch (ArithmeticException ex) {}
|
||||||
|
|
||||||
|
f1 = Fraction.getFraction(3,327680);
|
||||||
|
f2 = Fraction.getFraction(2,59049);
|
||||||
|
try {
|
||||||
|
f = f1.subtract(f2); // should overflow
|
||||||
|
fail("expecting ArithmeticException but got: " + f.toString());
|
||||||
|
} catch (ArithmeticException ex) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testMultiply() {
|
public void testMultiply() {
|
||||||
|
@ -800,6 +1075,15 @@ public class FractionTest extends TestCase {
|
||||||
assertEquals(6, f.getNumerator());
|
assertEquals(6, f.getNumerator());
|
||||||
assertEquals(25, f.getDenominator());
|
assertEquals(25, f.getDenominator());
|
||||||
|
|
||||||
|
f1 = Fraction.getFraction(6, 10);
|
||||||
|
f2 = Fraction.getFraction(6, 10);
|
||||||
|
f = f1.multiplyBy(f2);
|
||||||
|
assertEquals(9, f.getNumerator());
|
||||||
|
assertEquals(25, f.getDenominator());
|
||||||
|
f = f.multiplyBy(f2);
|
||||||
|
assertEquals(27, f.getNumerator());
|
||||||
|
assertEquals(125, f.getDenominator());
|
||||||
|
|
||||||
f1 = Fraction.getFraction(3, 5);
|
f1 = Fraction.getFraction(3, 5);
|
||||||
f2 = Fraction.getFraction(-2, 5);
|
f2 = Fraction.getFraction(-2, 5);
|
||||||
f = f1.multiplyBy(f2);
|
f = f1.multiplyBy(f2);
|
||||||
|
@ -812,6 +1096,7 @@ public class FractionTest extends TestCase {
|
||||||
assertEquals(6, f.getNumerator());
|
assertEquals(6, f.getNumerator());
|
||||||
assertEquals(25, f.getDenominator());
|
assertEquals(25, f.getDenominator());
|
||||||
|
|
||||||
|
|
||||||
f1 = Fraction.getFraction(0, 5);
|
f1 = Fraction.getFraction(0, 5);
|
||||||
f2 = Fraction.getFraction(2, 7);
|
f2 = Fraction.getFraction(2, 7);
|
||||||
f = f1.multiplyBy(f2);
|
f = f1.multiplyBy(f2);
|
||||||
|
@ -823,6 +1108,12 @@ public class FractionTest extends TestCase {
|
||||||
assertEquals(2, f.getNumerator());
|
assertEquals(2, f.getNumerator());
|
||||||
assertEquals(7, f.getDenominator());
|
assertEquals(7, f.getDenominator());
|
||||||
|
|
||||||
|
f1 = Fraction.getFraction(Integer.MAX_VALUE, 1);
|
||||||
|
f2 = Fraction.getFraction(Integer.MIN_VALUE, Integer.MAX_VALUE);
|
||||||
|
f = f1.multiplyBy(f2);
|
||||||
|
assertEquals(Integer.MIN_VALUE, f.getNumerator());
|
||||||
|
assertEquals(1, f.getDenominator());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
f.multiplyBy(null);
|
f.multiplyBy(null);
|
||||||
fail("expecting IllegalArgumentException");
|
fail("expecting IllegalArgumentException");
|
||||||
|
@ -875,6 +1166,12 @@ public class FractionTest extends TestCase {
|
||||||
assertEquals(1, f.getNumerator());
|
assertEquals(1, f.getNumerator());
|
||||||
assertEquals(1, f.getDenominator());
|
assertEquals(1, f.getDenominator());
|
||||||
|
|
||||||
|
f1 = Fraction.getFraction(Integer.MIN_VALUE, Integer.MAX_VALUE);
|
||||||
|
f2 = Fraction.getFraction(1, Integer.MAX_VALUE);
|
||||||
|
f = f1.divideBy(f2);
|
||||||
|
assertEquals(Integer.MIN_VALUE, f.getNumerator());
|
||||||
|
assertEquals(1, f.getDenominator());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
f.divideBy(null);
|
f.divideBy(null);
|
||||||
fail("IllegalArgumentException");
|
fail("IllegalArgumentException");
|
||||||
|
@ -932,6 +1229,7 @@ public class FractionTest extends TestCase {
|
||||||
Fraction f2 = null;
|
Fraction f2 = null;
|
||||||
|
|
||||||
f1 = Fraction.getFraction(3, 5);
|
f1 = Fraction.getFraction(3, 5);
|
||||||
|
assertTrue(f1.compareTo(f1) == 0);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
f1.compareTo(null);
|
f1.compareTo(null);
|
||||||
|
@ -945,15 +1243,24 @@ public class FractionTest extends TestCase {
|
||||||
|
|
||||||
f2 = Fraction.getFraction(2, 5);
|
f2 = Fraction.getFraction(2, 5);
|
||||||
assertTrue(f1.compareTo(f2) > 0);
|
assertTrue(f1.compareTo(f2) > 0);
|
||||||
|
assertTrue(f2.compareTo(f2) == 0);
|
||||||
|
|
||||||
f2 = Fraction.getFraction(4, 5);
|
f2 = Fraction.getFraction(4, 5);
|
||||||
assertTrue(f1.compareTo(f2) < 0);
|
assertTrue(f1.compareTo(f2) < 0);
|
||||||
|
assertTrue(f2.compareTo(f2) == 0);
|
||||||
|
|
||||||
f2 = Fraction.getFraction(3, 5);
|
f2 = Fraction.getFraction(3, 5);
|
||||||
assertTrue(f1.compareTo(f2) == 0);
|
assertTrue(f1.compareTo(f2) == 0);
|
||||||
|
assertTrue(f2.compareTo(f2) == 0);
|
||||||
|
|
||||||
f2 = Fraction.getFraction(6, 10);
|
f2 = Fraction.getFraction(6, 10);
|
||||||
assertTrue(f1.compareTo(f2) == 0);
|
assertTrue(f1.compareTo(f2) == 0);
|
||||||
|
assertTrue(f2.compareTo(f2) == 0);
|
||||||
|
|
||||||
|
f2 = Fraction.getFraction(-1, 1, Integer.MAX_VALUE);
|
||||||
|
assertTrue(f1.compareTo(f2) > 0);
|
||||||
|
assertTrue(f2.compareTo(f2) == 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testToString() {
|
public void testToString() {
|
||||||
|
@ -975,6 +1282,12 @@ public class FractionTest extends TestCase {
|
||||||
|
|
||||||
f = Fraction.getFraction(2, 2);
|
f = Fraction.getFraction(2, 2);
|
||||||
assertEquals("2/2", f.toString());
|
assertEquals("2/2", f.toString());
|
||||||
|
|
||||||
|
f = Fraction.getFraction(Integer.MIN_VALUE, 0, 1);
|
||||||
|
assertEquals("-2147483648/1", f.toString());
|
||||||
|
|
||||||
|
f = Fraction.getFraction(-1, 1, Integer.MAX_VALUE);
|
||||||
|
assertEquals("-2147483648/2147483647", f.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testToProperString() {
|
public void testToProperString() {
|
||||||
|
@ -1002,6 +1315,11 @@ public class FractionTest extends TestCase {
|
||||||
|
|
||||||
f = Fraction.getFraction(-7, 5);
|
f = Fraction.getFraction(-7, 5);
|
||||||
assertEquals("-1 2/5", f.toProperString());
|
assertEquals("-1 2/5", f.toProperString());
|
||||||
}
|
|
||||||
|
|
||||||
|
f = Fraction.getFraction(Integer.MIN_VALUE, 0, 1);
|
||||||
|
assertEquals("-2147483648", f.toProperString());
|
||||||
|
|
||||||
|
f = Fraction.getFraction(-1, 1, Integer.MAX_VALUE);
|
||||||
|
assertEquals("-1 1/2147483647", f.toProperString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue