All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ch.obermuhlner.math.big.BigRational Maven / Gradle / Ivy

There is a newer version: 2.3.2
Show newest version
package ch.obermuhlner.math.big;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;

/**
 * A rational number represented as a quotient of two values.
 * 
 * 

Basic calculations with rational numbers (+ - * /) have no loss of precision. * This allows to use {@link BigRational} as a replacement for {@link BigDecimal} if absolute accuracy is desired.

* *

Wikipedia: Rational number

* *

The values are internally stored as {@link BigDecimal} (for performance optimizations) but represented * as {@link BigInteger} (for mathematical correctness) * when accessed with {@link #getNumeratorBigInteger()} and {@link #getDenominatorBigInteger()}.

* *

The following basic calculations have no loss of precision:

*
    *
  • {@link #add(BigRational)}
  • *
  • {@link #subtract(BigRational)}
  • *
  • {@link #multiply(BigRational)}
  • *
  • {@link #divide(BigRational)}
  • *
  • {@link #pow(int)}
  • *
* *

The following calculations are special cases of the ones listed above and have no loss of precision:

*
    *
  • {@link #negate()}
  • *
  • {@link #reciprocal()}
  • *
  • {@link #increment()}
  • *
  • {@link #decrement()}
  • *
* *

Any {@link BigRational} value can be converted into an arbitrary {@link #withPrecision(int) precision} (number of significant digits) * or {@link #withScale(int) scale} (number of digits after the decimal point).

*/ public class BigRational implements Comparable { /** * The value 0 as {@link BigRational}. */ public static final BigRational ZERO = new BigRational(0); /** * The value 1 as {@link BigRational}. */ public static final BigRational ONE = new BigRational(1); /** * The value 2 as {@link BigRational}. */ public static final BigRational TWO = new BigRational(2); /** * The value 10 as {@link BigRational}. */ public static final BigRational TEN = new BigRational(10); private final BigDecimal numerator; private final BigDecimal denominator; private BigRational(int value) { this(BigDecimal.valueOf(value), BigDecimal.ONE); } private BigRational(BigDecimal num, BigDecimal denom) { BigDecimal n = num; BigDecimal d = denom; if (d.signum() == 0) { throw new ArithmeticException("Divide by zero"); } if (d.signum() < 0) { n = n.negate(); d = d.negate(); } numerator = n; denominator = d; } /** * Returns the numerator of this rational number as BigInteger. * * @return the numerator as BigInteger */ public BigInteger getNumeratorBigInteger() { return numerator.toBigInteger(); } /** * Returns the numerator of this rational number as BigDecimal. * * @return the numerator as BigDecimal */ public BigDecimal getNumerator() { return numerator; } /** * Returns the denominator of this rational number as BigInteger. * *

Guaranteed to not be 0.

*

Guaranteed to be positive.

* * @return the denominator as BigInteger */ public BigInteger getDenominatorBigInteger() { return denominator.toBigInteger(); } /** * Returns the denominator of this rational number as BigDecimal. * *

Guaranteed to not be 0.

*

Guaranteed to be positive.

* * @return the denominator as BigDecimal */ public BigDecimal getDenominator() { return denominator; } /** * Reduces this rational number to the smallest numerator/denominator with the same value. * * @return the reduced rational number */ public BigRational reduce() { BigInteger n = numerator.toBigInteger(); BigInteger d = denominator.toBigInteger(); BigInteger gcd = n.gcd(d); n = n.divide(gcd); d = d.divide(gcd); return valueOf(n, d); } /** * Returns the integer part of this rational number. * *

Examples:

*
    *
  • BigRational.valueOf(3.5).integerPart() returns BigRational.valueOf(3)
  • *
* * @return the integer part of this rational number */ public BigRational integerPart() { return of(numerator.subtract(numerator.remainder(denominator)), denominator); } /** * Returns the fraction part of this rational number. * *

Examples:

*
    *
  • BigRational.valueOf(3.5).integerPart() returns BigRational.valueOf(0.5)
  • *
* * @return the fraction part of this rational number */ public BigRational fractionPart() { return of(numerator.remainder(denominator), denominator); } /** * Negates this rational number (inverting the sign). * *

The result has no loss of precision.

* *

Examples:

*
    *
  • BigRational.valueOf(3.5).negate() returns BigRational.valueOf(-3.5)
  • *
* * @return the negated rational number */ public BigRational negate() { if (isZero()) { return this; } return of(numerator.negate(), denominator); } /** * Calculates the reciprocal of this rational number (1/x). * *

The result has no loss of precision.

* *

Examples:

*
    *
  • BigRational.valueOf(0.5).reciprocal() returns BigRational.valueOf(2)
  • *
  • BigRational.valueOf(-2).reciprocal() returns BigRational.valueOf(-0.5)
  • *
* * @return the reciprocal rational number * @throws ArithmeticException if this number is 0 (division by zero) */ public BigRational reciprocal() { return of(denominator, numerator); } /** * Returns the absolute value of this rational number. * *

The result has no loss of precision.

* *

Examples:

*
    *
  • BigRational.valueOf(-2).abs() returns BigRational.valueOf(2)
  • *
  • BigRational.valueOf(2).abs() returns BigRational.valueOf(2)
  • *
* * @return the absolute rational number (positive, or 0 if this rational is 0) */ public BigRational abs() { return isPositive() ? this : negate(); } /** * Returns the signum function of this rational number. * * @return -1, 0 or 1 as the value of this rational number is negative, zero or positive. */ public int signum() { return numerator.signum(); } /** * Calculates the increment of this rational number (+ 1). * *

This is functionally identical to * this.add(BigRational.ONE) * but slightly faster.

* *

The result has no loss of precision.

* * @return the incremented rational number */ public BigRational increment() { return of(numerator.add(denominator), denominator); } /** * Calculates the decrement of this rational number (- 1). * *

This is functionally identical to * this.subtract(BigRational.ONE) * but slightly faster.

* *

The result has no loss of precision.

* * @return the decremented rational number */ public BigRational decrement() { return of(numerator.subtract(denominator), denominator); } /** * Calculates the addition (+) of this rational number and the specified argument. * *

The result has no loss of precision.

* * @param value the rational number to add * @return the resulting rational number */ public BigRational add(BigRational value) { if (denominator.equals(value.denominator)) { return of(numerator.add(value.numerator), denominator); } BigDecimal n = numerator.multiply(value.denominator).add(value.numerator.multiply(denominator)); BigDecimal d = denominator.multiply(value.denominator); return of(n, d); } private BigRational add(BigDecimal value) { return of(numerator.add(value.multiply(denominator)), denominator); } /** * Calculates the addition (+) of this rational number and the specified argument. * *

This is functionally identical to * this.add(BigRational.valueOf(value)) * but slightly faster.

* *

The result has no loss of precision.

* * @param value the {@link BigInteger} to add * @return the resulting rational number */ public BigRational add(BigInteger value) { if (value.equals(BigInteger.ZERO)) { return this; } return add(new BigDecimal(value)); } /** * Calculates the addition (+) of this rational number and the specified argument. * *

This is functionally identical to * this.add(BigRational.valueOf(value)) * but slightly faster.

* *

The result has no loss of precision.

* * @param value the int value to add * @return the resulting rational number */ public BigRational add(int value) { if (value == 0) { return this; } return add(BigInteger.valueOf(value)); } /** * Calculates the subtraction (-) of this rational number and the specified argument. * *

The result has no loss of precision.

* * @param value the rational number to subtract * @return the resulting rational number */ public BigRational subtract(BigRational value) { if (denominator.equals(value.denominator)) { return of(numerator.subtract(value.numerator), denominator); } BigDecimal n = numerator.multiply(value.denominator).subtract(value.numerator.multiply(denominator)); BigDecimal d = denominator.multiply(value.denominator); return of(n, d); } private BigRational subtract(BigDecimal value) { return of(numerator.subtract(value.multiply(denominator)), denominator); } /** * Calculates the subtraction (-) of this rational number and the specified argument. * *

This is functionally identical to * this.subtract(BigRational.valueOf(value)) * but slightly faster.

* *

The result has no loss of precision.

* * @param value the {@link BigInteger} to subtract * @return the resulting rational number */ public BigRational subtract(BigInteger value) { if (value.equals(BigInteger.ZERO)) { return this; } return subtract(new BigDecimal(value)); } /** * Calculates the subtraction (-) of this rational number and the specified argument. * *

This is functionally identical to * this.subtract(BigRational.valueOf(value)) * but slightly faster.

* *

The result has no loss of precision.

* * @param value the int value to subtract * @return the resulting rational number */ public BigRational subtract(int value) { if (value == 0) { return this; } return subtract(BigInteger.valueOf(value)); } /** * Calculates the multiplication (*) of this rational number and the specified argument. * *

The result has no loss of precision.

* * @param value the rational number to multiply * @return the resulting rational number */ public BigRational multiply(BigRational value) { if (isZero() || value.isZero()) { return ZERO; } if (equals(ONE)) { return value; } if (value.equals(ONE)) { return this; } BigDecimal n = numerator.multiply(value.numerator); BigDecimal d = denominator.multiply(value.denominator); return of(n, d); } // private, because we want to hide that we use BigDecimal internally private BigRational multiply(BigDecimal value) { BigDecimal n = numerator.multiply(value); BigDecimal d = denominator; return of(n, d); } /** * Calculates the multiplication (*) of this rational number and the specified argument. * *

This is functionally identical to * this.multiply(BigRational.valueOf(value)) * but slightly faster.

* *

The result has no loss of precision.

* * @param value the {@link BigInteger} to multiply * @return the resulting rational number */ public BigRational multiply(BigInteger value) { if (isZero() || value.signum() == 0) { return ZERO; } if (equals(ONE)) { return valueOf(value); } if (value.equals(BigInteger.ONE)) { return this; } return multiply(new BigDecimal(value)); } /** * Calculates the multiplication (*) of this rational number and the specified argument. * *

This is functionally identical to * this.multiply(BigRational.valueOf(value)) * but slightly faster.

* *

The result has no loss of precision.

* * @param value the int value to multiply * @return the resulting rational number */ public BigRational multiply(int value) { return multiply(BigInteger.valueOf(value)); } /** * Calculates the division (/) of this rational number and the specified argument. * *

The result has no loss of precision.

* * @param value the rational number to divide (0 is not allowed) * @return the resulting rational number * @throws ArithmeticException if the argument is 0 (division by zero) */ public BigRational divide(BigRational value) { if (value.equals(ONE)) { return this; } BigDecimal n = numerator.multiply(value.denominator); BigDecimal d = denominator.multiply(value.numerator); return of(n, d); } private BigRational divide(BigDecimal value) { BigDecimal n = numerator; BigDecimal d = denominator.multiply(value); return of(n, d); } /** * Calculates the division (/) of this rational number and the specified argument. * *

This is functionally identical to * this.divide(BigRational.valueOf(value)) * but slightly faster.

* *

The result has no loss of precision.

* * @param value the {@link BigInteger} to divide (0 is not allowed) * @return the resulting rational number * @throws ArithmeticException if the argument is 0 (division by zero) */ public BigRational divide(BigInteger value) { if (value.equals(BigInteger.ONE)) { return this; } return divide(new BigDecimal(value)); } /** * Calculates the division (/) of this rational number and the specified argument. * *

This is functionally identical to * this.divide(BigRational.valueOf(value)) * but slightly faster.

* *

The result has no loss of precision.

* * @param value the int value to divide (0 is not allowed) * @return the resulting rational number * @throws ArithmeticException if the argument is 0 (division by zero) */ public BigRational divide(int value) { return divide(BigInteger.valueOf(value)); } /** * Returns whether this rational number is zero. * * @return true if this rational number is zero (0), false if it is not zero */ public boolean isZero() { return numerator.signum() == 0; } private boolean isPositive() { return numerator.signum() > 0; } /** * Returns whether this rational number is an integer number without fraction part. * * @return true if this rational number is an integer number, false if it has a fraction part */ public boolean isInteger() { return isIntegerInternal() || reduce().isIntegerInternal(); } /** * Returns whether this rational number is an integer number without fraction part. * *

Will return false if this number is not reduced to the integer representation yet (e.g. 4/4 or 4/2)

* * @return true if this rational number is an integer number, false if it has a fraction part * @see #isInteger() */ private boolean isIntegerInternal() { return denominator.compareTo(BigDecimal.ONE) == 0; } /** * Calculates this rational number to the power (xy) of the specified argument. * *

The result has no loss of precision.

* * @param exponent exponent to which this rational number is to be raised * @return the resulting rational number */ public BigRational pow(int exponent) { if (exponent == 0) { return ONE; } if (exponent == 1) { return this; } final BigInteger n; final BigInteger d; if (exponent > 0) { n = numerator.toBigInteger().pow(exponent); d = denominator.toBigInteger().pow(exponent); } else { n = denominator.toBigInteger().pow(-exponent); d = numerator.toBigInteger().pow(-exponent); } return valueOf(n, d); } /** * Finds the minimum (smaller) of two rational numbers. * * @param value the rational number to compare with * @return the minimum rational number, either this or the argument value */ private BigRational min(BigRational value) { return compareTo(value) <= 0 ? this : value; } /** * Finds the maximum (larger) of two rational numbers. * * @param value the rational number to compare with * @return the minimum rational number, either this or the argument value */ private BigRational max(BigRational value) { return compareTo(value) >= 0 ? this : value; } /** * Returns a rational number with approximatively this value and the specified precision. * * @param precision the precision (number of significant digits) of the calculated result, or 0 for unlimited precision * @return the calculated rational number with the specified precision */ public BigRational withPrecision(int precision) { return valueOf(toBigDecimal(new MathContext(precision))); } /** * Returns a rational number with approximatively this value and the specified scale. * * @param scale the scale (number of digits after the decimal point) of the calculated result * @return the calculated rational number with the specified scale */ public BigRational withScale(int scale) { return valueOf(toBigDecimal().setScale(scale, RoundingMode.HALF_UP)); } private static int countDigits(BigInteger number) { double factor = Math.log(2) / Math.log(10); int digitCount = (int) (factor * number.bitLength() + 1); if (BigInteger.TEN.pow(digitCount - 1).compareTo(number) > 0) { return digitCount - 1; } return digitCount; } // TODO what is precision of a rational? private int precision() { return countDigits(numerator.toBigInteger()) + countDigits(denominator.toBigInteger()); } /** * Returns this rational number as a double value. * * @return the double value */ public double toDouble() { // TODO best accuracy or maybe bigDecimalValue().doubleValue() is better? return numerator.doubleValue() / denominator.doubleValue(); } /** * Returns this rational number as a float value. * * @return the float value */ public float toFloat() { return numerator.floatValue() / denominator.floatValue(); } /** * Returns this rational number as a {@link BigDecimal}. * * @return the {@link BigDecimal} value */ public BigDecimal toBigDecimal() { int precision = Math.max(precision(), MathContext.DECIMAL128.getPrecision()); return toBigDecimal(new MathContext(precision)); } /** * Returns this rational number as a {@link BigDecimal} with the precision specified by the {@link MathContext}. * * @param mc the {@link MathContext} specifying the precision of the calculated result * @return the {@link BigDecimal} */ public BigDecimal toBigDecimal(MathContext mc) { return numerator.divide(denominator, mc); } @Override public int compareTo(BigRational other) { if (this == other) { return 0; } return numerator.multiply(other.denominator).compareTo(denominator.multiply(other.numerator)); } @Override public int hashCode() { if (isZero()) { return 0; } return numerator.hashCode() + denominator.hashCode(); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (!(obj instanceof BigRational)) { return false; } BigRational other = (BigRational) obj; if (!numerator.equals(other.numerator)) { return false; } return denominator.equals(other.denominator); } @Override public String toString() { if (isZero()) { return "0"; } if (isIntegerInternal()) { return numerator.toString(); } return toBigDecimal().toString(); } /** * Returns a plain string representation of this rational number without any exponent. * * @return the plain string representation * @see BigDecimal#toPlainString() */ public String toPlainString() { if (isZero()) { return "0"; } if (isIntegerInternal()) { return numerator.toPlainString(); } return toBigDecimal().toPlainString(); } /** * Returns the string representation of this rational number in the form "numerator/denominator". * *

The resulting string is a valid input of the {@link #valueOf(String)} method.

* *

Examples:

*
    *
  • BigRational.valueOf(0.5).toRationalString() returns "1/2"
  • *
  • BigRational.valueOf(2).toRationalString() returns "2"
  • *
  • BigRational.valueOf(4, 4).toRationalString() returns "4/4" (not reduced)
  • *
* * @return the rational number string representation in the form "numerator/denominator", or "0" if the rational number is 0. * @see #valueOf(String) * @see #valueOf(int, int) */ public String toRationalString() { if (isZero()) { return "0"; } if (isIntegerInternal()) { return numerator.toString(); } return numerator + "/" + denominator; } /** * Returns the string representation of this rational number as integer and fraction parts in the form "integerPart fractionNominator/fractionDenominator". * *

The integer part is omitted if it is 0 (when this absolute rational number is smaller than 1).

*

The fraction part is omitted it it is 0 (when this rational number is an integer).

*

If this rational number is 0, then "0" is returned.

* *

Example: BigRational.valueOf(3.5).toIntegerRationalString() returns "3 1/2".

* * @return the integer and fraction rational string representation * @see #valueOf(int, int, int) */ public String toIntegerRationalString() { BigDecimal fractionNumerator = numerator.remainder(denominator); BigDecimal integerNumerator = numerator.subtract(fractionNumerator); BigDecimal integerPart = integerNumerator.divide(denominator); StringBuilder result = new StringBuilder(); if (integerPart.signum() != 0) { result.append(integerPart); } if (fractionNumerator.signum() != 0) { if (result.length() > 0) { result.append(' '); } result.append(fractionNumerator.abs()); result.append('/'); result.append(denominator); } if (result.length() == 0) { result.append('0'); } return result.toString(); } /** * Creates a rational number of the specified int value. * * @param value the int value * @return the rational number */ public static BigRational valueOf(int value) { if (value == 0) { return ZERO; } if (value == 1) { return ONE; } return new BigRational(value); } /** * Creates a rational number of the specified numerator/denominator int values. * * @param numerator the numerator int value * @param denominator the denominator int value (0 not allowed) * @return the rational number * @throws ArithmeticException if the denominator is 0 (division by zero) */ public static BigRational valueOf(int numerator, int denominator) { return of(BigDecimal.valueOf(numerator), BigDecimal.valueOf(denominator)); } /** * Creates a rational number of the specified integer and fraction parts. * *

Useful to create numbers like 3 1/2 (= three and a half = 3.5) by calling * BigRational.valueOf(3, 1, 2).

*

To create a negative rational only the integer part argument is allowed to be negative: * to create -3 1/2 (= minus three and a half = -3.5) call BigRational.valueOf(-3, 1, 2).

* * @param integer the integer part int value * @param fractionNumerator the fraction part numerator int value (negative not allowed) * @param fractionDenominator the fraction part denominator int value (0 or negative not allowed) * @return the rational number * @throws ArithmeticException if the fraction part denominator is 0 (division by zero), * or if the fraction part numerator or denominator is negative */ public static BigRational valueOf(int integer, int fractionNumerator, int fractionDenominator) { if (fractionNumerator < 0 || fractionDenominator < 0) { throw new ArithmeticException("Negative value"); } BigRational integerPart = valueOf(integer); BigRational fractionPart = valueOf(fractionNumerator, fractionDenominator); return integerPart.isPositive() ? integerPart.add(fractionPart) : integerPart.subtract(fractionPart); } /** * Creates a rational number of the specified numerator/denominator BigInteger values. * * @param numerator the numerator {@link BigInteger} value * @param denominator the denominator {@link BigInteger} value (0 not allowed) * @return the rational number * @throws ArithmeticException if the denominator is 0 (division by zero) */ public static BigRational valueOf(BigInteger numerator, BigInteger denominator) { return of(new BigDecimal(numerator), new BigDecimal(denominator)); } /** * Creates a rational number of the specified {@link BigInteger} value. * * @param value the {@link BigInteger} value * @return the rational number */ public static BigRational valueOf(BigInteger value) { if (value.compareTo(BigInteger.ZERO) == 0) { return ZERO; } if (value.compareTo(BigInteger.ONE) == 0) { return ONE; } return valueOf(value, BigInteger.ONE); } /** * Creates a rational number of the specified double value. * * @param value the double value * @return the rational number * @throws NumberFormatException if the double value is Infinite or NaN. */ public static BigRational valueOf(double value) { if (value == 0.0) { return ZERO; } if (value == 1.0) { return ONE; } if (Double.isInfinite(value)) { throw new NumberFormatException("Infinite"); } if (Double.isNaN(value)) { throw new NumberFormatException("NaN"); } return valueOf(new BigDecimal(String.valueOf(value))); } /** * Creates a rational number of the specified {@link BigDecimal} value. * * @param value the double value * @return the rational number */ public static BigRational valueOf(BigDecimal value) { if (value.compareTo(BigDecimal.ZERO) == 0) { return ZERO; } if (value.compareTo(BigDecimal.ONE) == 0) { return ONE; } int scale = value.scale(); if (scale == 0) { return new BigRational(value, BigDecimal.ONE); } else if (scale < 0) { BigDecimal n = new BigDecimal(value.unscaledValue()).multiply(BigDecimal.ONE.movePointLeft(value.scale())); return new BigRational(n, BigDecimal.ONE); } else { BigDecimal n = new BigDecimal(value.unscaledValue()); BigDecimal d = BigDecimal.ONE.movePointRight(value.scale()); return new BigRational(n, d); } } /** * Creates a rational number of the specified string representation. * *

The accepted string representations are:

*
    *
  • Output of {@link BigRational#toString()} : "integerPart.fractionPart"
  • *
  • Output of {@link BigRational#toRationalString()} : "numerator/denominator"
  • *
  • Output of toString() of {@link BigDecimal}, {@link BigInteger}, {@link Integer}, ...
  • *
  • Output of toString() of {@link Double}, {@link Float} - except "Infinity", "-Infinity" and "NaN"
  • *
* * @param string the string representation to convert * @return the rational number * @throws ArithmeticException if the denominator is 0 (division by zero) */ public static BigRational valueOf(String string) { String[] strings = string.split("/"); BigRational result = valueOfSimple(strings[0]); for (int i = 1; i < strings.length; i++) { result = result.divide(valueOfSimple(strings[i])); } return result; } private static BigRational valueOfSimple(String string) { return valueOf(new BigDecimal(string)); } public static BigRational valueOf(boolean positive, String integerPart, String fractionPart, String fractionRepeatPart, String exponentPart) { BigRational result = ZERO; if (fractionRepeatPart != null && fractionRepeatPart.length() > 0) { BigInteger lotsOfNines = BigInteger.TEN.pow(fractionRepeatPart.length()).subtract(BigInteger.ONE); result = valueOf(new BigInteger(fractionRepeatPart), lotsOfNines); } if (fractionPart != null && fractionPart.length() > 0) { result = result.add(valueOf(new BigInteger(fractionPart))); result = result.divide(BigInteger.TEN.pow(fractionPart.length())); } if (integerPart != null && integerPart.length() > 0) { result = result.add(new BigInteger(integerPart)); } if (exponentPart != null && exponentPart.length() > 0) { int exponent = Integer.parseInt(exponentPart); BigInteger powerOfTen = BigInteger.TEN.pow(Math.abs(exponent)); result = exponent >= 0 ? result.multiply(powerOfTen) : result.divide(powerOfTen); } if (!positive) { result = result.negate(); } return result; } /** * Creates a rational number of the specified numerator/denominator BigDecimal values. * * @param numerator the numerator {@link BigDecimal} value * @param denominator the denominator {@link BigDecimal} value (0 not allowed) * @return the rational number * @throws ArithmeticException if the denominator is 0 (division by zero) */ public static BigRational valueOf(BigDecimal numerator, BigDecimal denominator) { return valueOf(numerator).divide(valueOf(denominator)); } private static BigRational of(BigDecimal numerator, BigDecimal denominator) { if (numerator.signum() == 0 && denominator.signum() != 0) { return ZERO; } if (numerator.compareTo(BigDecimal.ONE) == 0 && denominator.compareTo(BigDecimal.ONE) == 0) { return ONE; } return new BigRational(numerator, denominator); } /** * Returns the smallest of the specified rational numbers. * * @param values the rational numbers to compare * @return the smallest rational number, 0 if no numbers are specified */ public static BigRational min(BigRational... values) { if (values.length == 0) { return BigRational.ZERO; } BigRational result = values[0]; for (int i = 1; i < values.length; i++) { result = result.min(values[i]); } return result; } /** * Returns the largest of the specified rational numbers. * * @param values the rational numbers to compare * @return the largest rational number, 0 if no numbers are specified * @see #max(BigRational) */ public static BigRational max(BigRational... values) { if (values.length == 0) { return BigRational.ZERO; } BigRational result = values[0]; for (int i = 1; i < values.length; i++) { result = result.max(values[i]); } return result; } private static List bernoulliCache = new ArrayList<>(); /** * Calculates the Bernoulli number for the specified index. * *

This function calculates the first Bernoulli numbers and therefore bernoulli(1) returns -0.5

*

Note that bernoulli(x) for all odd x > 1 returns 0

*

See: Wikipedia: Bernoulli number

* * @param n the index of the Bernoulli number to be calculated (starting at 0) * @return the Bernoulli number for the specified index * @throws ArithmeticException if x is lesser than 0 */ public static BigRational bernoulli(int n) { if (n < 0) { throw new ArithmeticException("Illegal bernoulli(n) for n < 0: n = " + n); } if (n == 1) { return valueOf(-1, 2); } else if (n % 2 == 1) { return ZERO; } synchronized (bernoulliCache) { int index = n / 2; if (bernoulliCache.size() <= index) { for (int i = bernoulliCache.size(); i <= index; i++) { BigRational b = calculateBernoulli(i * 2); bernoulliCache.add(b); } } return bernoulliCache.get(index); } } private static BigRational calculateBernoulli(int n) { return IntStream.rangeClosed(0, n).parallel().mapToObj(k -> { BigRational jSum = ZERO ; BigRational bin = ONE ; for(int j=0 ; j <= k ; j++) { BigRational jPowN = valueOf(j).pow(n); if (j % 2 == 0) { jSum = jSum.add(bin.multiply(jPowN)) ; } else { jSum = jSum.subtract(bin.multiply(jPowN)) ; } bin = bin.multiply(valueOf(k-j).divide(valueOf(j+1))); } return jSum.divide(valueOf(k+1)); }).reduce(ZERO, BigRational::add); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy