You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
831 lines
22 KiB
831 lines
22 KiB
//==============================================================================
|
|
//
|
|
// Copyright (c) 2013-
|
|
// Authors:
|
|
// * Ernst Moritz Hahn <emhahn@cs.ox.ac.uk> (University of Oxford)
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// This file is part of PRISM.
|
|
//
|
|
// PRISM is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation; either version 2 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// PRISM 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 General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with PRISM; if not, write to the Free Software Foundation,
|
|
// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
//
|
|
//==============================================================================
|
|
|
|
package param;
|
|
|
|
import java.math.BigInteger;
|
|
|
|
import prism.PrismLangException;
|
|
|
|
/**
|
|
* Provides a class to store big rational numbers.
|
|
* Numerator and denominator of a number stored using this class are not
|
|
* necessarily coprime. However, cancellation is applied by default.
|
|
* The special values infinity (INF), minus infinity (MINF) and not a number
|
|
* (NAN)are provided. For them, the usual rules apply (INF * INF = INF,
|
|
* MINF&INF=MINF, etc.), with the exception that INF+MINF=0, INF-INF=0, etc
|
|
* rather than NAN.
|
|
*
|
|
* @author Ernst Moritz Hahn <emhahn@cs.ox.ac.uk> (University of Oxford)
|
|
*/
|
|
public final class BigRational implements Comparable<BigRational>
|
|
{
|
|
/** the BigInteger "-1" */
|
|
private final static BigInteger BMONE = BigInteger.ONE.negate();
|
|
/** the BigInteger "2" */
|
|
private final static BigInteger BITWO = new BigInteger("2");
|
|
/** the BigInteger "10" */
|
|
private final static BigInteger BITEN = new BigInteger("10");
|
|
|
|
/** the BigRational "1" */
|
|
final static BigRational ONE = new BigRational(BigInteger.ONE);
|
|
/** the BigRational "-1" */
|
|
final static BigRational MONE = new BigRational(BigInteger.ONE).negate();
|
|
/** the BigRational "0" */
|
|
final static BigRational ZERO = new BigRational(BigInteger.ZERO);
|
|
/** the BigRational "infinity" */
|
|
final static BigRational INF = new BigRational(BigInteger.ONE, BigInteger.ZERO);
|
|
/** the BigRational "-infinity" */
|
|
final static BigRational MINF = new BigRational(BMONE, BigInteger.ZERO);
|
|
/** the BigRational "not a number" */
|
|
final static BigRational NAN = new BigRational(BigInteger.ZERO, BigInteger.ZERO);
|
|
|
|
/** numerator */
|
|
private BigInteger num;
|
|
/** denominator */
|
|
private BigInteger den;
|
|
|
|
// constructors
|
|
|
|
/**
|
|
* Creates a new BigRational with value 0.
|
|
*/
|
|
public BigRational()
|
|
{
|
|
this.num = BigInteger.ZERO;
|
|
this.den = BigInteger.ONE;
|
|
}
|
|
|
|
/**
|
|
* Creates a new BigRational with value {@code num}.
|
|
*
|
|
* @param num value of new rational as an integer value
|
|
*/
|
|
public BigRational(BigInteger num)
|
|
{
|
|
this.num = num;
|
|
this.den = BigInteger.ONE;
|
|
}
|
|
|
|
/**
|
|
* Creates a new BigRational with value {@code num} / {@code den}.
|
|
* Cancellation of {@code num} and {@code den} is applied.
|
|
*
|
|
* @param num numerator of this BigRational
|
|
* @param den denominator of this BigRational
|
|
*/
|
|
public BigRational(BigInteger num, BigInteger den)
|
|
{
|
|
this(num, den, true);
|
|
}
|
|
|
|
/**
|
|
* Creates a new BigRational with value {@code num} / {@code den}.
|
|
* Whether cancellation between {@code num} and {@code den} is applied depends
|
|
* on {@code cancel}.
|
|
*
|
|
* @param num numerator of this BigRational
|
|
* @param den denominator of this BigRational
|
|
* @param cancel true to ensure resulting BigRational is coprime
|
|
*/
|
|
public BigRational(BigInteger num, BigInteger den, boolean cancel)
|
|
{
|
|
if (den.equals(BigInteger.ZERO)) {
|
|
int cmp = num.compareTo(BigInteger.ZERO);
|
|
switch (cmp) {
|
|
case -1:
|
|
num = BMONE;
|
|
break;
|
|
case 1:
|
|
num = BigInteger.ONE;
|
|
break;
|
|
}
|
|
}
|
|
if (cancel) {
|
|
if (num.equals(BigInteger.ZERO)) {
|
|
num = BigInteger.ZERO;
|
|
den = BigInteger.ONE;
|
|
} else {
|
|
BigInteger gcd = num.gcd(den);
|
|
num = num.divide(gcd);
|
|
den = den.divide(gcd);
|
|
if (den.signum() == -1) {
|
|
num = num.negate();
|
|
den = den.negate();
|
|
}
|
|
}
|
|
}
|
|
this.num = num;
|
|
this.den = den;
|
|
}
|
|
|
|
/**
|
|
* Creates a new BigRational with value {@code num} / {@code den}.
|
|
* Cancellation of {@code num} and {@code den} is applied.
|
|
*
|
|
* @param num numerator of this BigRational
|
|
* @param den denominator of this BigRational
|
|
*/
|
|
public BigRational(long num, long den)
|
|
{
|
|
this(new BigInteger(Long.toString(num)), new BigInteger(Long.toString(den)));
|
|
}
|
|
|
|
/**
|
|
* Creates a new BigRational with value {@code num}.
|
|
*
|
|
* @param num value of new rational as an integer value
|
|
*/
|
|
public BigRational(long num)
|
|
{
|
|
this(num, 1);
|
|
}
|
|
|
|
/**
|
|
* Creates a new BigRational from string {@code string}.
|
|
* Formats supported are num / den where num and den are integers,
|
|
* and scientific notation.
|
|
*
|
|
* @param string string to create BigRational from
|
|
*/
|
|
public BigRational(String string)
|
|
{
|
|
if (string.equals("Infinity") || string.equals("Inf")) {
|
|
this.num = new BigInteger("1");
|
|
this.den = new BigInteger("0");
|
|
return;
|
|
} else if (string.equals("-Infinity") || string.equals("-Inf")) {
|
|
this.num = new BigInteger("-1");
|
|
this.den = new BigInteger("0");
|
|
return;
|
|
}
|
|
BigInteger num;
|
|
BigInteger den;
|
|
string = string.trim();
|
|
int slashIdx = string.indexOf('/');
|
|
if (slashIdx < 0) {
|
|
// decimal point notation
|
|
Double.parseDouble(string); // ensures correctness of format
|
|
boolean negate = false;
|
|
if (string.charAt(0) == '-') {
|
|
negate = true;
|
|
string = string.substring(1);
|
|
}
|
|
int ePos = string.indexOf("e");
|
|
if (ePos < 0) {
|
|
ePos = string.indexOf("E");
|
|
}
|
|
String coefficient = string.substring(0, ePos >= 0 ? ePos : string.length());
|
|
int dotIdx = coefficient.indexOf('.');
|
|
int expo = 0;
|
|
String noDotCoeff;
|
|
if (dotIdx >= 0) {
|
|
noDotCoeff = coefficient.substring(0, dotIdx);
|
|
noDotCoeff += coefficient.substring(dotIdx + 1);
|
|
expo = -coefficient.substring(dotIdx + 1).length();
|
|
} else {
|
|
noDotCoeff = coefficient;
|
|
}
|
|
if (ePos >= 0) {
|
|
String eStr = string.substring(ePos + 1);
|
|
int eInt = Integer.parseInt(eStr);
|
|
expo += eInt;
|
|
}
|
|
num = new BigInteger((negate ? "-" : "") + noDotCoeff);
|
|
BigInteger ten = BITEN;
|
|
if (expo == 0) {
|
|
den = BigInteger.ONE;
|
|
} else if (expo > 0) {
|
|
den = BigInteger.ONE;
|
|
num = num.multiply(ten.pow(expo));
|
|
} else { // expo < 0
|
|
den = ten.pow(-expo);
|
|
}
|
|
BigRational result = new BigRational(num, den, true);
|
|
this.num = result.num;
|
|
this.den = result.den;
|
|
} else {
|
|
// fractional
|
|
num = new BigInteger(string.substring(0, slashIdx));
|
|
den = new BigInteger(string.substring(slashIdx + 1, string.length()));
|
|
BigRational r = cancel(num, den);
|
|
this.num = r.num;
|
|
this.den = r.den;
|
|
return;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Construct a BigRational from the given object.
|
|
* Throws an IllegalArgumentException if there is no
|
|
* known conversion.
|
|
*/
|
|
public static BigRational from(Object value)
|
|
{
|
|
if (value instanceof BigRational) {
|
|
BigRational v = (BigRational)value;
|
|
return new BigRational(v.num, v.den);
|
|
} else if (value instanceof Integer) {
|
|
return new BigRational((int) value);
|
|
} else if (value instanceof Long) {
|
|
return new BigRational((long) value);
|
|
} else if (value instanceof Boolean) {
|
|
boolean v = (Boolean)value;
|
|
return new BigRational(v ? 1 : 0);
|
|
} else if (value instanceof Double) {
|
|
// TODO: ? might be imprecise, perhaps there
|
|
// is a way to get the full precision?
|
|
return new BigRational(((Double)value).toString());
|
|
}
|
|
throw new IllegalArgumentException("Can not convert from " + value.getClass() + " to BigRational");
|
|
}
|
|
|
|
// helper functions
|
|
|
|
/**
|
|
* Negates this number.
|
|
* Negation of INF, MINF are as usual, negation of NAN is NAN.
|
|
*
|
|
* @return negated BigRational
|
|
*/
|
|
public BigRational negate()
|
|
{
|
|
return new BigRational(num.negate(), den, false);
|
|
}
|
|
|
|
/**
|
|
* Convert to coprime BigRational.
|
|
*
|
|
* @return coprime rational with the same value as this object
|
|
*/
|
|
public BigRational cancel()
|
|
{
|
|
return new BigRational(this.num, this.den, true);
|
|
}
|
|
|
|
/**
|
|
* Creates a new BigRational with value {@code num} / {@code den}.
|
|
* Makes sure that {@code num} and {@code den} are coprime.
|
|
* To be used
|
|
*
|
|
* @param num numerator of new BigRational
|
|
* @param den denominator of new BigRational
|
|
* @return BigRational with value {@code num} / {@code den}
|
|
*/
|
|
private static BigRational cancel(BigInteger num, BigInteger den)
|
|
{
|
|
return new BigRational(num, den);
|
|
}
|
|
|
|
// operations
|
|
|
|
public BigRational add(BigRational other, boolean cancel)
|
|
{
|
|
if (this.isNaN() || other.isNaN()) {
|
|
return NAN;
|
|
}
|
|
if (this.isInf() || other.isInf()) {
|
|
if (this.isMInf() || other.isMInf()) {
|
|
return ZERO;
|
|
}
|
|
return INF;
|
|
}
|
|
if (this.isMInf() || other.isMInf()) {
|
|
return MINF;
|
|
}
|
|
BigInteger num = this.num.multiply(other.den).add(other.num.multiply(this.den));
|
|
BigInteger den = this.den.multiply(other.den);
|
|
return new BigRational(num, den, cancel);
|
|
}
|
|
|
|
public BigRational add(BigRational other)
|
|
{
|
|
return add(other, true);
|
|
}
|
|
|
|
public BigRational subtract(BigRational other)
|
|
{
|
|
if (this.isNaN() || other.isNaN()) {
|
|
return NAN;
|
|
}
|
|
if ((this.isInf() && other.isInf()) || (this.isMInf() && other.isMInf())) {
|
|
return ZERO;
|
|
}
|
|
if (this.isInf()) {
|
|
return INF;
|
|
}
|
|
if (this.isMInf()) {
|
|
return MINF;
|
|
}
|
|
if (other.isInf()) {
|
|
return INF;
|
|
}
|
|
if (other.isMInf()) {
|
|
return MINF;
|
|
}
|
|
BigInteger num = this.num.multiply(other.den).subtract(other.num.multiply(this.den));
|
|
BigInteger den = this.den.multiply(other.den);
|
|
return new BigRational(num, den);
|
|
}
|
|
|
|
/**
|
|
* Multiply this BigRational with {@code other}.
|
|
*
|
|
* @param other BigRational to multiply with
|
|
* @return result of the multiplication
|
|
*/
|
|
public BigRational multiply(BigRational other, boolean cancel)
|
|
{
|
|
if (this.isNaN() || other.isNaN()) {
|
|
return NAN;
|
|
}
|
|
if (this.isZero() || other.isZero()) {
|
|
return ZERO;
|
|
}
|
|
if (this.isInf() || other.isInf()) {
|
|
return this.signum() * other.signum() == 1 ? INF : MINF;
|
|
}
|
|
BigInteger num = this.num.multiply(other.num);
|
|
BigInteger den = this.den.multiply(other.den);
|
|
return new BigRational(num, den, cancel);
|
|
}
|
|
|
|
public BigRational multiply(BigRational other)
|
|
{
|
|
return multiply(other, true);
|
|
}
|
|
|
|
/**
|
|
* Multiply this BigRational with {@code other}.
|
|
*
|
|
* @param other long to multiply with
|
|
* @param cancel whether ensure result rational is comprime
|
|
* @return result of the multiplication
|
|
*/
|
|
public BigRational multiply(long other, boolean cancel)
|
|
{
|
|
return multiply(new BigRational(other), cancel);
|
|
}
|
|
|
|
/**
|
|
* Multiply this BigRational with {@code other}.
|
|
* Ensures result rational is coprime
|
|
*
|
|
* @param other long to multiply with
|
|
* @return result of the multiplication
|
|
*/
|
|
public BigRational multiply(long other)
|
|
{
|
|
return multiply(other, true);
|
|
}
|
|
|
|
/**
|
|
* Multiply this BigRational by {@code other}.
|
|
*
|
|
* @param other long to divide by
|
|
* @param cancel whether ensure result rational is comprime
|
|
* @return result of the division
|
|
*/
|
|
public BigRational divide(BigRational other, boolean cancel)
|
|
{
|
|
if (other.isInf() || other.isMInf()) {
|
|
return NAN;
|
|
}
|
|
BigRational inverseOther = new BigRational(other.den, other.num, cancel);
|
|
return multiply(inverseOther, cancel);
|
|
}
|
|
|
|
/**
|
|
* Divides this BigRational with {@code other}.
|
|
* Ensures result rational is coprime
|
|
*
|
|
* @param other long to divide by
|
|
* @return result of the division
|
|
*/
|
|
public BigRational divide(BigRational other)
|
|
{
|
|
return divide(other, true);
|
|
}
|
|
|
|
/**
|
|
* Divides this BigRational with {@code other}.
|
|
* Ensures result rational is coprime
|
|
*
|
|
* @param other long to divide by
|
|
* @return result of the division
|
|
*/
|
|
public BigRational divide(long other)
|
|
{
|
|
return divide(new BigRational(other));
|
|
}
|
|
|
|
/**
|
|
* Returns the signum function of this BigInteger.
|
|
*
|
|
* @return -1, 0 or 1 as the value of this BigInteger is negative, zero or positive.
|
|
*/
|
|
public int signum()
|
|
{
|
|
return num.signum() * den.signum();
|
|
}
|
|
|
|
/**
|
|
* Returns a BigRational whose value is {@code this} to the {@code exponent}.
|
|
*
|
|
* @param exponent exponent to which this number is raised
|
|
* @return {@code this} to the {@code exponent}
|
|
*/
|
|
public BigRational pow(int exponent)
|
|
{
|
|
BigInteger num;
|
|
BigInteger den;
|
|
if (exponent == 0) {
|
|
return ONE;
|
|
} else if (exponent > 0) {
|
|
num = this.num.pow(exponent);
|
|
den = this.den.pow(exponent);
|
|
} else { // exponent < 0
|
|
num = this.den.pow(exponent);
|
|
den = this.num.pow(exponent);
|
|
}
|
|
return new BigRational(num, den, false);
|
|
}
|
|
|
|
/**
|
|
* Compares {@code this} to {@code obj}.
|
|
* Returns true iff {@code obj} is a BigRational which represents
|
|
* the same rational number as {@code this}.
|
|
*
|
|
* @param obj object to compare to
|
|
* @return true iff {@code obj} is a BigRational which represents the same rational number as {@code this}.
|
|
*/
|
|
@Override
|
|
public boolean equals(Object obj)
|
|
{
|
|
if (!(obj instanceof BigRational)) {
|
|
return false;
|
|
}
|
|
BigRational other = (BigRational) obj;
|
|
if (isNaN()) {
|
|
return other.isNaN();
|
|
}
|
|
if (isInf()) {
|
|
return other.isInf();
|
|
}
|
|
if (isMInf()) {
|
|
return other.isMInf();
|
|
}
|
|
return this.num.equals(other.num) && this.den.equals(other.den);
|
|
}
|
|
|
|
/**
|
|
* Returns a hash code for this object.
|
|
*
|
|
* @return has code
|
|
*/
|
|
@Override
|
|
public int hashCode()
|
|
{
|
|
return 37 * num.hashCode() + den.hashCode();
|
|
}
|
|
|
|
/**
|
|
* Returns a double approximation of value represented by this BigRational.
|
|
* There are no guarantees on preciseness currently, so this function
|
|
* should be mainly used for plotting graphs, etc. Can return
|
|
* {@code Double.NaN}, {@code Double.POSITIVE_INFINITY},
|
|
* {@code Double.NEGATIVE_INFINITY} in case this BigRational represents
|
|
* not-a-number, positive infinity or negative infinitey respectively.
|
|
*
|
|
* @return a double approximation of the rational represented by this object
|
|
*/
|
|
public double doubleValue()
|
|
{
|
|
if (isNaN()) {
|
|
return Double.NaN;
|
|
} else if (isInf()) {
|
|
return Double.POSITIVE_INFINITY;
|
|
} else if (isMInf()) {
|
|
return Double.NEGATIVE_INFINITY;
|
|
} else if (isOne()) {
|
|
return 1.0;
|
|
} else if (isZero()) {
|
|
return 0.0;
|
|
}
|
|
BigInteger shiftedNum;
|
|
int signum = num.signum() * den.signum();
|
|
BigInteger posNum = (num.signum() == 1) ? num : num.negate();
|
|
BigInteger posDen = (den.signum() == 1) ? den : den.negate();
|
|
shiftedNum = posNum.shiftLeft(55);
|
|
BigInteger div = shiftedNum.divide(posDen);
|
|
if (shiftedNum.mod(posDen).multiply(BITWO).compareTo(posDen) == 1) {
|
|
div = div.add(BigInteger.ONE);
|
|
}
|
|
return signum * div.doubleValue() / Math.pow(2.0, 55);
|
|
}
|
|
|
|
/**
|
|
* Returns a string representation of this BigRational.
|
|
*
|
|
* @return string representation of this rational number
|
|
*/
|
|
@Override
|
|
public String toString()
|
|
{
|
|
if (isNaN()) {
|
|
return "NaN";
|
|
} else if (isInf()) {
|
|
return "Inf";
|
|
} else if (isMInf()) {
|
|
return "-Inf";
|
|
} else if (den.equals(BigInteger.ONE)) {
|
|
return num.toString();
|
|
} else {
|
|
return num + "/" + den;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Compares this BigRational to another BigRational other.
|
|
*
|
|
* @return -1, 0 or 1 as this BigRational is numerically less than, equal to, or greater than {@code other}.
|
|
*/
|
|
@Override
|
|
public int compareTo(BigRational other)
|
|
{
|
|
if (this.isInf()) {
|
|
if (other.isInf()) {
|
|
return 0;
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
if (this.isMInf()) {
|
|
if (other.isMInf()) {
|
|
return 0;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
return this.num.multiply(other.den).compareTo(other.num.multiply(this.den));
|
|
}
|
|
|
|
/**
|
|
* Compares this BigRational to the long other.
|
|
*
|
|
* @return -1, 0 or 1 as this BigRational is numerically less than, equal to, or greater than {@code other}.
|
|
*/
|
|
public int compareTo(long i)
|
|
{
|
|
return this.compareTo(new BigRational(i));
|
|
}
|
|
|
|
/**
|
|
* Return numerator of this BigRational as a BigInteger.
|
|
*
|
|
* @return numerator of this BigRational as a BigInteger
|
|
*/
|
|
public java.math.BigInteger getNum()
|
|
{
|
|
return num;
|
|
}
|
|
|
|
/**
|
|
* Return denominator of this BigRational as a BigInteger.
|
|
*
|
|
* @return denominator of this BigRational as a BigInteger
|
|
*/
|
|
public java.math.BigInteger getDen()
|
|
{
|
|
return den;
|
|
}
|
|
|
|
/**
|
|
* Return absolute value of this BigRational.
|
|
*
|
|
* @return absolute value of this BigRational
|
|
*/
|
|
public BigRational abs()
|
|
{
|
|
if (num.signum() == -1) {
|
|
return new BigRational(num.negate(), den);
|
|
} else {
|
|
return this;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return ceil(value), i.e., the smallest integer >= value.
|
|
* @throws PrismLangException for special values (NaN, infinity)
|
|
*/
|
|
public BigRational ceil() throws PrismLangException
|
|
{
|
|
if (isSpecial()) {
|
|
throw new PrismLangException("Can not compute ceil of " + this);
|
|
}
|
|
|
|
BigInteger[] divideAndRemainder = getNum().divideAndRemainder(getDen());
|
|
|
|
switch (divideAndRemainder[1].compareTo(BigInteger.ZERO)) {
|
|
case 0: // no remainder
|
|
case -1: // negative remainder: value was negative, so we ignore the remainder
|
|
return new BigRational(divideAndRemainder[0]);
|
|
case 1: // positive remainder: return next-largest integer
|
|
return new BigRational(divideAndRemainder[0].add(BigInteger.ONE));
|
|
default:
|
|
throw new IllegalStateException("Should not be reached");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return floor(value), i.e., the largest integer <= value.
|
|
* @throws PrismLangException for special values (NaN, infinity)
|
|
*/
|
|
public BigRational floor() throws PrismLangException
|
|
{
|
|
if (isSpecial()) {
|
|
throw new PrismLangException("Can not compute floor of " + this);
|
|
}
|
|
|
|
BigInteger[] divideAndRemainder = getNum().divideAndRemainder(getDen());
|
|
switch (divideAndRemainder[1].compareTo(BigInteger.ZERO)) {
|
|
case 0: // no remainder
|
|
case 1: // positive remainder: value was positive, so we ignore the remainder
|
|
return new BigRational(divideAndRemainder[0]);
|
|
case -1: // negative remainder: value was negative, return next-smallest integer
|
|
return new BigRational(divideAndRemainder[0].subtract(BigInteger.ONE));
|
|
default:
|
|
throw new IllegalStateException("Should not be reached");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns larger value of {@code this} and {@code other}.
|
|
*
|
|
* @param other rational number to compare to
|
|
* @return {@code other} if {@code other} this is larger than {@code this} and {@code this} otherwise
|
|
*/
|
|
public BigRational max(BigRational other)
|
|
{
|
|
if (this.compareTo(other) >= 0) {
|
|
return this;
|
|
} else {
|
|
return other;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns smaller value of {@code this} and {@code other}.
|
|
*
|
|
* @param other rational number to compare to
|
|
* @return {@code other} if {@code other} this is smaller than {@code this} and {@code this} otherwise
|
|
*/
|
|
public BigRational min(BigRational other)
|
|
{
|
|
if (this.compareTo(other) <= 0) {
|
|
return this;
|
|
} else {
|
|
return other;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns true iff this BigRational represents the number zero.
|
|
*
|
|
* @return true iff this BigRational represents the number zero
|
|
*/
|
|
public boolean isZero()
|
|
{
|
|
return num.equals(BigInteger.ZERO) && den.equals(BigInteger.ONE);
|
|
}
|
|
|
|
/**
|
|
* Returns true iff this BigRational represents the number one.
|
|
*
|
|
* @return true iff this BigRational represents the number one
|
|
*/
|
|
public boolean isOne()
|
|
{
|
|
return num.equals(BigInteger.ONE) && den.equals(BigInteger.ONE);
|
|
}
|
|
|
|
/**
|
|
* Returns true iff this BigRational represents the special value not-a-number.
|
|
*
|
|
* @return true iff this BigRational represents the special value not-a-number"
|
|
*/
|
|
public boolean isNaN()
|
|
{
|
|
return num.equals(BigInteger.ZERO) && den.equals(BigInteger.ZERO);
|
|
}
|
|
|
|
/**
|
|
* Returns true iff this BigRational represents positive infinity.
|
|
*
|
|
* @return true iff this BigRational represents positive infinity
|
|
*/
|
|
public boolean isInf()
|
|
{
|
|
return num.equals(BigInteger.ONE) && den.equals(BigInteger.ZERO);
|
|
}
|
|
|
|
/**
|
|
* Returns true iff this BigRational represents negative infinity.
|
|
*
|
|
* @return true iff this BigRational represents negative infinity
|
|
*/
|
|
public boolean isMInf()
|
|
{
|
|
return num.equals(BMONE) && den.equals(BigInteger.ZERO);
|
|
}
|
|
|
|
/**
|
|
* Returns true iff this object represents a true rational number.
|
|
* This excludes the values for not-a-number as well as positive
|
|
* and negative infinity.
|
|
*
|
|
* @return true iff this object represents a true rational number
|
|
*/
|
|
public boolean isRational()
|
|
{
|
|
return !isNaN() && !isInf() && !isMInf();
|
|
}
|
|
|
|
/**
|
|
* Returns true iff this object represents an integer, i.e.,
|
|
* is not not-a-number, positive, or negative infinity and
|
|
* the denominator is 1.
|
|
*
|
|
* @return true iff this object represents an integer
|
|
*/
|
|
public boolean isInteger()
|
|
{
|
|
return isRational() && getDen().equals(BigInteger.ONE);
|
|
}
|
|
|
|
/**
|
|
* Returns true iff this value represents a special number.
|
|
* This is the case if this is either not-a-number, positive or
|
|
* negative infinity.
|
|
*
|
|
* @return true iff this object represents a special number
|
|
*/
|
|
public boolean isSpecial()
|
|
{
|
|
return isNaN() || isInf() || isMInf();
|
|
}
|
|
|
|
/**
|
|
* Returns true if this value equals 1 or false if this value
|
|
* equals 0. In all other cases, a PrismLangException is thrown.
|
|
*/
|
|
public boolean toBoolean() throws PrismLangException
|
|
{
|
|
if (isOne())
|
|
return true;
|
|
if (isZero())
|
|
return false;
|
|
throw new PrismLangException("Conversion from BigRational to Boolean not possible, invalid value: " + this);
|
|
}
|
|
|
|
/**
|
|
* Returns the int representation of this value,
|
|
* if this value is an integer and if the integer can
|
|
* be represented by an int variable.
|
|
* In all other cases, a PrismLangException is thrown.
|
|
*/
|
|
public int toInt() throws PrismLangException
|
|
{
|
|
if (!isInteger()) {
|
|
throw new PrismLangException("Can not convert fractional number to int");
|
|
}
|
|
int value = getNum().intValue();
|
|
if (!getNum().equals(new BigInteger(Integer.toString(value)))) {
|
|
throw new PrismLangException("Can not convert BigInteger to int, value out of range");
|
|
}
|
|
return value;
|
|
}
|
|
}
|