/*- * * * Copyright 2015 Skymind,Inc. * * * * Licensed under the Apache License, Version 2.0 (the "License"); * * you may not use this file except in compliance with the License. * * You may obtain a copy of the License at * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software * * distributed under the License is distributed on an "AS IS" BASIS, * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * * limitations under the License. * * */ package org.nd4j.linalg.util; /* * To change this template, choose Tools | Templates and open the template in the editor. */ // package org.nevec.rjm ; import java.math.BigDecimal; import java.math.BigInteger; import java.math.MathContext; import java.math.RoundingMode; /** * Fractions (rational numbers). * They are divisions of two BigInteger variables, reduced to greatest * common divisors of 1. */ class Rational implements Cloneable { /* The maximum and minimum value of a standard Java integer, 2^31. */ static BigInteger MAX_INT = BigInteger.valueOf(Integer.MAX_VALUE); static BigInteger MIN_INT = BigInteger.valueOf(Integer.MIN_VALUE); static Rational ONE = new Rational(1, 1); static Rational ZERO = new Rational(); /** * numerator */ BigInteger a; /** * denominator */ BigInteger b; /** * Default ctor, which represents the zero. */ public Rational() { a = BigInteger.ZERO; b = BigInteger.ONE; } /** * ctor from a numerator and denominator. * * @param a the numerator. * @param b the denominator. */ public Rational(BigInteger a, BigInteger b) { this.a = a; this.b = b; normalize(); } /** * ctor from a numerator. * * @param a the BigInteger. */ public Rational(BigInteger a) { this.a = a; b = BigInteger.valueOf(1); } /** * ctor from a numerator and denominator. * * @param a the numerator. * @param b the denominator. */ public Rational(int a, int b) { this(BigInteger.valueOf(a), BigInteger.valueOf(b)); } /** * 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(String str) throws NumberFormatException { 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 * 5 */ public Rational(String str, int radix) throws NumberFormatException { 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(); } } /** * 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. */ public static Rational binomial(Rational n, BigInteger m) { if (m.compareTo(BigInteger.ZERO) == 0) { return Rational.ONE; } Rational bin = n; for (BigInteger i = BigInteger.valueOf(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. */ public static Rational binomial(Rational n, int m) { 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 */ /** * Create a copy. */ @Override public Rational clone() { /* protected access means this does not work * return new Rational(a.clone(), b.clone()) ; */ BigInteger aclon = new BigInteger("" + a); 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) { BigInteger num = a.multiply(val.a); 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) { 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) { BigInteger tmp = BigInteger.valueOf(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(int exponent) { if (exponent == 0) { return new Rational(1, 1); } BigInteger num = a.pow(Math.abs(exponent)); 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. */ public Rational pow(BigInteger exponent) throws NumberFormatException { /* test for overflow */ if (exponent.compareTo(MAX_INT) == 1) { throw new NumberFormatException("Exponent " + exponent.toString() + " too large."); } if (exponent.compareTo(MIN_INT) == -1) { throw new NumberFormatException("Exponent " + exponent.toString() + " too small."); } /* promote to the simpler interface above */ return pow(exponent.intValue()); } /* Rational.pow */ /** * Divide by another fraction. * * @param val A second rational number. * @return The value of this/val */ public Rational divide(final Rational val) { BigInteger num = a.multiply(val.b); 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 */ public Rational divide(BigInteger val) { 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 */ public Rational divide(int val) { 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(Rational val) { BigInteger num = a.multiply(val.b).add(b.multiply(val.a)); 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(BigInteger val) { Rational val2 = new Rational(val, BigInteger.ONE); return (add(val2)); } /* Rational.add */ /** * Compute the negative. * * @return -this. */ public Rational negate() { return (new Rational(a.negate(), b)); } /* Rational.negate */ /** * Subtract another fraction. * 7 * * @param val the number to be subtracted from this * @return this - val. */ public Rational subtract(Rational val) { 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(BigInteger val) { 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(int val) { Rational val2 = new Rational(val, 1); return (subtract(val2)); } /* Rational.subtract */ /** * 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 */ /** * 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. */ 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. */ 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 converst the result. */ 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. */ public float floatValue() { 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. */ public BigDecimal BigDecimalValue(MathContext mc) { /* numerator and denominator individually rephrased */ BigDecimal n = new BigDecimal(a); BigDecimal d = new BigDecimal(b); return n.divide(d, mc); } /* Rational.BigDecimnalValue */ /** * Return a string in floating point format. * * @param digits The precision (number of digits) * @return The human-readable version in base 10. */ public String toFString(int digits) { if (b.compareTo(BigInteger.ONE) != 0) { MathContext mc = new MathContext(digits, RoundingMode.DOWN); 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. */ 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. */ 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). */ 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). */ public Rational Pochhammer(int n) { return Pochhammer(BigInteger.valueOf(n)); } /* Rational.pochhammer */ /** * Normalize to coprime numerator and denominator. * Also copy a negative sign of the denominator to the numerator. */ 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 */