I have two numbers, x1
and x2
. For a number y
, I want to calculate the common divisor of x1
and x2
as close
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!
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.
x1
and x2
. GCD <= Y
then return GCD
GCD
, with a best distance of GCD - y
.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.
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
"""