将浮点小数转换为分数

我正在尝试将具有十进制结果的用户键入的计算转换为分数。例如;66.6666666667 转换为 66 2/3。任何指针?提前感恩节


答案 1

连续分数可用于查找实数的有理近似值,这些实数在严格意义上是“最佳”的。下面是一个 PHP 函数,它查找给定(正)浮点数的有理近似值,相对误差小于:$tolerance

<?php
function float2rat($n, $tolerance = 1.e-6) {
    $h1=1; $h2=0;
    $k1=0; $k2=1;
    $b = 1/$n;
    do {
        $b = 1/$b;
        $a = floor($b);
        $aux = $h1; $h1 = $a*$h1+$h2; $h2 = $aux;
        $aux = $k1; $k1 = $a*$k1+$k2; $k2 = $aux;
        $b = $b-$a;
    } while (abs($n-$h1/$k1) > $n*$tolerance);

    return "$h1/$k1";
}

printf("%s\n", float2rat(66.66667)); # 200/3
printf("%s\n", float2rat(sqrt(2)));  # 1393/985
printf("%s\n", float2rat(0.43212));  # 748/1731

我已经写了更多关于这个算法以及它为什么工作,甚至在这里写了一个JavaScript演示:https://web.archive.org/web/20180731235708/http://jonisalonen.com/2012/converting-decimal-numbers-to-ratios/


答案 2

在这种情况下,Farey分数可能非常有用。

它们可用于将任何小数转换为具有尽可能低分母的分数。

抱歉 - 我没有PHP的原型,所以这里有一个Python的原型:

def farey(v, lim):
    """No error checking on args.  lim = maximum denominator.
        Results are (numerator, denominator); (1, 0) is 'infinity'."""
    if v < 0:
        n, d = farey(-v, lim)
        return (-n, d)
    z = lim - lim   # Get a "zero of the right type" for the denominator
    lower, upper = (z, z+1), (z+1, z)
    while True:
        mediant = (lower[0] + upper[0]), (lower[1] + upper[1])
        if v * mediant[1] > mediant[0]:
            if lim < mediant[1]:
                return upper
            lower = mediant
        elif v * mediant[1] == mediant[0]:
            if lim >= mediant[1]:
                return mediant
            if lower[1] < upper[1]:
                return lower
            return upper
        else:
            if lim < mediant[1]:
                return lower
            upper = mediant

推荐