/* * Copyright (C) 2009-2012 University of Freiburg * * This file is part of SMTInterpol. * * SMTInterpol is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * SMTInterpol is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with SMTInterpol. If not, see <http://www.gnu.org/licenses/>. */ package de.uni_freiburg.informatik.ultimate.logic; import java.math.BigInteger; /** * Class that represents a rational number num/denom, * where num and denom are BigInteger. This class also handles * infinity and NAN. * * Internally, the numbers are always kept in reduced form; the * denominator is always kept non-negative. A zero denominator * with non-zero numerator indicates positive or negative infinity. * The number 0/0 is used to represent NAN (not a number). * * Every operation that involves NAN gives NAN as result. * The non-obvious rules for ZERO, INFINITY, and NAN are: * <pre> * ONE.div(NEGATIVE_INFINITY).isNegative() = false (no negative ZERO) * ZERO.inverse() = POSITIVE_INFINITY * POSITIVE_INFINITY.add(finite number) = POSITIVE_INFINITY. * POSITIVE_INFINITY.add(NEGATIVE_INFINITY) = NAN * ZERO.mul(POSITIVE_INFINITY) = ZERO.mul(NEGATIVE_INFINITY) = NAN * number.div(ZERO) = POSITIVE_INFINITY.mul(number.signum()) * NAN.isIntegral = POSITIVE_INFINITY.isIntegral = true * NAN.floor() = NAN; * POSITIVE_INFINITY.floor() = POSITIVE_INFINITY; * NAN.frac() = POSITIVE_INFINITY.frac() = ZERO; * </pre> * * This class only uses bigintegers if either numerator or * denominator does not fit into an int. * @author Juergen Christ, Jochen Hoenicke */ public class Rational implements Comparable<Rational> { /** * The numerator if num and denom are in int range. */ int mNum; /** * The denominator if num and denom are in int range. */ int mDenom; static class BigRational extends Rational { /** * The numerator if num or denom is outside int range. */ BigInteger mBignum; /** * The denominator if num or denom is outside int range. */ BigInteger mBigdenom; /** * Construct a rational from two bigints. The constructor * is private and does not normalize. Use the static * constructor valueOf instead. * @param nom Numerator * @param denom Denominator */ private BigRational(BigInteger nom,BigInteger denom) { super(nom.signum(),1); mBignum = nom; mBigdenom = denom; } /** * Return a new rational representing <code>this + other</code>. * @param other Rational to add. * @return Sum of <code>this</code> and <code>other</code>. */ @Override public Rational add(Rational other) { /* fast path */ if (other == Rational.ZERO) { return this; } final BigInteger tdenom = denominator(); final BigInteger odenom = other.denominator(); if (tdenom.equals(odenom)) { /* another very simple case */ return valueOf(numerator().add(other.numerator()), tdenom); } final BigInteger gcd = tdenom.gcd(odenom); final BigInteger tdenomgcd = tdenom.divide(gcd); final BigInteger odenomgcd = odenom.divide(gcd); final BigInteger newnum = numerator().multiply(odenomgcd) .add(other.numerator().multiply(tdenomgcd)); final BigInteger newdenom = tdenom.multiply(odenomgcd); return valueOf(newnum, newdenom); } /** * Returns a new rational equal to <code>-this</code>. * @return <code>-this</code> */ @Override public Rational negate() { return Rational.valueOf(mBignum.negate(), mBigdenom); } /** * Return a new rational representing <code>this * other</code>. * @param other Rational to multiply. * @return Product of <code>this</code> and <code>other</code>. */ @Override public Rational mul(Rational other) { /* fast path */ if (other == Rational.ONE) { return this; } if (other == Rational.ZERO) { return other; } if (other == Rational.MONE) { return negate(); } final BigInteger newnum = numerator().multiply(other.numerator()); final BigInteger newdenom = denominator().multiply(other.denominator()); return valueOf(newnum, newdenom); } /** * Return a new rational representing <code>this * other</code>. * @param other big integer to multiply. * @return Product of <code>this</code> and <code>other</code>. */ @Override public Rational mul(BigInteger other) { if (other.bitLength() < 2) { /* fast path */ final int oint = other.intValue(); if (oint == 1) { return this; } if (oint == -1) { return negate(); } if (oint == 0) { return Rational.ZERO; } } return valueOf(numerator().multiply(other), denominator()); } /** * Return a new rational representing <code>this / other</code>. * @param other Rational to divide. * @return Quotient of <code>this</code> and <code>other</code>. */ @Override public Rational div(Rational other) { if (other == Rational.ONE) { return this; } if (other == Rational.MONE) { return negate(); } final BigInteger denom = denominator().multiply(other.numerator()); BigInteger nom = numerator().multiply(other.denominator()); // +-inf : -c = -+inf if (denom.equals(BigInteger.ZERO) && other.numerator().signum() == -1) { nom = nom.negate(); } return valueOf(nom,denom); } /** * Return a new rational representing <code>this / other</code>. * @param other Rational to divide. * @return Quotient of <code>this</code> and <code>other</code>. */ public Rational idiv(Rational other) { BigInteger num = denominator().multiply(other.numerator()); final BigInteger denom = numerator().multiply(other.denominator()); // +-inf : -c = -+inf if (denom.equals(BigInteger.ZERO) && numerator().signum() == -1) { num = num.negate(); } return valueOf(num,denom); } /** * Returns a new rational representing the inverse of <code>this</code>. * @return Inverse of <code>this</code>. */ @Override public Rational inverse() { return valueOf(mBigdenom, mBignum); } /** * Compute the gcd of two rationals (this and other). The gcd * is the rational number, such that dividing this and other with * the gcd will yield two co-prime integers. * @param other the second rational argument. * @return the gcd of this and other. */ @Override public Rational gcd(Rational other) { if (other == Rational.ZERO) { return this; } final BigInteger tdenom = denominator(); final BigInteger odenom = other.denominator(); final BigInteger gcddenom = tdenom.gcd(odenom); final BigInteger denom = tdenom.divide(gcddenom).multiply(odenom); final BigInteger num = numerator().gcd(other.numerator()); return Rational.valueOf(num, denom); } @Override public int compareTo(Rational o) { final BigInteger valthis = numerator().multiply(o.denominator()); final BigInteger valo = o.numerator().multiply(denominator()); return valthis.compareTo(valo); } @Override public boolean equals(Object o) { if (o instanceof BigRational) { final BigRational r = (BigRational) o; // Works thanks to normalization!!! return mBignum.equals(r.mBignum) && mBigdenom.equals(r.mBigdenom); } if (o instanceof MutableRational) { return ((MutableRational) o).equals(this); } return false; } @Override public BigInteger numerator() { return mBignum; } @Override public BigInteger denominator() { return mBigdenom; } @Override public int hashCode() { return mBignum.hashCode() * 257 + mBigdenom.hashCode(); } @Override public String toString() { if (mBigdenom.equals(BigInteger.ONE)) { return mBignum.toString(); } return mBignum.toString() + "/" + mBigdenom.toString(); } /** * Check whether this rational represents an integral value. Both * infinity values are treated as integral. * @return <code>true</code> iff value is integral. */ @Override public boolean isIntegral() { return mBigdenom.equals(BigInteger.ONE); } /** * Return a new rational representing the biggest integral rational not * bigger than <code>this</code>. * @return Next smaller integer of <code>this</code>. */ @Override public Rational floor() { if (denominator().equals(BigInteger.ONE)) { return this; } BigInteger div = numerator().divide(denominator()); if (numerator().signum() < 0) { div = div.subtract(BigInteger.ONE); } return Rational.valueOf(div,BigInteger.ONE); } /** * Returns the fractional part of the rational, i.e. the * number this.sub(this.floor()). * @return Next smaller integer of <code>this</code>. */ @Override public Rational frac() { if (mBigdenom.equals(BigInteger.ONE)) { return Rational.ZERO; } BigInteger newnum = mBignum.mod(mBigdenom); if (newnum.signum() < 0) { newnum = newnum.add(mBigdenom); } return Rational.valueOf(newnum, mBigdenom); } /** * Return a new rational representing the smallest integral rational not * smaller than <code>this</code>. * @return Next bigger integer of <code>this</code>. */ @Override public Rational ceil() { if (denominator().equals(BigInteger.ONE)) { return this; } BigInteger div = numerator().divide(denominator()); if (numerator().signum() > 0) { div = div.add(BigInteger.ONE); } return Rational.valueOf(div,BigInteger.ONE); } @Override public Rational abs() { return valueOf(mBignum.abs(), mBigdenom); } } /** * Construct a rational from two ints. The constructor * is private and does not normalize. Use the static * constructor valueOf instead. * @param num The numerator. * @param denom The denominator. */ private Rational(int num, int denom) { mNum = num; mDenom = denom; } /** * Construct a rational from two bigints. Use this method * to create a rational number if the numerator or denominator * may be to big to fit in an int. This method normalizes * the rational number and does partial unification. * * @param bignum The numerator. * @param bigdenom The denominator. * @return a rational representing numerator/denominator. */ public static Rational valueOf(BigInteger bignum, BigInteger bigdenom) { final int cp = bigdenom.signum(); if (cp < 0) { bignum = bignum.negate(); bigdenom = bigdenom.negate(); } else if (cp == 0) { return valueOf(bignum.signum(), 0); } if (!bigdenom.equals(BigInteger.ONE)) { final BigInteger norm = gcd(bignum, bigdenom).abs(); if (!norm.equals(BigInteger.ONE)) { bignum = bignum.divide(norm); bigdenom = bigdenom.divide(norm); } } if (bigdenom.bitLength() < 32 && bignum.bitLength() < 32) { return valueOf(bignum.intValue(), bigdenom.intValue()); } else { return new BigRational(bignum, bigdenom); } } /** * Construct a rational from two longs. Use this method * to create a rational number. This method normalizes * the rational number and may return a previously created * one. * This method does not work if called with value * Long.MIN_VALUE. * * @param newnum The numerator. * @param newdenom The denominator. * @return a rational representing numerator/denominator. */ public static Rational valueOf(long newnum, long newdenom) { if (newdenom != 1) { long gcd2 = Math.abs(gcd(newnum, newdenom)); if (gcd2 == 0) { return NAN; } if (newdenom < 0) { gcd2 = -gcd2; } newnum /= gcd2; newdenom /= gcd2; } if (newdenom == 1) { if (newnum == 0) { return ZERO; } if (newnum == 1) { return ONE; } if (newnum == -1) { return MONE; } } else if (newdenom == 0) { if (newnum == 1) { return POSITIVE_INFINITY; } else { return NEGATIVE_INFINITY; } } if (Integer.MIN_VALUE <= newnum && newnum <= Integer.MAX_VALUE && newdenom <= Integer.MAX_VALUE) { return new Rational((int) newnum, (int) newdenom); } return new BigRational(BigInteger.valueOf(newnum), BigInteger.valueOf(newdenom)); } /** * Calculates the greatest common divisor of two numbers. Expects two * nonnegative values. * @param a First number * @param b Second Number * @return Greatest common divisor */ static int gcd(int a,int b) { /* This is faster for integer */ //assert(a >= 0 && b >= 0); while (b != 0) { final int t = a % b; a = b; b = t; } return a; } /** * Calculates the greatest common divisor of two numbers. * @param a First number * @param b Second Number * @return Greatest common divisor */ static long gcd(long a,long b) { /* This is faster for longs on 32-bit architectures */ if (a < 0) { a = -a; } if (b < 0) { b = -b; } if (a == 0 || b == 1) { return b; } if (b == 0 || a == 1) { return a; } final int ashift = Long.numberOfTrailingZeros(a); final int bshift = Long.numberOfTrailingZeros(b); a >>= ashift; b >>= bshift; while (a != b) { long t; if (a < b) { t = b - a; b = a; } else { if (b == 1) { a = b; break; } t = a - b; } do { t >>= 1; } while (((int) t & 1) == 0); a = t; } return a << Math.min(ashift, bshift); } /** * Compute the gcd of two BigInteger. This is the same * as {@code i1.gcd(i2)}, but it is more efficient for small numbers. * @param i1 the first big integer. * @param i2 the second big integer. * @return the gcd of i1 and i2. */ public static BigInteger gcd(BigInteger i1, BigInteger i2) { if (i1.equals(BigInteger.ONE) || i2.equals(BigInteger.ONE)) { return BigInteger.ONE; } final int l1 = i1.bitLength(); final int l2 = i2.bitLength(); if (l1 < 31 && l2 < 31) { return BigInteger.valueOf(gcd(i1.intValue(), i2.intValue())); } else if (l1 < 63 && l2 < 63) { return BigInteger.valueOf(gcd(i1.longValue(), i2.longValue())); } else { return i1.gcd(i2); } } /** * Return a new rational representing <code>this + other</code>. * @param other Rational to add. * @return Sum of <code>this</code> and <code>other</code>. */ public Rational add(Rational other) { /* fast path */ if (other == Rational.ZERO) { return this; } if (this == Rational.ZERO) { return other; } if (other instanceof BigRational) { return other.add(this); } else { if (mDenom == other.mDenom) { /* handle gcd = 0 correctly * two INFINITYs with same sign give INFINITY, * otherwise it gives NAN. */ if (mDenom == 0) { return mNum == other.mNum ? this : NAN; } /* a common, very simple case, e.g. for integers */ return valueOf((long) mNum + other.mNum, mDenom); } /* This also handles infinity/NAN + normal correctly. */ final int gcd = gcd(mDenom, other.mDenom); final long denomgcd = mDenom / gcd; final long otherdenomgcd = other.mDenom / gcd; final long newdenom = denomgcd * other.mDenom; final long newnum = otherdenomgcd * mNum + denomgcd * other.mNum; return valueOf(newnum, newdenom); } } /** * Computes {@code this + (fac1*fac2)}. * @param fac1 one of the factors. * @param fac2 the other factor. * @return the result of the computation. */ public Rational addmul(Rational fac1,Rational fac2) { return add(fac1.mul(fac2)); } /** * Computes {@code (this - s) / d}. * @param s the rational to subtract. * @param d the divisor. * @return the result of the computation. */ public Rational subdiv(Rational s,Rational d) { return sub(s).div(d); } /** * Returns a new rational equal to <code>-this</code>. * @return <code>-this</code>. */ public Rational negate() { return Rational.valueOf(-(long)mNum, mDenom); } /** * Return a new rational representing <code>this - other</code>. * @param other Rational to subtract. * @return Difference of <code>this</code> and <code>other</code>. */ public Rational sub(Rational other) { return add(other.negate()); } /** * Return a new rational representing <code>this * other</code>. * @param other Rational to multiply. * @return Product of <code>this</code> and <code>other</code>. */ public Rational mul(Rational other) { /* fast path */ if (other == Rational.ONE) { return this; } if (this == Rational.ONE) { return other; } if (other == Rational.MONE) { return negate(); } if (this == Rational.MONE) { return other.negate(); } if (other instanceof BigRational) { return other.mul(this); } final long newnum = (long)mNum * other.mNum; final long newdenom = (long)mDenom * other.mDenom; return valueOf(newnum, newdenom); } /** * Return a new rational representing <code>this * other</code>. * @param other big integer to multiply. * @return Product of <code>this</code> and <code>other</code>. */ public Rational mul(BigInteger other) { if (other.bitLength() < 32) { // NOCHECKSTYLE /* fast path */ final int oint = other.intValue(); if (oint == 1) { return this; } if (oint == -1) { return negate(); } final long newnum = (long)mNum * oint; return valueOf(newnum, mDenom); } if (this == Rational.ONE) { return valueOf(other, BigInteger.ONE); } if (this == Rational.MONE) { return valueOf(other.negate(), BigInteger.ONE); } return valueOf(numerator().multiply(other), denominator()); } /** * Return a new rational representing <code>this / other</code>. * @param other Rational to divide. * @return Quotient of <code>this</code> and <code>other</code>. */ public Rational div(Rational other) { if (other == Rational.ONE) { return this; } if (other == Rational.MONE) { return negate(); } if (other instanceof BigRational) { return ((BigRational)other).idiv(this); } /* fast path */ long newnum = (long)mNum * other.mDenom; final long newdenom = (long)mDenom * other.mNum; // +-inf : -c = -+inf if (newdenom == 0 && other.mNum < 0) { newnum = -newnum; } return valueOf(newnum, newdenom); } /** * Compute the gcd of two rationals (this and other). The gcd * is the rational number, such that dividing this and other with * the gcd will yield two co-prime integers. * @param other the second rational argument. * @return the gcd of this and other. */ public Rational gcd(Rational other) { if (this == Rational.ZERO) { return other; } if (other == Rational.ZERO) { return this; } if (other instanceof BigRational) { return other.gcd(this); } /* new numerator = gcd(num, other.num) */ /* new denominator = lcm(denom, other.denom) */ final int gcddenom = gcd(mDenom, other.mDenom); final long denom = ((long) (mDenom / gcddenom)) * other.mDenom; final long num = gcd(mNum < 0 ? -mNum : mNum, other.mNum < 0 ? -other.mNum : other.mNum); return valueOf(num, denom); } /** * Returns a new rational representing the inverse of <code>this</code>. * @return Inverse of <code>this</code>. */ public Rational inverse() { return valueOf(mDenom, mNum); } /** * Check whether this rational is negative. * @return <code>true</code> iff this rational is negative. */ public boolean isNegative() { return mNum < 0; } /** * Return the sign of this rational. The sign will be -1, 0, or 1 if this * rational is negative, zero, or positive. * @return The sign of this rational. */ public int signum() { return mNum < 0 ? -1 : mNum == 0 ? 0 : 1; } @Override /** * Compares this rational with the other. * @param o the other rational. * @return -1, if this < o; 1, if this > o; 0 if they are equal. */ public int compareTo(Rational o) { if (o instanceof BigRational) { return -o.compareTo(this); } /* handle infinities and nan */ if (o.mDenom == mDenom) { return mNum < o.mNum ? -1 : mNum == o.mNum ? 0 : 1; } final long valt = (long)mNum * o.mDenom; final long valo = (long)o.mNum * mDenom; return valt < valo ? -1 : valt == valo ? 0 : 1; } @Override /** * Compares this rational with the other. This works with * Rational and MutableRational. * @param o the other rational. * @return true if this equals o, false otherwise. */ public boolean equals(Object o) { if (o instanceof Rational) { if (o instanceof BigRational) { return false; } final Rational r = (Rational) o; // Works thanks to normalization!!! return mNum == r.mNum && mDenom == r.mDenom; } if (o instanceof MutableRational) { return ((MutableRational) o).equals(this); } return false; } /** * Get the numerator of this rational. * @return the numerator. */ public BigInteger numerator() { return BigInteger.valueOf(mNum); } /** * Get the denominator of this rational. * @return the denominator. */ public BigInteger denominator() { return BigInteger.valueOf(mDenom); } /** * Computes a hashcode. The hashcode is computed as * {@code 257 * numerator + denominator} if both fit into an integer and * {@code 257 * numerator().hashCode() + denominator().hashCode()} if big * integers are necessary. * @return the hashcode. */ @Override public int hashCode() { return mNum * 257 + mDenom; } /** * Get a string representation of this number. This is * {@code numerator()+ "/" + denominator()} except for * infinity ({@code "inf"}), nan ({@code "nan"}), or minus * infinity ({@code "-inf"}). * @return the string representation. */ @Override public String toString() { if (mDenom == 0) { return mNum > 0 ? "inf" : mNum == 0 ? "nan" : "-inf"; } if (mDenom == 1) { return String.valueOf(mNum); } return mNum + "/" + mDenom; } /** * Check whether this rational represents an integral value. Both infinity * values are treated as integral. * @return <code>true</code> iff value is integral. */ public boolean isIntegral() { return mDenom <= 1; } /** * Return a new rational representing the biggest integral rational not * bigger than <code>this</code>. * @return Next smaller integer of <code>this</code>. */ public Rational floor() { if (mDenom <= 1) { return this; } int div = mNum / mDenom; // Java rounds the wrong way for negative numbers. // We know that the division is not exact due to // normalization and mdenom != 1, so subtracting // one fixes the result for negative numbers. if (mNum < 0) { div--; } return valueOf(div, 1); } /** * Returns the fractional part of the rational, i.e. the * number this.sub(this.floor()). * @return Next smaller integer of <code>this</code>. */ public Rational frac() { if (mDenom <= 1) { return Rational.ZERO; } int newnum = mNum % mDenom; // Java rounds the wrong way for negative numbers. // We know that the division is not exact due to // normalization and mdenom != 1, so subtracting // one fixes the result for negative numbers. if (newnum < 0) { newnum += mDenom; } return valueOf(newnum, mDenom); } /** * Return a new rational representing the smallest integral rational not * smaller than <code>this</code>. * @return Next bigger integer of <code>this</code>. */ public Rational ceil() { if (mDenom <= 1) { return this; } int div = mNum / mDenom; // Java rounds the wrong way for positive numbers. // We know that the division is not exact due to // normalization and mdenom != 1, so adding // one fixes the result for positive numbers. if (mNum > 0) { div++; } return valueOf(div, 1); } /** * Compute the absolute of this rational. * @return Rational that is equal to the absolute value of this rational. */ public Rational abs() { return valueOf(Math.abs((long) mNum), mDenom); } /** * Positive infinity. Used to represent the result of 1/0. */ public final static Rational POSITIVE_INFINITY = new Rational(1,0); /** * Not a number. Used to represent the result of 0/0. */ public final static Rational NAN = new Rational(0,0); /** * Negative infinity. Used to represent the result of -1/0. */ public final static Rational NEGATIVE_INFINITY = new Rational(-1,0); /** * The number 0. */ public final static Rational ZERO = new Rational(0,1); /** * The number 1. */ public final static Rational ONE = new Rational(1,1); /** * The number -1. */ public final static Rational MONE = new Rational(-1,1); /** * The number 2. */ public static final Rational TWO = new Rational(2,1); /** * Creates a constant term containing this rational. * @param sort the sort of the constant term that should be created. * @return a constant term with this rational value. * @throws SMTLIBException if term is infinite or NaN, if the * sort is not numeric, or if the term is not integral and the sort * is Int. */ public Term toTerm(Sort sort) { return sort.getTheory().constant(this, sort); } /** * Convert this rational into an SMTLIB term. * @param t Theory to use during conversion. * @return SMTLIB term corresponding to this rational. * @deprecated Use {@link #toTerm(Sort)} since this is the type-safe version */ @Deprecated public Term toSMTLIB(Theory t) { return t.rational(numerator(), denominator()); } /** * Check whether this rational corresponds to a (finite) rational value. * This function can be used to test for infinites and NaNs. * @return true if and only if this rational is not infinite or NaN. */ public boolean isRational() { return mDenom != 0; } }