Почему класс BigFraction в библиотеке Apache-Commons-Math возвращает неверные результаты деления? - PullRequest
1 голос
/ 14 мая 2010

В духе использования существующих, проверенных и стабильных библиотек кода я начал использовать библиотеку Apache-Commons-Math и ее BigFraction класс для выполнения некоторых рациональных вычислений для приложения для Android, которое я пишу, называется RationalCalc.

Он прекрасно работает для каждой задачи, которую я ему бросил, за исключением одной неприятной проблемы. При делении определенных значений BigFraction я получаю неверные результаты.

Если я создаю BigFraction с инверсией делителя и вместо этого умножаю, я получаю тот же неправильный ответ, но, возможно, именно так и поступает библиотека внутри.

Кто-нибудь знает, что я делаю не так?

Деление работает правильно с BigFraction, равным 2,5, но не с 2,51, 2,49 и т. Д. *

[UPDATE]

Это действительно ошибка в библиотеках apache-commons-math 2.0. Ошибка исправлена ​​в v.2.1.

Теперь он указан в разделе «Исправленные проблемы» в трекере ошибок:

При умножении двух объектов BigFraction на числители, размер которых больше, чем уместится в java-примитиве int, неверно возвращается результат BigFraction.ZERO. .

Спасибо @BartK за попытку воспроизвести проблему и завести меня на правильный путь.

[/ UPDATE]

// *** incorrect! ***
BigFraction one = new BigFraction(1.524);
//one: 1715871458028159 / 1125899906842624

BigFraction two = new BigFraction(2.51);
//two: 1413004383087493 / 562949953421312

BigFraction three = one.divide(two);
//three: 0

Log.i("solve", three.toString());
//should be 0.607171315  ??
//returns 0


// *** correct! ****
BigFraction four = new BigFraction(1.524);
//four: 1715871458028159 / 1125899906842624

BigFraction five = new BigFraction(2.5);
//five: 5 / 2

BigFraction six = four.divide(five);
//six: 1715871458028159 / 2814749767106560

Log.i("solve", six.toString());
//should be 0.6096  ??
//returns 0.6096

1 Ответ

3 голосов
/ 14 мая 2010

Предоставление double в конструкторах приводит к ошибкам округления. Использование точных числителей и знаменателей приведет к ожидаемому результату:

public class CommonsMathTest {

    public static void main(String[] args) {

        BigFraction one = new BigFraction(1524, 1000);
        System.out.println("one   = " + one);

        BigFraction two = new BigFraction(251, 100);
        System.out.println("two   = " + two);

        BigFraction three = one.divide(two);
        System.out.println("three = " + three);

        BigFraction four = new BigFraction(1524, 1000);
        System.out.println("four  = " + four);

        BigFraction five = new BigFraction(5, 2);
        System.out.println("five  = " + five);

        BigFraction six = four.divide(five);
        System.out.println("six   = " + six + " = " + six.bigDecimalValue());
    }
}

производит:

one   = 381 / 250
two   = 251 / 100
three = 762 / 1255
four  = 381 / 250
five  = 5 / 2
six   = 381 / 625 = 0.6096

EDIT

Кстати, я не смог воспроизвести ваш вывод. Используя Commons-Math 2.1, следующее:

BigFraction one = new BigFraction(1.524);
BigFraction two = new BigFraction(2.51);
BigFraction three = one.divide(two);
System.out.println(three.toString() + " = " +three.doubleValue());

не производит 0, как вы сказали, но печатает:

1715871458028159 / 2826008766174986 = 0.6071713147410359
...