Существует ли обычно используемая библиотека рациональных чисел в Java? - PullRequest
31 голосов
/ 26 марта 2011

Я ищу библиотеку 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() и т. Д.

Ответы [ 5 ]

16 голосов
/ 26 марта 2011

Подходит ли вам Apache Commons Math ?

13 голосов
/ 24 декабря 2012

Библиотека 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))));
1 голос
/ 26 января 2012

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

import java.util.ArrayList;

public class RationalNumber {

    /**
     *
     * @author Suat KARAKUSOGLU
     * @email  suatkarakusoglu@gmail.com
     * 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);
    }



}
1 голос
/ 27 марта 2011

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

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

Содержание:

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

1 голос
/ 27 марта 2011

Я не уверен, насколько часто он используется, но пакеты apfloat (Java и C ++) содержат класс для рациональной арифметики .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...