简体   繁体   English

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

[英]How can I turn a floating point number into the closest fraction represented by a byte numerator and denominator?

How can I write an algorithm that given a floating point number, and attempts to represent is as accurately as possible using a numerator and a denominator, both restricted to the range of a Java byte?如何编写一个给定浮点数的算法,并尝试使用分子和分母尽可能准确地表示,两者都限制在 Java 字节的范围内?

The reason for this is that an I2C device wants a numerator and denominator, while it would make sense to give it a float.这样做的原因是 I2C 设备需要一个分子和分母,而给它一个浮点数是有意义的。

For example, 3.1415926535... would result in 245/78 , rather than 314/100 or 22/7 .例如, 3.1415926535...将导致245/78 ,而不是314/10022/7

In terms of efficiency, this would be called around three times at the start of the program, but after that not at all.就效率而言,这将在程序开始时调用大约 3 次,但在那之后根本不会调用。 So a slow algorithm isn't too bad.因此,慢速算法还不错

Here's the code I used in the end (based on uckelman's code)这是我最后使用的代码(基于 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};
}

Thanks for those who helped感谢那些帮助过的人

How worried are you about efficiency?你对效率有多担心? If you're not calling this conversion function 100s of times per second or more, then it probably wouldn't be all that hard to brute-force through every possible denominator (most likely only 255 of them) and find which one gives the closest approximation (computing the numerator to go with the denominator is constant time).如果您没有每秒调用此转换函数 100 次或更多次,那么通过每个可能的分母(很可能只有 255 个)并找出最接近的分母可能并不难近似(计算分子与分母是常数时间)。

I've written some code (in Java, even) to do just the thing you're asking for.我已经编写了一些代码(甚至在 Java 中)来完成您所要求的事情。 In my case, I needed to display a scaling factor as both a percentage and a ratio.就我而言,我需要将比例因子显示为百分比和比率。 The most familiar example of this is the zoom dialog you see in image editors, such as the GIMP.最熟悉的示例是您在图像编辑器(例如 GIMP)中看到的缩放对话框。

You can find my code here , in the updateRatio() method starting at line 1161. You can simply use it, so long as the LGPL license works for you.你可以在这里找到我的代码,在从第 1161 行开始的 updateRatio() 方法中。你可以简单地使用它,只要 LGPL 许可证适合你。 What I did essentially follows what's done in the GIMP---this is one of those things where there's pretty much only one efficient, sensible way to do it.我所做的基本上遵循了 GIMP 中所做的事情——这是其中几乎只有一种有效、明智的方法来做的事情之一。

I would comment, but I don't have rep yet...我会发表评论,但我还没有代表...

Eric's answer above doesn't consider the case where an exact result is possible.埃里克的上述回答没有考虑可能获得确切结果的情况。 For example, if you use 0.4 as input, then the representation should be 2/5, in which case you end up with a division by zero in the third iteration of the loop (r=0 on second loop => r = 1/r error on third).例如,如果您使用 0.4 作为输入,那么表示应该是 2/5,在这种情况下,您最终会在循环的第三次迭代中除以零(第二次循环中的 r=0 => r = 1/第三个错误)。

So you want to modify the while loop to exclude that option:因此,您要修改 while 循环以排除该选项:

while(true)

should be应该

while(r != 0)

What about using Apache's BigFraction:使用 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);
}

You should look at the Farey Sequence.你应该看看法雷数列。
Given a limit on the denominator d, the Farey Sequence is every fraction having denominator <= d.给定分母 d 的限制,法雷数列是分母 <= d 的每个分数。

Then, you would simply take your float and compare it to the resolved value of the Farey fraction.然后,您只需将浮点数与 Farey 分数的解析值进行比较。 This will allow you to represent your float in terms of repeating-decimal reals.这将允许您用重复的十进制实数来表示您的浮点数。

Here is a page on its implementation in java:这是有关其在java中实现的页面:
http://www.merriampark.com/fractions.htm http://www.merriampark.com/fractions.htm

Here is a good demonstration of their use:这是他们使用的一个很好的演示:
http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fractions/fareySB.html http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fractions/fareySB.html

I reached out here out of curiosity, but I remembered there's such feature in Python standard library fractions .出于好奇,我来到这里,但我记得 Python 标准库分数中有这样的功能。

Maybe, we can look into the source code of the two functions:也许,我们可以看看这两个函数的源代码:

如何在双数据类型中存储 18 位数字(当分子<denominator)< div><div id="text_translate"><p> 我想做的是,例如</p><pre>int num = 18, den = 19; double q=(double)num/(double)den;</pre><p> 返回 0.9473684210526315</p><p> 但我想要的是 0.947368421052631578</p><p> 因为 num<den,小数点左边总是“0”,我是否可以使用这些字符的空间并将其改为“78”? 如果我不能那样做,另一种方法是什么?</p><p> 我需要这个的原因是一个 LC 问题。 </p></div></denominator)<> - how to store 18 digits in a double datatype (when numerator<denominator)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 12.1可以完全表示为浮点数吗? - Can 12.1 be represented exactly as a floating point number? 输出分数作为分子在java中的分母? - Output fraction as numerator over denominator in java? 如何获取以分数的“分子/分母”形式返回分数的字符串版本的方法 - How to get method which returns the String version of the Fraction in the form of “numerator / denominator” of fraction 如何用浮点格式表示一个分数是否会被舍入(使用fp时re:java remainder [%]结果) - How to know if a fraction will be rounded up when represented in floating point format (re: java remainder [%] results when using fp's) 如何测试浮点随机数生成器? - How can I test a floating-point random number generator? 如何检查字符串是否为浮点数? - how can I check if a string is a floating point number? 有理数的方法-分子和分母 - Method to Rational - numerator and denominator 这个方法如何计算 Rational(1).hashCode()? 1 的分子或分母是 1 本身 - How does this method compute Rational(1).hashCode()? The numerator or denominator of 1 is 1 itself 如何在双数据类型中存储 18 位数字(当分子<denominator)< div><div id="text_translate"><p> 我想做的是,例如</p><pre>int num = 18, den = 19; double q=(double)num/(double)den;</pre><p> 返回 0.9473684210526315</p><p> 但我想要的是 0.947368421052631578</p><p> 因为 num<den,小数点左边总是“0”,我是否可以使用这些字符的空间并将其改为“78”? 如果我不能那样做,另一种方法是什么?</p><p> 我需要这个的原因是一个 LC 问题。 </p></div></denominator)<> - how to store 18 digits in a double datatype (when numerator<denominator) 如何读取浮点值并打印小于或大于该值的最接近的数字? - How do I read a floating point value and print the closest numbers less than or greater than that value?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM