为什么 Apache-Commons-Math 库中的 BigFraction 类返回错误的除法结果?

发布于 2024-09-01 03:46:09 字数 1643 浏览 4 评论 0原文

本着使用现有的、经过测试的、稳定的代码库的精神,我开始使用 Apache-Commons-Math 库< /a> 及其 BigFraction< /code> 类来为我正在编写的名为 RationalCalc 的 Android 应用程序执行一些理性计算。

它对于我交给它的每一项任务都很有效,除了一个棘手的问题。除某些 BigFraction 值时,我得到了不正确的结果。

如果我用除数的倒数创建一个 BigFraction 并进行乘法,我会得到相同的错误答案,但也许这就是库内部正在做的事情。

有谁知道我做错了什么?

除法在 BigFraction 为 2.5 时可以正常工作,但在 2.51、2.49 等情况下则不行...

[更新]

这确实是 apache-commons-math 2.0 库中的一个错误。该错误已在 v.2.1 中修复。

它现在列在错误跟踪器的“已修复问题”部分中:

当将两个 BigFraction 对象与大于 java-primitive int 的分子将错误地返回 BigFraction.ZERO 的结果。

感谢@BartK 尝试重现该问题并使我走上正确的轨道。

[/更新]

// *** 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

In the spirit of using existing, tested and stable libraries of code, I started using the Apache-Commons-Math library and its BigFraction class to perform some rational calculations for an Android app I'm writing called RationalCalc.

It works great for every task that I have thrown at it, except for one nagging problem. When dividing certain BigFraction values, I am getting incorrect results.

If I create a BigFraction with the inverse of the divisor and multiply instead, I get the same incorrect answer but perhaps that is what the library is doing internally anyway.

Does anyone know what I am doing wrong?

The division works correctly with a BigFraction of 2.5 but not 2.51, 2.49, etc...

[UPDATE]

This was indeed a bug in the apache-commons-math 2.0 libraries. The bug is fixed in v.2.1.

It is now listed in the Fixed Issues section of the bug tracker:

When multiplying two BigFraction objects with numerators larger than will fit in an java-primitive int the result of BigFraction.ZERO is incorrectly returned..

Thanks to @BartK for attempting to reproduce the issue and setting me on the right track.

[/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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

匿名。 2024-09-08 03:46:09

在构造函数中提供双精度数会导致舍入错误。使用精确的分子和分母将产生预期的结果:

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

编辑

顺便说一句,我无法重现您的输出。使用 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

Providing double's in the constructors lead to round-off errors. Using exact numerators and denominators will result in the expected outcome:

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());
    }
}

produces:

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

EDIT

By the way, I could not reproduce your output. Using Commons-Math 2.1, the following:

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

does not produce 0 as you said, but prints:

1715871458028159 / 2826008766174986 = 0.6071713147410359
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文