Существует ли в Java обычная библиотека рациональных чисел?

Я ищу библиотеку Java, которая представляет фракции (рациональные числа). Например, если я хочу сохранить фракцию 1/3, то она не будет сохранена как 0.33333, которая потеряет свою точность.

Вот некоторые из функций, которые я ожидаю найти в такой библиотеке:

  • getNumerator()
  • getDenominator()
  • add(Rational r1, Rational r2), subtract(Rational r1, Rational r2), multiply(Rational r1, Rational r2), divide(Rational r1, Rational r2)
  • isProper()
  • getCommonDenominator(Collection<Rational> rationals)
  • getSimplified()

Я могу реализовать такую ​​библиотеку самостоятельно, хотя мне было интересно, похоже ли что-то подобное.

РЕДАКТИРОВАТЬ: Было бы неплохо, если бы библиотека реализовала (в дополнение к выше) некоторые алгоритмы теории чисел, такие как getEgyptianFractionsSum() и т.д.

Ответ 1

Библиотека JScience включает класс org.jscience.mathematics.number.Rational. В дополнение к обычным фабрикам, аксессуарам и операциям можно построить другие полезные объекты, включая Polynomial<Rational>, Vector<Rational> и Matrix<Rational>.

В качестве примера, функция для получения самого низкого общего знаменателя набора дроби может выглядеть так:

private static LargeInteger lcd(Collection<Rational> fractions) {
    Rational sum = Rational.ZERO;
    for (Rational rational : fractions) {
        sum = sum.plus(rational);
    }
    return sum.getDivisor();
}

Следующий оператор печатает 6:

System.out.println(lcd(Arrays.asList(
    Rational.valueOf(1, 2), Rational.valueOf(1, 3))));

Ответ 4

Библиотека Apfloat обладает множеством отличных функций, производительности, точности и т.д. Его определенно лучший BigDecimal, который будет справедливым, но довольно прост и предлагает небольшую функциональность.

http://www.apfloat.org/apfloat_java/

Содержание:

Настройка класса Первый пример Построение апфлоатов Предостережения о конструкции Apfloats неизменяемы точность Вывод Расширенные математические функции Целые Комплексные числа Рациональное число Использование некоторых других оснований, чем 10 Равенство и сравнение Форматирование

Ответ 5

Я реализовал небольшой класс, который можно использовать для этих целей, возможно, он может быть полезен и вам, используйте с осторожностью.

import java.util.ArrayList;

public class RationalNumber {

    /**
     *
     * @author Suat KARAKUSOGLU
     * @email  [email protected]
     * This class has 2 kind of constructors
     * 1. is RationalNumber a=new RationalNumber("3.3");
     *       RationalNumber a=new RationalNumber("-3.3");
     * With this constructor one can enter the decimal number and also specify whether negative or not
     *
     * 2. is RationalNumber a=new RationalNumber(3,5);
     * With this constructor the first value is nominator and second one is denominator.
     *
     * The advantage side of this class is, it prevents the fractional errors while dividing
     * RationalNumber keeps all denominator and nominator values as it is and when the real value is
     * needed, the calculation occurs at that time.
     *
     * Supports multiply,divide,add,subtract operations on RationalNumber classes.
     *
     */


    /*
     * Simple Usage:
     *
     * RationalNumber a=new RationalNumber("3.3");
     * RationalNumber b=new RationalNumber("4.5");
     * System.out.println("a ="+a.getStringValue());
     * System.out.println("b ="+b.getStringValue());
     * System.out.println("a-b ="+a.subtract(b).getStringValue());
     * System.out.println("a ="+a.getStringValue());
     * System.out.println("b ="+b.getStringValue());
     * RationalNumber k=a.divide(b);
     * System.out.println("a/b="+k.getStringValue());
     * System.out.println("a/b="+k.getDoubleValue());
     *
     * System out results:
     *
     * a =33/10
     * b =9/2
     * a-b =-6/5
     * a =33/10
     * b =9/2
     * a/b=11/15
     * a/b=0.7333333333333333
     *
     */

    public ArrayList<Long> nominators = new ArrayList<Long>();
    public ArrayList<Long> denominators = new ArrayList<Long>();

    public RationalNumber(String rationalNumberStringValue) {
        this(parseRationalNumberStringValue(rationalNumberStringValue)[0],
                parseRationalNumberStringValue(rationalNumberStringValue)[1]);

    }

    private static Long[] parseRationalNumberStringValue(
            String rationalNumberStringValue) {

        boolean positive = true;
        if (rationalNumberStringValue.charAt(0) == '-') {
            positive = false;
            rationalNumberStringValue = rationalNumberStringValue.substring(1);
        }

        // 0. index is keeping nominator
        // 1. index is keeping denominator
        Long[] nominatorDenominator = new Long[2];
        nominatorDenominator[0] = 1l;
        nominatorDenominator[1] = 1l;

        String[] splittedNumberArr = rationalNumberStringValue.split("\\.");
        String denominatorStr = splittedNumberArr[1];

        for (int i = 0; i < denominatorStr.length(); i++) {
            nominatorDenominator[1] *= 10;
        }

        rationalNumberStringValue = removeCharAt(rationalNumberStringValue,
                rationalNumberStringValue.indexOf('.'));
        nominatorDenominator[0] = Long.valueOf(rationalNumberStringValue);
        if (!positive) {
            nominatorDenominator[0] *= -1;
        }
        return nominatorDenominator;

    }

