如何将浮点数转换为由字节分子和分母表示的最接近的分数?

时间:2009-11-01 11:35:31

标签: java algorithm math floating-point fractions

如何编写一个给出浮点数的算法,并尝试使用分子和分母尽可能准确地表示,两者都限制在Java字节的范围内?

这样做的原因是I2C设备需要分子和分母,而给它一个浮点数是有意义的。

例如,3.1415926535...会产生245/78,而非314/10022/7

就效率而言,在程序开始时会调用三次,但之后根本不会。因此,慢速算法不会坏。

6 个答案:

答案 0 :(得分:4)

这是我最后使用的代码(基于uckelman的代码)

public static int[] GetFraction(double input)
{
    int p0 = 1;
    int q0 = 0;
    int p1 = (int) Math.floor(input);
    int q1 = 1;
    int p2;
    int q2;

    double r = input - p1;
    double next_cf;
    while(true)
    {
        r = 1.0 / r;
        next_cf = Math.floor(r);
        p2 = (int) (next_cf * p1 + p0);
        q2 = (int) (next_cf * q1 + q0);

        // Limit the numerator and denominator to be 256 or less
        if(p2 > 256 || q2 > 256)
            break;

        // remember the last two fractions
        p0 = p1;
        p1 = p2;
        q0 = q1;
        q1 = q2;

        r -= next_cf;
    }

    input = (double) p1 / q1;
    // hard upper and lower bounds for ratio
    if(input > 256.0)
    {
        p1 = 256;
        q1 = 1;
    }
    else if(input < 1.0 / 256.0)
    {
        p1 = 1;
        q1 = 256;
    }
    return new int[] {p1, q1};
}

感谢那些帮助过的人

答案 1 :(得分:3)

你对效率有多担心?如果你没有每秒100次或更多地调用这个转换函数,那么通过每个可能的分母(最可能只有255个)并且找到哪一个给出最接近的分数可能不是那么难近似(计算分子与分母一起是恒定时间)。

答案 2 :(得分:3)

我已经编写了一些代码(甚至用Java编写)来完成你要求的东西。就我而言,我需要将比例因子显示为百分比和比率。最常见的例子是您在图像编辑器中看到的缩放对话框,例如GIMP。

您可以在第1161行开始的updateRatio()方法中找到我的代码here。只要LGPL许可证适合您,您就可以使用它。我所做的基本上是遵循GIMP中所做的 - 这是其中一种只有一种有效,明智的方法。

答案 3 :(得分:1)

我会评论,但我还没有代表...

Eric上面的回答并没有考虑可以得到确切结果的情况。例如,如果你使用0.4作为输入,那么表示应该是2/5,在这种情况下你最后在循环的第三次迭代中除以零(r = 0 on second loop =&gt; r = 1 / r错误在第三个。)

因此,您希望修改while循环以排除该选项:

while(true)

应该是

while(r != 0)

答案 4 :(得分:1)

你应该看看Farey序列 鉴于分母d的限制,Farey序列是具有分母&lt; = d的每个分数。

然后,您只需将您的浮点数与Farey分数的已解析值进行比较即可。这将允许您用重复十进制实数表示浮动。

这是一个关于它在java中实现的页面:
http://www.merriampark.com/fractions.htm

以下是他们使用的一个很好的证明:
http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fractions/fareySB.html

答案 5 :(得分:0)

如何使用Apache的BigFraction:

import org.apache.commons.math3.fraction.BigFraction;

public static BigFraction GetBigFraction(double input)
{
    int precision = 1000000000;
    return new BigFraction((int)(input * (double)precision), precision);
}