Code Review
Anywho, I've wanted (for a while, yet) a BigFraction class. So I made one. I'd like to get comments on it, though, so:
/* Author: Adeodatus
*
*
*/
/**package java.math;**/
import java.math.*;
publicclass BigFractionextends Numberimplements Comparable<BigFraction>
{
publicstaticfinal BigFraction ZERO =new BigFraction(BigInteger.ZERO, BigInteger.ONE),
ONE =new BigFraction(BigInteger.ONE, BigInteger.ONE),
TEN =new BigFraction(BigInteger.TEN, BigInteger.ONE);
private/*final*/ BigInteger n,//numerator
d;//denominator
privatefinal BigDecimal m;
privatestaticfinal BigInteger TWO = BigInteger.valueOf(2);
privatestaticfinal java.security.SecureRandom rng;
static
{
rng =new java.security.SecureRandom();
rng.setSeed(BigInteger.valueOf(System.currentTimeMillis() * 1000000/*+ System.nanoTime()*/).pow(65).toByteArray());
}
public BigFraction(char[] in)
{
this(in, 0, in.length);
}
public BigFraction(char[] in,int offset,int len)
{
this(new String(in).substring(offset, len));
}
public BigFraction(String val)
{
int index = val.indexOf('/');
if(index < 0)
thrownew ArithmeticException("Constructor must be passed a fraction.");
n =new BigInteger(val.substring(0, index));
d =new BigInteger(val.substring(index + 1, val.length()));
m =new BigDecimal(n).divide(new BigDecimal(d), MathContext.DECIMAL64);
}
public BigFraction(String numerator, String denominator)
{
this(new BigInteger(numerator),new BigInteger(denominator));
}
public BigFraction(BigDecimal bd)
{
int scale = bd.scale();
if(scale >= 0)
{
n = bd.unscaledValue().multiply(BigInteger.TEN.pow(scale));
d = BigInteger.ONE;
}
else
{
n = bd.unscaledValue();
d = BigInteger.TEN.pow(-scale);
}
m = bd;
}
public BigFraction(BigFraction val)
{
n = val.n;
d = val.d;
m = val.m;
}
public BigFraction(BigInteger numerator)
{
this(numerator, BigInteger.ONE);
}
public BigFraction(byte[] numerator,byte[] denominator)
{
this(new BigInteger(numerator),new BigInteger(denominator));
}
public BigFraction(BigInteger numerator, BigInteger denominator)
{
if(BigInteger.ZERO.equals(denominator))
thrownew ArithmeticException("Division by Zero");
n = numerator;
d = denominator;
m =new BigDecimal(n).divide(new BigDecimal(d), MathContext.DECIMAL128);
}
public BigFraction abs()
{
if(n.signum() >= 0 && d.signum() == 1)
returnthis;
returnnew BigFraction(n.abs(), d.abs());
}
public BigFraction add(BigFraction augend)
{
returnnew BigFraction(n.multiply(augend.d).add(augend.n.multiply(d)), d.multiply(augend.d)).simp();
}
publicbyte byteValueExact()
{
return m.byteValueExact();
}
publicbyte byteValue()
{
return m.byteValue();
}
publicint compareTo(BigFraction val)
{
ints = signum(),
vals = val.signum();
return s == vals ? this.subtract(val).signum() : (s > vals ? 1 : -1);
}
public BigInteger denominator()
{
return d;
}
public BigFraction divide(BigFraction divisor)
{
returnnew BigFraction(n.multiply(divisor.d), d.multiply(divisor.n));
}
public BigFraction[] divideAndRemainder(BigFraction divisor)
{
BigFraction[] ans =new BigFraction[2];
ans[0] = divideToIntegralValue(divisor);
ans[1] = subtract(divisor.multiply(ans[0]));
return ans;
}
public BigFraction divideToIntegralValue(BigFraction divisor)
{
returnnew BigFraction(n.divide(d), BigInteger.ONE);
}
publicdouble doubleValue()
{
return m.doubleValue();
}
publicboolean equals(Object o)
{
return oinstanceof BigFraction ? equals((BigFraction) o) :false;
}
publicboolean equals(BigFraction val)
{
if(this == val)
returntrue;
BigFraction a = this.simplify(),
b = val.simplify();
return a.d.equals(b.d) && a.n.equals(b.n);
}
publicfloat floatValue()
{
return m.floatValue();
}
publicint hashCode()
{
return n.hashCode()+d.hashCode();
}
publicint intValueExact()
{
return m.intValueExact();
}
publicint intValue()
{
return m.intValue();
}
public BigFraction inverse()
{
returnnew BigFraction(d, n);
}
publicboolean isSimplified()
{
return (d.signum() == 0) && n.gcd(d).equals(BigInteger.ONE);
}
publiclong longValueExact()
{
return m.longValueExact();
}
publiclong longValue()
{
return m.longValue();
}
public BigFraction max(BigFraction val)
{
return compareTo(val) >= 0 ?this : val;
}
public BigFraction min(BigFraction val)
{
return compareTo(val) <= 0 ?this : val;
}
public BigFraction mod(BigFraction m)
{
return remainder(m).abs();
}
public BigFraction multiply(BigFraction multiplicand)
{
returnnew BigFraction(n.multiply(multiplicand.n), d.multiply(multiplicand.d));
}
public BigFraction negate()
{
returnnew BigFraction(n.negate(), d);
}
public BigInteger numerator()
{
return n;
}
public BigFraction plus()
{
returnthis;
}
public BigFraction pow(int power)
{
BigInteger n = this.n,
d = this.d;
if(power < 0)
{
power = -power;
n = this.d;
d = this.n;
}
returnnew BigFraction(n.pow(power), d.pow(power));
}
publicstatic BigFraction random()
{
return random(128, rng);
}
publicstatic BigFraction random(int bits)
{
return random(bits, rng);
}
publicstatic BigFraction random(int bits, java.util.Random rng)
{
returnnew BigFraction(new BigInteger(bits, rng), TWO.pow(bits));
}
public BigFraction remainder(BigFraction divisor)
{
return subtract(divisor.multiply(divideToIntegralValue(divisor)));
}
publicshort shortValueExact()
{
return m.shortValueExact();
}
publicshort shortValue()
{
return m.shortValue();
}
publicint signum()
{
return m.signum();
}
protected BigFraction simp()
{//helper method: Used to return simplified fractions from other methods
BigInteger gcd = n.gcd(d);
if(d.signum() == 1)
{
if(!gcd.equals(BigInteger.ONE))
{
n = n.divide(gcd);
d = d.divide(gcd);
}
}
else
{
if(gcd.equals(BigInteger.ONE))
{
n = n.negate();
d = d.negate();
}
else
{
n = n.divide(gcd).negate();
d = d.divide(gcd).negate();
}
}
returnthis;
}
public BigFraction simplify()
{
BigInteger gcd = n.gcd(d);
if(d.signum() == 1)
{
if(gcd.equals(BigInteger.ONE))
returnthis;
returnnew BigFraction(n.divide(gcd), d.divide(gcd));
}
else
returnnew BigFraction(n.divide(gcd).negate(), d.divide(gcd).negate());
}
public BigFraction subtract(BigFraction subtrahend)
{
returnnew BigFraction(n.multiply(subtrahend.d).subtract(subtrahend.n.multiply(d)), d.multiply(subtrahend.d)).simp();
}
public BigDecimal toBigDecimal()
{
return toBigDecimal(MathContext.UNLIMITED);
}
public BigDecimal toBigDecimal(int precision)
{
return toBigDecimal(new MathContext(precision));
}
public BigDecimal toBigDecimal(MathContext m)
{
returnnew BigDecimal(n).divide(new BigDecimal(d), m);
}
public BigInteger toBigInteger()
{
return n.divide(d);
}
BigInteger toBigIntegerExact()
{
BigInteger[] div = n.divideAndRemainder(d);
if(div[1].equals(BigInteger.ZERO))
thrownew ArithmeticException("Information lost in conversion to BigInteger.");
return div[0];
}
public String toDecimalString()
{
return toDecimalString(MathContext.UNLIMITED);
}
public String toDecimalString(int precision)
{
return toDecimalString(new MathContext(precision));
}
public String toDecimalString(MathContext m)
{
return toBigDecimal(m).toString();
}
public String toString()
{
return toString(10);
}
public String toString(int base)
{
return n.toString(base) +"/" + d.toString(base);
}
publicstatic BigFraction valueOf(double val)
{
returnnew BigFraction(BigDecimal.valueOf(val));
}
publicstatic BigFraction valueOf(long val)
{
return valueOf(val, 1);
}
publicstatic BigFraction valueOf(long numerator,long denominator)
{
returnnew BigFraction(BigInteger.valueOf(numerator), BigInteger.valueOf(denominator));
}
publicstatic BigFraction valueOf(String val)
{
int index = val.indexOf('/');
if(index >= 0)
returnnew BigFraction(val);
else
returnnew BigFraction(new BigDecimal(val));
}
}
[22378 byte] By [
Adeodatus] at [2007-9-30 20:56:22]

I noticed this page is te first hit on google for "BigFraction." Not wanting to foul anyone up with the bugs in my first version, I'm posting my fixed-up version ;~)
/* Author: Adeodatus
*
*
*/
/*package java.math;*/
import java.math.*;
public class BigFraction extends Number implements Comparable<BigFraction>, java.io.Serializable
{
public static final BigFraction ZERO = new BigFraction(BigInteger.ZERO, BigInteger.ONE),
ONE = new BigFraction(BigInteger.ONE, BigInteger.ONE),
TEN = new BigFraction(BigInteger.TEN, BigInteger.ONE);
private final BigInteger n, //numerator
d; //denominator
private static final BigInteger TWO = BigInteger.valueOf(2);
private static final java.security.SecureRandom rng;
static
{
rng = new java.security.SecureRandom();
rng.setSeed(BigInteger.valueOf(System.currentTimeMillis() * 1000000 + System.nanoTime()).pow(65).subtract(BigInteger.valueOf(13)).toByteArray());
}
public BigFraction()
{
this(BigInteger.ZERO, BigInteger.ONE);
}
public BigFraction(String val)
{
this(val, val.indexOf('/'));
}
public BigFraction(String val, int radix)
{
int index = val.indexOf('/');
if(index < 0)
throw new NumberFormatException("Constructor must be passed a properly formatted String.");
try
{
BigInteger n = new BigInteger(val.substring(0, index), radix),
d = new BigInteger(val.substring(index + 1, val.length()), radix),
gcd = n.gcd(d);
if(d.signum() == 0)
throw new ArithmeticException("Division by Zero");
else if(d.signum() == -1)
{
n = n.negate();
d = d.negate();
}
if(!gcd.equals(BigInteger.ONE))
{
n = n.divide(gcd);
d = d.divide(gcd);
}
this.n = n;
this.d = d;
}
catch(ArithmeticException e)
{
throw new ArithmeticException("Constructor must be passed a properly formatted String.");
}
}
public BigFraction(String numerator, String denominator)
{
this(new BigInteger(numerator), new BigInteger(denominator));
}
public BigFraction(BigDecimal bd)
{
int scale = bd.scale();
BigInteger n, d;
if(bd.signum() == 0)
{
n = BigInteger.ONE;
d = BigInteger.ZERO;
}
else
{
if(scale >= 0)
{
n = bd.unscaledValue().multiply(BigInteger.TEN.pow(scale));
d = BigInteger.ONE;
}
else
{
n = bd.unscaledValue();
d = BigInteger.TEN.pow(-scale);
}
BigInteger gcd = n.gcd(d);
if(!gcd.equals(BigInteger.ONE))
{
n = n.divide(gcd);
d = d.divide(gcd);
}
}
this.n = n;
this.d = d;
}
public BigFraction(BigInteger numerator)
{
this(numerator, BigInteger.ONE);
}
public BigFraction(byte[] numerator, byte[] denominator)
{
this(new BigInteger(numerator), new BigInteger(denominator));
}
public BigFraction(BigInteger numerator, BigInteger denominator)
{
if(denominator.signum() == 0)
throw new ArithmeticException("Division by Zero");
BigInteger n = numerator,
d = denominator,
gcd = n.gcd(d);
if(n.signum() == 0)
{
n = BigInteger.ZERO;
d = BigInteger.ONE;
}
else
{
if(d.signum() == -1)
{
n = n.negate();
d = d.negate();
}
if(!gcd.equals(BigInteger.ONE))
{
n = n.divide(gcd);
d = d.divide(gcd);
}
}
this.n = n;
this.d = d;
}
public BigFraction abs()
{
return n.signum() >= 0 ? this : new BigFraction(n.negate(), d);
}
public BigFraction add(BigFraction augend)
{
return new BigFraction(n.multiply(augend.d).add(augend.n.multiply(d)), d.multiply(augend.d));
}
public byte byteValue()
{
return toBigInteger().byteValue();
}
public byte byteValueExact()
{
BigInteger b = toBigIntegerExact();
if(isInRange(b, BigInteger.valueOf(Byte.MAX_VALUE), BigInteger.valueOf(Byte.MIN_VALUE)))
return b.byteValue();
throw new ArithmeticException("BigFraction out of range for byte");
}
public int compareTo(BigFraction val)
{
if(signum() == val.signum())
{
if(signum() == 0)
return 0;
return n.multiply(val.d).compareTo(val.n.multiply(d));
}
return signum() > val.signum() ? 1 : -1;
}
public BigInteger denominator()
{
return d;
}
public BigFraction divide(BigFraction divisor)
{
return new BigFraction(n.multiply(divisor.d), d.multiply(divisor.n));
}
public BigFraction[] divideAndRemainder(BigFraction divisor)
{
BigFraction[] ans = new BigFraction[2];
ans[0] = divideToIntegralValue(divisor);
ans[1] = subtract(divisor.multiply(ans[0]));
return ans;
}
public BigFraction divideToIntegralValue(BigFraction divisor)
{
return new BigFraction(divide(divisor).toBigInteger(), BigInteger.ONE);
}
public double doubleValue()
{
return toBigDecimal(MathContext.DECIMAL64).doubleValue();
}
public boolean equals(Object o)
{
return o instanceof BigFraction ? equals((BigFraction) o) : false;
}
public boolean equals(BigFraction val)
{
if(this == val)
return true;
return val != null && n.equals(val.n) && d.equals(val.d);
}
public float floatValue()
{
return toBigDecimal(MathContext.DECIMAL32).floatValue();
}
public int hashCode()
{
return n.hashCode() ^ d.hashCode();
}
public int intValue()
{
return toBigInteger().intValue();
}
public int intValueExact()
{
BigInteger b = toBigIntegerExact();
if(isInRange(b, BigInteger.valueOf(Integer.MAX_VALUE), BigInteger.valueOf(Integer.MIN_VALUE)))
return b.intValue();
throw new ArithmeticException("BigFraction out of range for int");
}
public BigFraction inverse()
{
return new BigFraction(d, n);
}
private boolean isInRange(BigInteger test, BigInteger min, BigInteger max)
{
return test.compareTo(min) >= 0 && test.compareTo(max) <= 0;
}
public long longValue()
{
return toBigInteger().longValue();
}
public long longValueExact()
{
BigInteger b = toBigIntegerExact();
if(isInRange(b, BigInteger.valueOf(Long.MAX_VALUE), BigInteger.valueOf(Long.MIN_VALUE)))
return b.longValue();
throw new ArithmeticException("BigFraction out of range for long");
}
public BigFraction max(BigFraction val)
{
return compareTo(val) >= 0 ? this : val;
}
public BigFraction min(BigFraction val)
{
return compareTo(val) <= 0 ? this : val;
}
public BigFraction mod(BigFraction val)
{
return remainder(val).abs();
}
public BigFraction multiply(BigFraction multiplicand)
{
return new BigFraction(n.multiply(multiplicand.n), d.multiply(multiplicand.d));
}
public BigFraction negate()
{
return new BigFraction(n.negate(), d);
}
public BigInteger numerator()
{
return n;
}
public BigFraction plus()
{
return this;
}
public BigFraction pow(int power)
{
BigInteger n = this.n,
d = this.d;
if(power < 0)
{
power = -power;
n = this.d;
d = this.n;
}
return new BigFraction(n.pow(power), d.pow(power));
}
public static BigFraction random()
{
return random(128, rng);
}
public static BigFraction random(int bits)
{
return random(bits, rng);
}
public static BigFraction random(int bits, java.util.Random rng)
{
try
{
return new BigFraction(new BigInteger(bits, rng), TWO.pow(bits));
}
catch(IllegalArgumentException e)
{
throw new IllegalArgumentException("Bit length may not be negative.", e);
}
}
public BigFraction remainder(BigFraction divisor)
{
return subtract(divisor.multiply(divideToIntegralValue(divisor)));
}
public short shortValue()
{
return toBigInteger().shortValue();
}
public short shortValueExact()
{
BigInteger b = toBigIntegerExact();
if(isInRange(b, BigInteger.valueOf(Short.MAX_VALUE), BigInteger.valueOf(Short.MIN_VALUE)))
return b.shortValue();
throw new ArithmeticException("BigFraction out of range for short");
}
public int signum()
{
return n.signum();
}
public BigFraction subtract(BigFraction subtrahend)
{
return new BigFraction(n.multiply(subtrahend.d).subtract(subtrahend.n.multiply(d)), d.multiply(subtrahend.d));
}
public BigDecimal toBigDecimal()
{
return toBigDecimal(MathContext.UNLIMITED);
}
public BigDecimal toBigDecimal(MathContext mc)
{
return new BigDecimal(n).divide(new BigDecimal(d), mc);
}
public BigInteger toBigInteger()
{
return n.divide(d);
}
BigInteger toBigIntegerExact()
{
BigInteger[] div = n.divideAndRemainder(d);
if(div[1].signum() != 0)
throw new ArithmeticException("Information lost in conversion to BigInteger.");
return div[0];
}
public String toString()
{
return toString(10);
}
public String toString(int base)
{
return n.toString(base) + "/" + d.toString(base);
}
public static BigFraction valueOf(double val)
{
return new BigFraction(BigDecimal.valueOf(val));
}
public static BigFraction valueOf(long val)
{
return valueOf(val, 1);
}
public static BigFraction valueOf(long numerator, long denominator)
{
return new BigFraction(BigInteger.valueOf(numerator), BigInteger.valueOf(denominator));
}
public static BigFraction valueOf(String val)
{
try
{
return new BigFraction(val, 10);
}
catch(NumberFormatException e)
{
try
{
return new BigFraction(new BigDecimal(val));
}
catch(NumberFormatException e2)
{
}
}
throw new IllegalArgumentException("Must be passed a properly formatted String.");
}
}