    public static String removeCharAt(String s, int pos) {
        return s.substring(0, pos) + s.substring(pos + 1);
    }

    public RationalNumber(Integer nominator, Integer denominator) {

        this((long) nominator, (long) denominator);

    }

    public RationalNumber(Long nominator, Long denominator) {

        nominators.add(nominator);
        denominators.add(denominator);
        simplify();

    }

    public RationalNumber(ArrayList<Long> nominatorList,
            ArrayList<Long> denominatorList) {

        nominators.addAll(nominatorList);
        denominators.addAll(denominatorList);
        simplify();

    }

    public String getStringValue() {
        return getMultipliedValue(this.nominators) + "/"
                + getMultipliedValue(this.denominators);
    }

    public double getDoubleValue() {
        return (double) getMultipliedValue(this.nominators)
                / (double) getMultipliedValue(this.denominators);
    }

    public RationalNumber multiply(RationalNumber rationalNumberToMultiply) {

        RationalNumber mulResult = new RationalNumber(
                rationalNumberToMultiply.nominators,
                rationalNumberToMultiply.denominators);
        mulResult.nominators.addAll(this.nominators);
        mulResult.denominators.addAll(this.denominators);

        return RationalNumber.simplifyRationalNumber(mulResult);
    }

    public RationalNumber divide(RationalNumber rationalNumberToDivide) {

        RationalNumber divideResult = new RationalNumber(
                rationalNumberToDivide.nominators,
                rationalNumberToDivide.denominators);

        // division means multiplication with reverse values
        ArrayList<Long> tempLongList = divideResult.nominators;
        divideResult.nominators = divideResult.denominators;
        divideResult.denominators = tempLongList;

        return this.multiply(divideResult);

    }

    public RationalNumber add(RationalNumber rationalNumberToAdd) {

        rationalNumberToAdd = RationalNumber
                .simplifyRationalNumber(rationalNumberToAdd);

        return new RationalNumber(
                (getMultipliedValue(this.nominators) * getMultipliedValue(rationalNumberToAdd.denominators))
                        + (getMultipliedValue(this.denominators) * getMultipliedValue(rationalNumberToAdd.nominators)),
                (getMultipliedValue(this.denominators) * getMultipliedValue(rationalNumberToAdd.denominators)));

    }

    public RationalNumber subtract(RationalNumber rationalNumberToSubtract) {

        rationalNumberToSubtract = RationalNumber
                .simplifyRationalNumber(rationalNumberToSubtract);

        RationalNumber subtractTempRational = new RationalNumber(
                rationalNumberToSubtract.nominators,
                rationalNumberToSubtract.denominators);

        // Multiply one of its nominators negative value
        subtractTempRational.nominators.set(0,
                (subtractTempRational.nominators.get(0) * -1));

        // add with its negative value
        return this.add(subtractTempRational);

    }

    private long getMultipliedValue(ArrayList<Long> longList) {
        Long mulResult = 1l;
        for (Long tempLong : longList) {
            mulResult *= tempLong;
        }
        return mulResult;
    }

    // simplifies original rationalnumber
    public void simplify() {
        long tempGcd = 1;
        long iValue = 1;
        long jValue = 1;
        for (int i = 0; i < this.nominators.size(); i++) {
            iValue = this.nominators.get(i);
            for (int j = 0; j < this.denominators.size(); j++) {
                jValue = this.denominators.get(j);
                tempGcd = gcd(iValue, jValue);
                this.nominators.set(i, iValue / tempGcd);
                this.denominators.set(j, jValue / tempGcd);
            }
        }
    }

    public static RationalNumber simplifyRationalNumber(
            RationalNumber rationalNumberToSimplify) {
        long tempGcd = 1;
        long iValue = 1;
        long jValue = 1;
        for (int i = 0; i < rationalNumberToSimplify.nominators.size(); i++) {
            for (int j = 0; j < rationalNumberToSimplify.denominators.size(); j++) {
                iValue = rationalNumberToSimplify.nominators.get(i);
                jValue = rationalNumberToSimplify.denominators.get(j);
                tempGcd = gcd(iValue, jValue);
                rationalNumberToSimplify.nominators.set(i, iValue / tempGcd);
                rationalNumberToSimplify.denominators.set(j, jValue / tempGcd);
            }
        }
        return rationalNumberToSimplify;
    }

    // Euclidean algorithm to find greatest common divisor
    public static long gcd(long a, long b) {

        a = Math.abs(a);
        b = Math.abs(b);

        if (a < b) {
            long temp = a;
            a = b;
            b = temp;
        }

        if (b == 0)
            return a;
        else
            return gcd(b, a % b);
    }

    public RationalNumber add(int integerToAdd) {

        RationalNumber tempRationalNumber=new RationalNumber(integerToAdd,1);
        return this.add(tempRationalNumber);
    }
    public RationalNumber subtract(int integerToSubtract) {

        RationalNumber tempRationalNumber=new RationalNumber(integerToSubtract,1);
        return this.subtract(tempRationalNumber);
    }
    public RationalNumber multiply(int integerToMultiply) {

        RationalNumber tempRationalNumber=new RationalNumber(integerToMultiply,1);
        return this.multiply(tempRationalNumber);
    }
    public RationalNumber divide(int integerToDivide) {

        RationalNumber tempRationalNumber=new RationalNumber(integerToDivide,1);
        return this.divide(tempRationalNumber);
    }



}