package is.L42.connected.withNumbers; import java.io.Reader; import java.math.BigInteger; import java.math.MathContext; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Random; import java.util.Set; public final class BigRational implements Comparable<BigRational>{ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((den == null) ? 0 : den.hashCode()); result = prime * result + ((num == null) ? 0 : num.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; BigRational other = (BigRational) obj; if (den == null) { if (other.den != null) return false; } else if (!den.equals(other.den)) return false; if (num == null) { if (other.num != null) return false; } else if (!num.equals(other.num)) return false; return true; } public final BigInteger num; public final BigInteger den; public final static BigRational ZERO = new BigRational(BigInteger.ZERO,BigInteger.ONE); public final static BigRational ONE = new BigRational(BigInteger.ONE,BigInteger.ONE); //public final static BigRational POSINFINITE = new BigRational(BigInteger.ONE,BigInteger.ZERO); //public final static BigRational NEGINFINITE = new BigRational(BigInteger.ONE.negate(),BigInteger.ZERO); //they should never happen private BigRational(BigInteger num, BigInteger den) { this.num = num; this.den = den; } public static BigRational from(BigInteger num) { return new BigRational(num,BigInteger.ONE); } public static BigRational from (BigInteger num, BigInteger den) { return normalize(num, den); } public static BigRational from (long num, long den) { return from(BigInteger.valueOf(num),BigInteger.valueOf(den)); } /** * @param s String. * @throws NumberFormatException */ public static BigRational from(String s){ assert s != null; assert s.length() != 0; assert s.equals(s.trim()); int i = s.indexOf('/'); if (i < 0) { assert i==-1; return noSlash(s);} String sn = s.substring(0, i); String sd = s.substring(i + 1, s.length()); if (s.indexOf(".") < 0) { // both integers return from(new BigInteger(sn), new BigInteger(sd)); } return BigRational.noSlash(sn).divide(BigRational.noSlash(sd)); } private static BigRational noSlash(String s) { int i = s.indexOf('.'); if (i < 0) {assert i==-1; return new BigRational(new BigInteger(s),BigInteger.ONE); } //we have a . to worry about int pow=s.length()-i; String sDen="1"; for(int j=0;j<pow;j++){ sDen+="0";} BigInteger den=new BigInteger(sDen); String sNum=//s.replace(".","");//would tollerate more dots s.substring(0, i)+s.substring(i+1,s.length()); assert sNum.indexOf(".")==-1; BigInteger num=new BigInteger(sNum); return BigRational.from(num,den); } /** * Get the string representation. * @see java.lang.Object#toString() */ @Override public String toString() { if (den.equals(BigInteger.ONE)){return num.toString();} StringBuffer s = new StringBuffer(); s.append(num); s.append("/"); s.append(den); return s.toString(); } public double doubleValue() { double num=this.num.doubleValue(); double den=this.den.doubleValue(); return num/den; } /** * Rational number reduction to lowest terms. * @param n BigInteger. * @param d BigInteger. * @return a/b ~ n/d, gcd(a,b) = 1, b > 0. */ public static BigRational normalize(BigInteger n, BigInteger d) { if (n.equals(BigInteger.ZERO)) { return ZERO;} if (n.equals(d)) { return ONE;} BigInteger c = n.gcd(d); if (d.signum() ==-1) { n=n.negate(); d=d.negate();} assert d.signum()!=-1; if (c.equals(BigInteger.ONE)) { return new BigRational(n,d);}//sign return new BigRational(n.divide(c), d.divide(c)); } public BigRational abs() { if (this.signum() >= 0) { return this; } return this.negate(); } @Override public int compareTo(BigRational S) { BigInteger J2Y; BigInteger J3Y; BigInteger R1; BigInteger R2; BigInteger S1; BigInteger S2; int J1Y; int SL; int TL; int RL; if (this.equals(ZERO)) { return -S.signum(); } if (S.equals(ZERO)) { return this.signum(); } R1 = num; //this.numerator(); R2 = den; //this.denominator(); S1 = S.num; S2 = S.den; RL = R1.signum(); SL = S1.signum(); J1Y = (RL - SL); TL = (J1Y / 2); if (TL != 0) { return TL; } J3Y = R1.multiply(S2); J2Y = R2.multiply(S1); TL = J3Y.compareTo(J2Y); return TL; } /** * Rational number difference. * @param S BigRational. * @return this-S. */ public BigRational subtract(BigRational S) { return this.sum(S.negate()); } /** * Rational number inverse. * @return 1/this. * @see edu.jas.structure.RingElem#inverse() */ public BigRational inverse() { BigInteger R1 = num; BigInteger R2 = den; BigInteger S1; BigInteger S2; if (R1.signum() >= 0) { S1 = R2; S2 = R1; } else { S1 = R2.negate(); S2 = R1.negate(); } return new BigRational(S1, S2); } /** * Rational number negative. * @return -this. * @see edu.jas.structure.RingElem#negate() */ public BigRational negate() { BigInteger n = num.negate(); return new BigRational(n, den); } /** * Rational number product. * @param S BigRational. * @return this*S. */ public BigRational multiply(BigRational S) { BigInteger D1 = null; BigInteger D2 = null; BigInteger R1 = null; BigInteger R2 = null; BigInteger RB1 = null; BigInteger RB2 = null; BigInteger S1 = null; BigInteger S2 = null; BigInteger SB1 = null; BigInteger SB2 = null; BigRational T; BigInteger T1; BigInteger T2; if (this.equals(ZERO) || S.equals(ZERO)) { T = ZERO; return T; } R1 = num; //this.numerator(); R2 = den; //this.denominator(); S1 = S.num; S2 = S.den; if (R2.equals(BigInteger.ONE) && S2.equals(BigInteger.ONE)) { T1 = R1.multiply(S1); T = new BigRational(T1, BigInteger.ONE); return T; } if (R2.equals(BigInteger.ONE)) { if (R1.equals(S2)) { D1 = R1; } else { D1 = R1.gcd(S2); } RB1 = R1.divide(D1); SB2 = S2.divide(D1); T1 = RB1.multiply(S1); T = new BigRational(T1, SB2); return T; } if (S2.equals(BigInteger.ONE)) { if (S1.equals(R2)) { D2 = S1; } else { D2 = S1.gcd(R2); } SB1 = S1.divide(D2); RB2 = R2.divide(D2); T1 = SB1.multiply(R1); T = new BigRational(T1, RB2); return T; } if (R1.equals(S2)) { D1 = R1; } else { D1 = R1.gcd(S2); } RB1 = R1.divide(D1); SB2 = S2.divide(D1); if (S1.equals(R2)) { D2 = S1; } else { D2 = S1.gcd(R2); } SB1 = S1.divide(D2); RB2 = R2.divide(D2); T1 = RB1.multiply(SB1); T2 = RB2.multiply(SB2); T = new BigRational(T1, T2); return T; } /** * Rational number quotient. * @param S BigRational. * @return this/S. */ public BigRational divide(BigRational S) { return multiply(S.inverse()); } /** * Rational number sign. * @see edu.jas.structure.RingElem#signum() */ public int signum() { return num.signum(); } /** * Rational number sum. * @param S BigRational. * @return this+S. */ public BigRational sum(BigRational S) { BigInteger D = null; BigInteger E, J1Y, J2Y; BigRational T; BigInteger R1 = null; BigInteger R2 = null; BigInteger RB2 = null; BigInteger S1 = null; BigInteger S2 = null; BigInteger SB2 = null; BigInteger T1; BigInteger T2; if (this.equals(ZERO)) { return S; } if (S.equals(ZERO)) { return this; } R1 = num; //this.numerator(); R2 = den; //this.denominator(); S1 = S.num; S2 = S.den; if (R2.equals(BigInteger.ONE) && S2.equals(BigInteger.ONE)) { T1 = R1.add(S1); T = new BigRational(T1, BigInteger.ONE); return T; } if (R2.equals(BigInteger.ONE)) { T1 = R1.multiply(S2); T1 = T1.add(S1); T = new BigRational(T1, S2); return T; } if (S2.equals(BigInteger.ONE)) { T1 = R2.multiply(S1); T1 = T1.add(R1); T = new BigRational(T1, R2); return T; } if (R2.equals(S2)) { D = R2; } else { D = R2.gcd(S2); } if (D.equals(BigInteger.ONE)) { RB2 = R2; SB2 = S2; } else { RB2 = R2.divide(D); SB2 = S2.divide(D); } J1Y = R1.multiply(SB2); J2Y = RB2.multiply(S1); T1 = J1Y.add(J2Y); if (T1.equals(BigInteger.ZERO)) { return ZERO; } if (!D.equals(BigInteger.ONE)) { if (T1.equals(D)) { E = D; } else { E = T1.gcd(D); } if (!E.equals(BigInteger.ONE)) { T1 = T1.divide(E); R2 = R2.divide(E); } } T2 = R2.multiply(SB2); T = new BigRational(T1, T2); return T; } /** * Returns the number of bits in the representation of this BigRational, * including a sign bit. For positive BigRational, this is equivalent to * {@code num.bitLength()+den.bitLength()}.) * @return number of bits in the representation of this BigRational, * including a sign bit. */ public long bitLength() { long n = num.bitLength(); if (num.signum() < 0) { n++; } n++; n += den.bitLength(); assert den.signum() ==1; n++; return n; } }