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

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

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

例如, 3.1415926535...将导致245/78 ,而不是314/10022/7

在效率方面,这将在程序开始时调用三次,但之后根本不会。 所以慢速算法也不算糟糕。

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

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

这是我最后使用的代码(基于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}; } 

谢谢那些帮助过的人

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

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

Eric上面的回答没有考虑可能得到确切结果的情况。 例如,如果使用0.4作为输入,则表示应为2/5,在这种情况下,在循环的第三次迭代中最终得到除以零(第二次循环时r = 0 => r = 1 / r错误在第三)。

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

 while(true) 

应该

 while(r != 0) 

你应该看一下Farey Sequence。
鉴于分母d的限制,Farey序列是具有分母<= d的每个分数。

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

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

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

那么使用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); }