901 lines
22 KiB
Java
901 lines
22 KiB
Java
package org.nevec.rjm;
|
|
|
|
import java.math.BigDecimal;
|
|
import java.math.BigInteger;
|
|
import java.math.MathContext;
|
|
import java.math.RoundingMode;
|
|
|
|
import it.cavallium.warppi.util.Error;
|
|
import it.cavallium.warppi.util.Errors;
|
|
|
|
/**
|
|
* Fractions (rational numbers). They are divisions of two BigInteger numbers,
|
|
* reduced to coprime numerator and denominator.
|
|
*
|
|
* @since 2006-06-25
|
|
* @author Richard J. Mathar
|
|
*/
|
|
public class Rational implements Cloneable, Comparable<Rational> {
|
|
/**
|
|
* numerator
|
|
*/
|
|
BigInteger a;
|
|
|
|
/**
|
|
* denominator, always larger than zero.
|
|
*/
|
|
BigInteger b;
|
|
|
|
/**
|
|
* The maximum and minimum value of a standard Java integer, 2^31.
|
|
*
|
|
* @since 2009-05-18
|
|
*/
|
|
static public BigInteger MAX_INT = new BigInteger("2147483647");
|
|
static public BigInteger MIN_INT = new BigInteger("-2147483648");
|
|
|
|
/**
|
|
* The constant 1.
|
|
*/
|
|
public static Rational ONE = new Rational(1, 1);
|
|
/**
|
|
* The constant 0.
|
|
*/
|
|
static public Rational ZERO = new Rational();
|
|
|
|
/**
|
|
* The constant 1/2
|
|
*
|
|
* @since 2010-05-25
|
|
*/
|
|
static public Rational HALF = new Rational(1, 2);
|
|
|
|
/**
|
|
* Default ctor, which represents the zero.
|
|
*
|
|
* @since 2007-11-17
|
|
*/
|
|
public Rational() {
|
|
a = BigInteger.ZERO;
|
|
b = BigInteger.ONE;
|
|
}
|
|
|
|
/**
|
|
* ctor from a numerator and denominator.
|
|
*
|
|
* @param a
|
|
* the numerator.
|
|
* @param b
|
|
* the denominator.
|
|
*/
|
|
public Rational(final BigInteger a, final BigInteger b) {
|
|
this.a = a;
|
|
this.b = b;
|
|
normalize();
|
|
}
|
|
|
|
/**
|
|
* ctor from a numerator.
|
|
*
|
|
* @param a
|
|
* the BigInteger.
|
|
*/
|
|
public Rational(final BigInteger a) {
|
|
this.a = a;
|
|
b = new BigInteger("1");
|
|
}
|
|
|
|
/**
|
|
* ctor from a numerator and denominator.
|
|
*
|
|
* @param a
|
|
* the numerator.
|
|
* @param b
|
|
* the denominator.
|
|
*/
|
|
public Rational(final int a, final int b) {
|
|
this(new BigInteger("" + a), new BigInteger("" + b));
|
|
}
|
|
|
|
/**
|
|
* ctor from an integer.
|
|
*
|
|
* @param n
|
|
* the integer to be represented by the new instance.
|
|
* @since 2010-07-18
|
|
*/
|
|
public Rational(final int n) {
|
|
this(n, 1);
|
|
}
|
|
|
|
/**
|
|
* ctor from a string representation.
|
|
*
|
|
* @param str
|
|
* the string. This either has a slash in it, separating two
|
|
* integers, or, if there is no slash, is representing the
|
|
* numerator with implicit denominator equal to 1. Warning: this
|
|
* does not yet test for a denominator equal to zero
|
|
*/
|
|
public Rational(final String str) {
|
|
this(str, 10);
|
|
}
|
|
|
|
/**
|
|
* ctor from a string representation in a specified base.
|
|
*
|
|
* @param str
|
|
* the string. This either has a slash in it, separating two
|
|
* integers, or, if there is no slash, is just representing the
|
|
* numerator.
|
|
* @param radix
|
|
* the number base for numerator and denominator Warning: this
|
|
* does not yet test for a denominator equal to zero
|
|
*/
|
|
public Rational(final String str, final int radix) {
|
|
final int hasslah = str.indexOf("/");
|
|
if (hasslah == -1) {
|
|
a = new BigInteger(str, radix);
|
|
b = new BigInteger("1", radix);
|
|
/* no normalization necessary here */
|
|
} else {
|
|
/*
|
|
* create numerator and denominator separately
|
|
*/
|
|
a = new BigInteger(str.substring(0, hasslah), radix);
|
|
b = new BigInteger(str.substring(hasslah + 1), radix);
|
|
normalize();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a copy.
|
|
*
|
|
* @since 2008-11-07
|
|
*/
|
|
@Override
|
|
public Rational clone() {
|
|
/*
|
|
* protected access means this does not work return new
|
|
* Rational(a.clone(), b.clone()) ;
|
|
*/
|
|
final BigInteger aclon = new BigInteger("" + a);
|
|
final BigInteger bclon = new BigInteger("" + b);
|
|
return new Rational(aclon, bclon);
|
|
} /* Rational.clone */
|
|
|
|
/**
|
|
* Multiply by another fraction.
|
|
*
|
|
* @param val
|
|
* a second rational number.
|
|
* @return the product of this with the val.
|
|
*/
|
|
public Rational multiply(final Rational val) {
|
|
final BigInteger num = a.multiply(val.a);
|
|
final BigInteger deno = b.multiply(val.b);
|
|
/*
|
|
* Normalization to an coprime format will be done inside the ctor() and
|
|
* is not duplicated here.
|
|
*/
|
|
return new Rational(num, deno);
|
|
} /* Rational.multiply */
|
|
|
|
/**
|
|
* Multiply by a BigInteger.
|
|
*
|
|
* @param val
|
|
* a second number.
|
|
* @return the product of this with the value.
|
|
*/
|
|
public Rational multiply(final BigInteger val) {
|
|
final Rational val2 = new Rational(val, BigInteger.ONE);
|
|
return multiply(val2);
|
|
} /* Rational.multiply */
|
|
|
|
/**
|
|
* Multiply by an integer.
|
|
*
|
|
* @param val
|
|
* a second number.
|
|
* @return the product of this with the value.
|
|
*/
|
|
public Rational multiply(final int val) {
|
|
final BigInteger tmp = new BigInteger("" + val);
|
|
return multiply(tmp);
|
|
} /* Rational.multiply */
|
|
|
|
/**
|
|
* Power to an integer.
|
|
*
|
|
* @param exponent
|
|
* the exponent.
|
|
* @return this value raised to the power given by the exponent. If the
|
|
* exponent is 0, the value 1 is returned.
|
|
*/
|
|
public Rational pow(final int exponent) {
|
|
if (exponent == 0) {
|
|
return new Rational(1, 1);
|
|
}
|
|
|
|
final BigInteger num = a.pow(Math.abs(exponent));
|
|
final BigInteger deno = b.pow(Math.abs(exponent));
|
|
if (exponent > 0) {
|
|
return new Rational(num, deno);
|
|
} else {
|
|
return new Rational(deno, num);
|
|
}
|
|
} /* Rational.pow */
|
|
|
|
/**
|
|
* Power to an integer.
|
|
*
|
|
* @param exponent
|
|
* the exponent.
|
|
* @return this value raised to the power given by the exponent. If the
|
|
* exponent is 0, the value 1 is returned.
|
|
* @throws Error
|
|
* @since 2009-05-18
|
|
*/
|
|
public Rational pow(final BigInteger exponent) throws Error {
|
|
/* test for overflow */
|
|
if (exponent.compareTo(Rational.MAX_INT) == 1) {
|
|
throw new Error(Errors.NUMBER_TOO_LARGE);
|
|
}
|
|
if (exponent.compareTo(Rational.MIN_INT) == -1) {
|
|
throw new Error(Errors.NUMBER_TOO_SMALL);
|
|
}
|
|
|
|
/* promote to the simpler interface above */
|
|
return pow(exponent.intValue());
|
|
} /* Rational.pow */
|
|
|
|
/**
|
|
* r-th root.
|
|
*
|
|
* @param r
|
|
* the inverse of the exponent. 2 for the square root, 3 for the
|
|
* third root etc
|
|
* @return this value raised to the inverse power given by the root
|
|
* argument, this^(1/r).
|
|
* @throws Error
|
|
* @since 2009-05-18
|
|
*/
|
|
public Rational root(final BigInteger r) throws Error {
|
|
/* test for overflow */
|
|
if (r.compareTo(Rational.MAX_INT) == 1) {
|
|
throw new Error(Errors.NUMBER_TOO_LARGE);
|
|
}
|
|
if (r.compareTo(Rational.MIN_INT) == -1) {
|
|
throw new Error(Errors.NUMBER_TOO_SMALL);
|
|
}
|
|
|
|
final int rthroot = r.intValue();
|
|
/* cannot pull root of a negative value with even-valued root */
|
|
if (compareTo(Rational.ZERO) == -1 && rthroot % 2 == 0) {
|
|
throw new Error(Errors.NEGATIVE_PARAMETER);
|
|
}
|
|
|
|
/*
|
|
* extract a sign such that we calculate |n|^(1/r), still r carrying any
|
|
* sign
|
|
*/
|
|
final boolean flipsign = compareTo(Rational.ZERO) == -1 && rthroot % 2 != 0 ? true : false;
|
|
|
|
/*
|
|
* delegate the main work to ifactor#root()
|
|
*/
|
|
final Ifactor num = new Ifactor(a.abs());
|
|
final Ifactor deno = new Ifactor(b);
|
|
final Rational resul = num.root(rthroot).divide(deno.root(rthroot));
|
|
if (flipsign) {
|
|
return resul.negate();
|
|
} else {
|
|
return resul;
|
|
}
|
|
} /* Rational.root */
|
|
|
|
/**
|
|
* Raise to a rational power.
|
|
*
|
|
* @param exponent
|
|
* The exponent.
|
|
* @return This value raised to the power given by the exponent. If the
|
|
* exponent is 0, the value 1 is returned.
|
|
* @throws Error
|
|
* @since 2009-05-18
|
|
*/
|
|
public Rational pow(final Rational exponent) throws Error {
|
|
if (exponent.a.compareTo(BigInteger.ZERO) == 0) {
|
|
return new Rational(1, 1);
|
|
}
|
|
|
|
/*
|
|
* calculate (a/b)^(exponent.a/exponent.b) as
|
|
* ((a/b)^exponent.a)^(1/exponent.b) = tmp^(1/exponent.b)
|
|
*/
|
|
final Rational tmp = pow(exponent.a);
|
|
return tmp.root(exponent.b);
|
|
} /* Rational.pow */
|
|
|
|
/**
|
|
* Divide by another fraction.
|
|
*
|
|
* @param val
|
|
* A second rational number.
|
|
* @return The value of this/val
|
|
* @throws Error
|
|
*/
|
|
public Rational divide(final Rational val) throws Error {
|
|
if (val.compareTo(Rational.ZERO) == 0) {
|
|
throw new Error(Errors.DIVISION_BY_ZERO);
|
|
}
|
|
final BigInteger num = a.multiply(val.b);
|
|
final BigInteger deno = b.multiply(val.a);
|
|
/*
|
|
* Reduction to a coprime format is done inside the ctor, and not
|
|
* repeated here.
|
|
*/
|
|
return new Rational(num, deno);
|
|
} /* Rational.divide */
|
|
|
|
/**
|
|
* Divide by an integer.
|
|
*
|
|
* @param val
|
|
* a second number.
|
|
* @return the value of this/val
|
|
* @throws Error
|
|
*/
|
|
public Rational divide(final BigInteger val) throws Error {
|
|
if (val.compareTo(BigInteger.ZERO) == 0) {
|
|
throw new Error(Errors.DIVISION_BY_ZERO);
|
|
}
|
|
final Rational val2 = new Rational(val, BigInteger.ONE);
|
|
return divide(val2);
|
|
} /* Rational.divide */
|
|
|
|
/**
|
|
* Divide by an integer.
|
|
*
|
|
* @param val
|
|
* A second number.
|
|
* @return The value of this/val
|
|
* @throws Error
|
|
*/
|
|
public Rational divide(final int val) throws Error {
|
|
if (val == 0) {
|
|
throw new Error(Errors.DIVISION_BY_ZERO);
|
|
}
|
|
final Rational val2 = new Rational(val, 1);
|
|
return divide(val2);
|
|
} /* Rational.divide */
|
|
|
|
/**
|
|
* Add another fraction.
|
|
*
|
|
* @param val
|
|
* The number to be added
|
|
* @return this+val.
|
|
*/
|
|
public Rational add(final Rational val) {
|
|
final BigInteger num = a.multiply(val.b).add(b.multiply(val.a));
|
|
final BigInteger deno = b.multiply(val.b);
|
|
return new Rational(num, deno);
|
|
} /* Rational.add */
|
|
|
|
/**
|
|
* Add another integer.
|
|
*
|
|
* @param val
|
|
* The number to be added
|
|
* @return this+val.
|
|
*/
|
|
public Rational add(final BigInteger val) {
|
|
final Rational val2 = new Rational(val, BigInteger.ONE);
|
|
return add(val2);
|
|
} /* Rational.add */
|
|
|
|
/**
|
|
* Add another integer.
|
|
*
|
|
* @param val
|
|
* The number to be added
|
|
* @return this+val.
|
|
* @since May 26 2010
|
|
*/
|
|
public Rational add(final int val) {
|
|
final BigInteger val2 = a.add(b.multiply(new BigInteger("" + val)));
|
|
return new Rational(val2, b);
|
|
} /* Rational.add */
|
|
|
|
/**
|
|
* Compute the negative.
|
|
*
|
|
* @return -this.
|
|
*/
|
|
public Rational negate() {
|
|
return new Rational(a.negate(), b);
|
|
} /* Rational.negate */
|
|
|
|
/**
|
|
* Subtract another fraction.
|
|
*
|
|
* @param val
|
|
* the number to be subtracted from this
|
|
* @return this - val.
|
|
*/
|
|
public Rational subtract(final Rational val) {
|
|
final Rational val2 = val.negate();
|
|
return add(val2);
|
|
} /* Rational.subtract */
|
|
|
|
/**
|
|
* Subtract an integer.
|
|
*
|
|
* @param val
|
|
* the number to be subtracted from this
|
|
* @return this - val.
|
|
*/
|
|
public Rational subtract(final BigInteger val) {
|
|
final Rational val2 = new Rational(val, BigInteger.ONE);
|
|
return subtract(val2);
|
|
} /* Rational.subtract */
|
|
|
|
/**
|
|
* Subtract an integer.
|
|
*
|
|
* @param val
|
|
* the number to be subtracted from this
|
|
* @return this - val.
|
|
*/
|
|
public Rational subtract(final int val) {
|
|
final Rational val2 = new Rational(val, 1);
|
|
return subtract(val2);
|
|
} /* Rational.subtract */
|
|
|
|
/**
|
|
* binomial (n choose m).
|
|
*
|
|
* @param n
|
|
* the numerator. Equals the size of the set to choose from.
|
|
* @param m
|
|
* the denominator. Equals the number of elements to select.
|
|
* @return the binomial coefficient.
|
|
* @since 2006-06-27
|
|
* @author Richard J. Mathar
|
|
* @throws Error
|
|
*/
|
|
public static Rational binomial(final Rational n, final BigInteger m) throws Error {
|
|
if (m.compareTo(BigInteger.ZERO) == 0) {
|
|
return Rational.ONE;
|
|
}
|
|
Rational bin = n;
|
|
for (BigInteger i = new BigInteger("2"); i.compareTo(m) != 1; i = i.add(BigInteger.ONE)) {
|
|
bin = bin.multiply(n.subtract(i.subtract(BigInteger.ONE))).divide(i);
|
|
}
|
|
return bin;
|
|
} /* Rational.binomial */
|
|
|
|
/**
|
|
* binomial (n choose m).
|
|
*
|
|
* @param n
|
|
* the numerator. Equals the size of the set to choose from.
|
|
* @param m
|
|
* the denominator. Equals the number of elements to select.
|
|
* @return the binomial coefficient.
|
|
* @since 2009-05-19
|
|
* @author Richard J. Mathar
|
|
* @throws Error
|
|
*/
|
|
public static Rational binomial(final Rational n, final int m) throws Error {
|
|
if (m == 0) {
|
|
return Rational.ONE;
|
|
}
|
|
Rational bin = n;
|
|
for (int i = 2; i <= m; i++) {
|
|
bin = bin.multiply(n.subtract(i - 1)).divide(i);
|
|
}
|
|
return bin;
|
|
} /* Rational.binomial */
|
|
|
|
/**
|
|
* Hankel's symbol (n,k)
|
|
*
|
|
* @param n
|
|
* the first parameter.
|
|
* @param k
|
|
* the second parameter, greater or equal to 0.
|
|
* @return Gamma(n+k+1/2)/k!/GAMMA(n-k+1/2)
|
|
* @since 2010-07-18
|
|
* @author Richard J. Mathar
|
|
* @throws Error
|
|
*/
|
|
public static Rational hankelSymb(final Rational n, final int k) throws Error {
|
|
if (k == 0) {
|
|
return Rational.ONE;
|
|
} else if (k < 0) {
|
|
throw new Error(Errors.NEGATIVE_PARAMETER);
|
|
}
|
|
Rational nkhalf = n.subtract(k).add(Rational.HALF);
|
|
nkhalf = nkhalf.Pochhammer(2 * k);
|
|
final Factorial f = new Factorial();
|
|
return nkhalf.divide(f.at(k));
|
|
} /* Rational.binomial */
|
|
|
|
/**
|
|
* Get the numerator.
|
|
*
|
|
* @return The numerator of the reduced fraction.
|
|
*/
|
|
public BigInteger numer() {
|
|
return a;
|
|
}
|
|
|
|
/**
|
|
* Get the denominator.
|
|
*
|
|
* @return The denominator of the reduced fraction.
|
|
*/
|
|
public BigInteger denom() {
|
|
return b;
|
|
}
|
|
|
|
/**
|
|
* Absolute value.
|
|
*
|
|
* @return The absolute (non-negative) value of this.
|
|
*/
|
|
public Rational abs() {
|
|
return new Rational(a.abs(), b.abs());
|
|
}
|
|
|
|
/**
|
|
* floor(): the nearest integer not greater than this.
|
|
*
|
|
* @return The integer rounded towards negative infinity.
|
|
*/
|
|
public BigInteger floor() {
|
|
/*
|
|
* is already integer: return the numerator
|
|
*/
|
|
if (b.compareTo(BigInteger.ONE) == 0) {
|
|
return a;
|
|
} else if (a.compareTo(BigInteger.ZERO) > 0) {
|
|
return a.divide(b);
|
|
} else {
|
|
return a.divide(b).subtract(BigInteger.ONE);
|
|
}
|
|
} /* Rational.floor */
|
|
|
|
/**
|
|
* ceil(): the nearest integer not smaller than this.
|
|
*
|
|
* @return The integer rounded towards positive infinity.
|
|
* @since 2010-05-26
|
|
*/
|
|
public BigInteger ceil() {
|
|
/*
|
|
* is already integer: return the numerator
|
|
*/
|
|
if (b.compareTo(BigInteger.ONE) == 0) {
|
|
return a;
|
|
} else if (a.compareTo(BigInteger.ZERO) > 0) {
|
|
return a.divide(b).add(BigInteger.ONE);
|
|
} else {
|
|
return a.divide(b);
|
|
}
|
|
} /* Rational.ceil */
|
|
|
|
/**
|
|
* Remove the fractional part.
|
|
*
|
|
* @return The integer rounded towards zero.
|
|
*/
|
|
public BigInteger trunc() {
|
|
/*
|
|
* is already integer: return the numerator
|
|
*/
|
|
if (b.compareTo(BigInteger.ONE) == 0) {
|
|
return a;
|
|
} else {
|
|
return a.divide(b);
|
|
}
|
|
} /* Rational.trunc */
|
|
|
|
/**
|
|
* Compares the value of this with another constant.
|
|
*
|
|
* @param val
|
|
* the other constant to compare with
|
|
* @return -1, 0 or 1 if this number is numerically less than, equal to, or
|
|
* greater than val.
|
|
*/
|
|
@Override
|
|
public int compareTo(final Rational val) {
|
|
/*
|
|
* Since we have always kept the denominators positive, simple
|
|
* cross-multiplying works without changing the sign.
|
|
*/
|
|
final BigInteger left = a.multiply(val.b);
|
|
final BigInteger right = val.a.multiply(b);
|
|
return left.compareTo(right);
|
|
} /* Rational.compareTo */
|
|
|
|
/**
|
|
* Compares the value of this with another constant.
|
|
*
|
|
* @param val
|
|
* the other constant to compare with
|
|
* @return -1, 0 or 1 if this number is numerically less than, equal to, or
|
|
* greater than val.
|
|
*/
|
|
public int compareTo(final BigInteger val) {
|
|
final Rational val2 = new Rational(val, BigInteger.ONE);
|
|
return compareTo(val2);
|
|
} /* Rational.compareTo */
|
|
|
|
/**
|
|
* Return a string in the format number/denom. If the denominator equals 1,
|
|
* print just the numerator without a slash.
|
|
*
|
|
* @return the human-readable version in base 10
|
|
*/
|
|
@Override
|
|
public String toString() {
|
|
if (b.compareTo(BigInteger.ONE) != 0) {
|
|
return a.toString() + "/" + b.toString();
|
|
} else {
|
|
return a.toString();
|
|
}
|
|
} /* Rational.toString */
|
|
|
|
/**
|
|
* Return a double value representation.
|
|
*
|
|
* @return The value with double precision.
|
|
* @since 2008-10-26
|
|
*/
|
|
public double doubleValue() {
|
|
/*
|
|
* To meet the risk of individual overflows of the exponents of a
|
|
* separate invocation a.doubleValue() or b.doubleValue(), we divide
|
|
* first in a BigDecimal environment and convert the result.
|
|
*/
|
|
final BigDecimal adivb = new BigDecimal(a).divide(new BigDecimal(b), MathContext.DECIMAL128);
|
|
return adivb.doubleValue();
|
|
} /* Rational.doubleValue */
|
|
|
|
/**
|
|
* Return a float value representation.
|
|
*
|
|
* @return The value with single precision.
|
|
* @since 2009-08-06
|
|
*/
|
|
public float floatValue() {
|
|
final BigDecimal adivb = new BigDecimal(a).divide(new BigDecimal(b), MathContext.DECIMAL128);
|
|
return adivb.floatValue();
|
|
} /* Rational.floatValue */
|
|
|
|
/**
|
|
* Return a representation as BigDecimal.
|
|
*
|
|
* @param mc
|
|
* the mathematical context which determines precision, rounding
|
|
* mode etc
|
|
* @return A representation as a BigDecimal floating point number.
|
|
* @since 2008-10-26
|
|
*/
|
|
public BigDecimal BigDecimalValue(final MathContext mc) {
|
|
/*
|
|
* numerator and denominator individually rephrased
|
|
*/
|
|
final BigDecimal n = new BigDecimal(a);
|
|
final BigDecimal d = new BigDecimal(b);
|
|
/*
|
|
* the problem with n.divide(d,mc) is that the apparent precision might
|
|
* be smaller than what is set by mc if the value has a precise
|
|
* truncated representation. 1/4 will appear as 0.25, independent of mc
|
|
*/
|
|
return BigDecimalMath.scalePrec(n.divide(d, mc), mc);
|
|
} /* Rational.BigDecimalValue */
|
|
|
|
/**
|
|
* Return a string in floating point format.
|
|
*
|
|
* @param digits
|
|
* The precision (number of digits)
|
|
* @return The human-readable version in base 10.
|
|
* @since 2008-10-25
|
|
*/
|
|
public String toFString(final int digits) {
|
|
if (b.compareTo(BigInteger.ONE) != 0) {
|
|
final MathContext mc = new MathContext(digits, RoundingMode.DOWN);
|
|
final BigDecimal f = new BigDecimal(a).divide(new BigDecimal(b), mc);
|
|
return f.toString();
|
|
} else {
|
|
return a.toString();
|
|
}
|
|
} /* Rational.toFString */
|
|
|
|
/**
|
|
* Compares the value of this with another constant.
|
|
*
|
|
* @param val
|
|
* The other constant to compare with
|
|
* @return The arithmetic maximum of this and val.
|
|
* @since 2008-10-19
|
|
*/
|
|
public Rational max(final Rational val) {
|
|
if (compareTo(val) > 0) {
|
|
return this;
|
|
} else {
|
|
return val;
|
|
}
|
|
} /* Rational.max */
|
|
|
|
/**
|
|
* Compares the value of this with another constant.
|
|
*
|
|
* @param val
|
|
* The other constant to compare with
|
|
* @return The arithmetic minimum of this and val.
|
|
* @since 2008-10-19
|
|
*/
|
|
public Rational min(final Rational val) {
|
|
if (compareTo(val) < 0) {
|
|
return this;
|
|
} else {
|
|
return val;
|
|
}
|
|
} /* Rational.min */
|
|
|
|
/**
|
|
* Compute Pochhammer's symbol (this)_n.
|
|
*
|
|
* @param n
|
|
* The number of product terms in the evaluation.
|
|
* @return Gamma(this+n)/Gamma(this) = this*(this+1)*...*(this+n-1).
|
|
* @since 2008-10-25
|
|
*/
|
|
public Rational Pochhammer(final BigInteger n) {
|
|
if (n.compareTo(BigInteger.ZERO) < 0) {
|
|
return null;
|
|
} else if (n.compareTo(BigInteger.ZERO) == 0) {
|
|
return Rational.ONE;
|
|
} else {
|
|
/*
|
|
* initialize results with the current value
|
|
*/
|
|
Rational res = new Rational(a, b);
|
|
BigInteger i = BigInteger.ONE;
|
|
for (; i.compareTo(n) < 0; i = i.add(BigInteger.ONE)) {
|
|
res = res.multiply(add(i));
|
|
}
|
|
return res;
|
|
}
|
|
} /* Rational.pochhammer */
|
|
|
|
/**
|
|
* Compute pochhammer's symbol (this)_n.
|
|
*
|
|
* @param n
|
|
* The number of product terms in the evaluation.
|
|
* @return Gamma(this+n)/GAMMA(this).
|
|
* @since 2008-11-13
|
|
*/
|
|
public Rational Pochhammer(final int n) {
|
|
return Pochhammer(new BigInteger("" + n));
|
|
} /* Rational.pochhammer */
|
|
|
|
/**
|
|
* True if the value is integer. Equivalent to the indication whether a
|
|
* conversion to an integer can be exact.
|
|
*
|
|
* @since 2010-05-26
|
|
*/
|
|
public boolean isBigInteger() {
|
|
return b.abs().compareTo(BigInteger.ONE) == 0;
|
|
} /* Rational.isBigInteger */
|
|
|
|
/**
|
|
* True if the value is integer and in the range of the standard integer.
|
|
* Equivalent to the indication whether a conversion to an integer can be
|
|
* exact.
|
|
*
|
|
* @since 2010-05-26
|
|
*/
|
|
public boolean isInteger() {
|
|
if (!isBigInteger()) {
|
|
return false;
|
|
}
|
|
return a.compareTo(Rational.MAX_INT) <= 0 && a.compareTo(Rational.MIN_INT) >= 0;
|
|
} /* Rational.isInteger */
|
|
|
|
/**
|
|
* Conversion to an integer value, if this can be done exactly.
|
|
*
|
|
* @throws Error
|
|
*
|
|
* @since 2011-02-13
|
|
*/
|
|
int intValue() throws Error {
|
|
if (!isInteger()) {
|
|
throw new Error(Errors.CONVERSION_ERROR);
|
|
}
|
|
return a.intValue();
|
|
}
|
|
|
|
/**
|
|
* Conversion to a BigInteger value, if this can be done exactly.
|
|
*
|
|
* @throws Error
|
|
*
|
|
* @since 2012-03-02
|
|
*/
|
|
BigInteger BigIntegerValue() throws Error {
|
|
if (!isBigInteger()) {
|
|
throw new Error(Errors.CONVERSION_ERROR);
|
|
}
|
|
return a;
|
|
}
|
|
|
|
/**
|
|
* True if the value is a fraction of two integers in the range of the
|
|
* standard integer.
|
|
*
|
|
* @since 2010-05-26
|
|
*/
|
|
public boolean isIntegerFrac() {
|
|
return a.compareTo(Rational.MAX_INT) <= 0 && a.compareTo(Rational.MIN_INT) >= 0 && b.compareTo(Rational.MAX_INT) <= 0 && b.compareTo(Rational.MIN_INT) >= 0;
|
|
} /* Rational.isIntegerFrac */
|
|
|
|
/**
|
|
* The sign: 1 if the number is >0, 0 if ==0, -1 if <0
|
|
*
|
|
* @return the signum of the value.
|
|
* @since 2010-05-26
|
|
*/
|
|
public int signum() {
|
|
return b.signum() * a.signum();
|
|
} /* Rational.signum */
|
|
|
|
/**
|
|
* Common lcm of the denominators of a set of rational values.
|
|
*
|
|
* @param vals
|
|
* The list/set of the rational values.
|
|
* @return LCM(denom of first, denom of second, ..,denom of last)
|
|
* @since 2012-03-02
|
|
*/
|
|
static public BigInteger lcmDenom(final Rational[] vals) {
|
|
BigInteger l = BigInteger.ONE;
|
|
for (final Rational val : vals) {
|
|
l = BigIntegerMath.lcm(l, val.b);
|
|
}
|
|
return l;
|
|
} /* Rational.lcmDenom */
|
|
|
|
/**
|
|
* Normalize to coprime numerator and denominator. Also copy a negative sign
|
|
* of the denominator to the numerator.
|
|
*
|
|
* @since 2008-10-19
|
|
*/
|
|
protected void normalize() {
|
|
/*
|
|
* compute greatest common divisor of numerator and denominator
|
|
*/
|
|
final BigInteger g = a.gcd(b);
|
|
if (g.compareTo(BigInteger.ONE) > 0) {
|
|
a = a.divide(g);
|
|
b = b.divide(g);
|
|
}
|
|
if (b.compareTo(BigInteger.ZERO) == -1) {
|
|
a = a.negate();
|
|
b = b.negate();
|
|
}
|
|
} /* Rational.normalize */
|
|
} /* Rational */
|