diff --git a/prism/src/param/BigRational.java b/prism/src/param/BigRational.java index daa0e58f..d0a6bafa 100644 --- a/prism/src/param/BigRational.java +++ b/prism/src/param/BigRational.java @@ -41,8 +41,11 @@ import prism.PrismLangException; * * @author Ernst Moritz Hahn (University of Oxford) */ -public final class BigRational implements Comparable +public final class BigRational extends Number implements Comparable { + /** Serial version for serialisation */ + private static final long serialVersionUID = 8273185089413305187L; + /** the BigInteger "-1" */ private final static BigInteger BMONE = BigInteger.ONE.negate(); /** the BigInteger "2" */ @@ -560,6 +563,87 @@ public final class BigRational implements Comparable return signum * div.doubleValue() / Math.pow(2.0, 55); } + /** + * Returns the value of the specified number as an {@code int}, + * which may involve rounding or truncation. + *
+ * Note: In contrast to the standard Number.intValue() behaviour, + * this implementation throws an Arithmetic exception if the underlying + * rational number is not an integer or if representing as an {@code int} + * overflows. + *
+ * Positive and negative infinity are mapped to Integer.MAX_VALUE and Integer.MIN_VALUE, + * respectively, NaN is mapped to 0 (per the Java Language Specification). + * + * @return the numeric value represented by this object after conversion + * to type {@code int}. + */ + @Override + public int intValue() + { + if (isSpecial()) { + if (isInf()) return Integer.MAX_VALUE; + if (isMInf()) return Integer.MIN_VALUE; + if (isNaN()) return 0; // per Java Language Specification + } + + // TODO JK: In case of fraction / overflow, this method should not throw an + // exception but return some imprecise result. We are conservative here. + // In the future, it may make sense to have an intValueExact (similar to BigInteger) + if (!isInteger()) { + throw new ArithmeticException("Can not convert fractional number to int"); + } + int value = getNum().intValue(); + if (!getNum().equals(new BigInteger(Integer.toString(value)))) { + throw new ArithmeticException("Can not convert BigInteger to int, value " + this + " out of range"); + } + return value; + } + + /** + * Returns the value of the specified number as a {@code long}, + * which may involve rounding or truncation. + *
+ * Note: In contrast to the standard Number.longValue() behaviour, + * this implementation throws an Arithmetic exception if the underlying + * rational number is not an integer or if representing as a {@code long} + * overflows. + *
+ * Positive and negative infinity are mapped to Long.MAX_VALUE and Long.MIN_VALUE, + * respectively, NaN is mapped to 0 (per the Java Language Specification). + * + * @return the numeric value represented by this object after conversion + * to type {@code int}. + */ + @Override + public long longValue() + { + if (isSpecial()) { + if (isInf()) return Long.MAX_VALUE; + if (isMInf()) return Long.MIN_VALUE; + if (isNaN()) return 0; // per Java Language Specification + } + + // TODO JK: In case of fraction / overflow, this method should not throw an + // exception but return some imprecise result. We are conservative here. In the future, + // it may make sense to have an intValueExact (similar to BigInteger) + if (!isInteger()) { + throw new ArithmeticException("Can not convert fractional number to long"); + } + long value = getNum().longValue(); + if (!getNum().equals(new BigInteger(Long.toString(value)))) { + throw new ArithmeticException("Can not convert BigInteger to long, value " + this + " out of range"); + } + return value; + } + + @Override + public float floatValue() + { + // TODO JK: Better precision? + return (float)doubleValue(); + } + /** * Returns a string representation of this BigRational. *