找到最接近某个值的公约数的高效算法?

时间:2012-02-08 17:48:34

标签: algorithm math number-theory

我有两个号码x1x2。对于数字y,我想计算x1x2的公约数尽可能接近y

这是否有一个有效的算法?


我相信是时候重新解决我的问题并且更清楚了。这不是关于整数...... 所以,假设我们有两个数字x1x2。比如说,用户输入一个数字y。我想要找到的是y'接近y的数字,以便x1 % y'x2 % y'非常小(例如,小于0.02,但是我们可以拨打这个号码LIMIT)。换句话说,我不需要最优算法,但需要很好的近似。

我感谢你们所有的时间和精力,这真的很棒!

4 个答案:

答案 0 :(得分:7)

我认为没有已知的有效(多项式时间)算法用于此问题,因为从integer factorization到此问题的多项式时间减少。由于没有已知的用于整数分解的多项式时间算法,因此对于您的问题也不可能有已知的算法,因为否则我们确实会有一个用于整数分解的多项式时间算法。

要了解其工作原理,假设您有一个您想要考虑的数字n。现在,使用您想要的任何算法,找到最接近√n的n和n的公因子。由于n的非平凡除数不能大于√n,因此找到(1)除以n的最大整数,或者(2)如果n为素数则为1。然后,您可以将n除以此数字并重复以生成n的所有因子。由于n最多只能有O(log n)个因子,因此对于你的问题,这最多需要求解器的多次迭代,因此我们有一个从整数因子分解到这个问题的多项式时间减少。如上所述,这意味着,至少在公开文献中,没有已知的有效经典算法来解决该问题。可能存在一个,但这将是一个非常重要的结果。

对于否定的答案感到抱歉,希望这会有所帮助!

答案 1 :(得分:2)

我认为你可以通过贪婪算法来做到这一点,首先通过常用算法找到GCD命名为d(可以在对数时间内计算),然后在每次除d时找到因子d }到最小可用因子(创建d'),并将|d'-y||d-y|进行比较,如果较小则以这种方式继续(并将d'替换为d),否则,将d'乘以最小的消除因子,并再次将其距离与y进行比较。

答案 2 :(得分:2)

这很有效,因为我可以得到它:

from fractions import gcd
primes=[i for i in range(2,1000) if all(i%j!=0 for j in range(2,i))] #ensure you have enough primes.. (can improve efficency here)


def f(x1,x2,y):
    _gcd=gcd(x1,x2)
    if _gcd==1:
        return 1
    factors=(i for i in range(2,_gcd+1) if _gcd%i==0) #can improve efficiency here.. e.g. only go up to root(gcd)
    r1=999999999
    r2=999999999
    for i in factors:
        r1=min(r1,y%i)
        r2=min(r2,i-y%i)
    return y-r1 if r1<=r2 else y+r2


print f(8,4,3)
print f(16,12,5)
print f(997,53,44)
print f(2300*2,2300*3,57)

"""
2
4
1
56
"""

答案 3 :(得分:0)

  1. 找到x1x2的GCD。
  2. 如果GCD <= Y,则返回GCD
  3. 目前最佳答案为GCD,最佳距离为GCD - y
  4. 遍历所有数字Y +/- [0 ...最佳距离]
  5. 返回第一个整数,它是x1x2
  6. 的倍数

    找到GCD

    public int getGCD( int a, int b )
    {
       return (b==0) ? a : gcd(b, a%b);
    }
    

    找到与y最接近的除数......

    public int closestDivisor( int a, int b, int y ){
        int gcd = getGCD( a, b );
        if( gcd <= y ) return gcd;
        int best = gcd - y;
        for( int i = 0; i < best; i++ )
        {
            if( gcd % (i-y) == 0 ) return i - y;
            if( gcd % (i+y) == 0 ) return i + y;
        }
        return gcd;
    }
    

    我认为唯一可用的额外优化是将gcd(可能使用筛子?)视为@trinithis建议的因素。