测试小数是否足够接近有理数

时间:2010-10-14 00:24:30

标签: algorithm numerical

给定小数x,我想测试x是否在有理数的10 ^ -12范围内,分母为9999或更小。显然,我可以通过查看x,2x,3x等来查看,并查看其中是否有任何一个足够接近整数。但是有更高效的算法吗?

3 个答案:

答案 0 :(得分:5)

有一种称为continued fraction algorithm的算法可以在某种定义的意义上为您提供“最佳”有理近似。当分母超过9999然后返回到先前的收敛并进行比较以查看它是否足够接近时,您可以停止。当然,如果小数是一个足够小的有理数,算法将提前终止。

答案 1 :(得分:2)

所以,有几件事:

我假设通过'decimal x'你指的是一些浮点表示x。也就是说,你打算以某种格式实现它,它实际上不能完美地表示.1或1/3等。如果你是用手或者其他有自己的方式表示小数的东西,这就赢了适用。

其次,你是否与那些特定的分母和容忍相关联?我问,因为如果你没有2的幂(例如,分母高达8192,容差为2 ^ -35),你可以很容易地利用IEEE-754风格浮点都是有理数的事实。使用指数确定尾数中的哪个数字对应于2 ^ -13,然后确保尾数的下22个数字为0(如果精度不足以包括超过该点的22,则最多22个)。如果是这样,你就明白了。

现在,如果你不愿意改变你的算法使用base 2,你至少可以用它来缩小它并做一些消除。

答案 2 :(得分:1)

我知道你已经接受了答案,但无论如何我都要打电话。

蛮力方法不需要检查每个分母。如果你向后工作,你不仅可以消除你刚检查过的数字,还可以消除每个因素。例如,一旦你检查了9999,你就不需要检查3333,1111,909,303,101,99,33,11,9,3或1;如果数字可以表示为其中一个的一部分,它也可以表示为9999的分数。事实证明,每个5000以下的数字是至少一个数字5000到9999的因子,所以你切你的搜索空间减半。

编辑:我发现这个问题非常有趣,可以用Python编写解决方案。

def gcd(a, b):
    if b == 0:
        return a
    return gcd(b, a % b)

def simplify(fraction_tuple):
    divisor = gcd(fraction_tuple[0], fraction_tuple[1])
    return fraction_tuple[0] / divisor, fraction_tuple[1] / divisor

def closest_fraction(value, max_denominator=9999, tolerance=1e-12, enforce_tolerance=False):
    best_error, best_result = abs(value), (0,1)
    for denominator in range(max_denominator/2+1, max_denominator+1):
        numerator = round(value * denominator)
        error = abs(value - (numerator / denominator))
        if error < best_error:
            best_error = error
            best_result = int(numerator), denominator
            if error <= tolerance:
                break
    if enforce_tolerance and best_error > tolerance:
        return None
    return simplify(best_result)