可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have two numbers, x1
and x2
. For a number y
, I want to calculate the common divisor of x1
and x2
as close as possible to y
.
Is there an efficient algorithm for this?
I believe it's time to rephrase my problem and be more clear. This is not about integers...
So, say we have two numbers x1
and x2
. Say, the user inputs a number y
. What I want to find, is a number y'
close to y
so that x1 % y'
and x2 % y'
are very small (smaller than 0.02
, for example, but lets call this number LIMIT
). In other words, I don't need an optimal algorithm, but a good approximation.
I thank you all for your time and effort, that's really kind!
回答1:
I believe that there is no known efficient (polynomial-time) algorithm for this problem because there is a polynomial-time reduction from integer factorization to this problem. Since there is no known polynomial-time algorithm for integer factorization, there cannot be a known algortihm for your problem either, since otherwise we would indeed have a polynomial-time algorithm for integer factorization.
To see how this works, suppose you have a number n that you'd like to factor. Now, using whatever algorithm you'd like, find the common factor of n and n closest to √n. Since no nontrivial divisor of n can be greater than √n, this finds either (1) the largest integer that divides n, or (2) the number 1 if n is prime. You can then divide n by this number and repeat to produce all the factors of n. Since n can have at most O(log n) factors, this requires at most polynomially many iterations of the solver for your problem, so we have a polynomial-time reduction from integer factorization to this problem. As mentioned above, this means that, at least in the open literature, there is no known efficient classical algorithm for solving this problem. One might exist, but it would be a really hugely important result.
Sorry for the negative answer, and hope this helps!
回答2:
This is efficient as I can get it:
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:
I think you can do it by greedy algorithm, first find GCD by common algorithms name it d
(which is computable in logarithmic time) then find factors of d
each time divide d
to smallest available factor (create d'
), and compare |d'-y|
with |d-y|
if is smaller continue in this way (and replace d'
with d
), else, multiply d'
with smallest eliminated factor, and again compare its distance to y.
回答4:
- Find the GCD of
x1
and x2
.
- If
GCD <= Y
then return GCD
- Current best answer is
GCD
, with a best distance of GCD - y
.
- Iterate through all numbers Y +/- [0 ... best distance]
- Return the first integer that is a multiple of both
x1
and x2
To find the GCD
public int getGCD( int a, int b )
{
return (b==0) ? a : gcd(b, a%b);
}
To find closest divisor to 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;
}
I believe the only additional optimization available would be to factor the gcd (perhaps using a sieve?) as @trinithis suggested.