The previous answers iteratively searches for a coprime, and running in O(coprime gap after num) gcd invokes. A long, long, long processing time could be needed with this algorithm.
Take a number like 47897850, its integer square root is 6920, and it can be verified that 23 gcd calculations are needed before finding 6943 as the first coprime to 47897850.
gcd( 47897850 , 6920 ) = 10
gcd( 47897850 , 6921 ) = 3
gcd( 47897850 , 6922 ) = 2
gcd( 47897850 , 6923 ) = 7
gcd( 47897850 , 6924 ) = 6
gcd( 47897850 , 6925 ) = 25
gcd( 47897850 , 6926 ) = 2
gcd( 47897850 , 6927 ) = 3
gcd( 47897850 , 6928 ) = 2
gcd( 47897850 , 6929 ) = 13
gcd( 47897850 , 6930 ) = 2310
gcd( 47897850 , 6931 ) = 29
gcd( 47897850 , 6932 ) = 2
gcd( 47897850 , 6933 ) = 3
gcd( 47897850 , 6934 ) = 2
gcd( 47897850 , 6935 ) = 5
gcd( 47897850 , 6936 ) = 6
gcd( 47897850 , 6937 ) = 7
gcd( 47897850 , 6938 ) = 2
gcd( 47897850 , 6939 ) = 3
gcd( 47897850 , 6940 ) = 10
gcd( 47897850 , 6941 ) = 11
gcd( 47897850 , 6942 ) = 78
gcd( 47897850 , 6943 ) = 1
And the following numbers full of small factors are an example of increased calculation costs when trying to find the very first coprime to num larger than integer sqrt(num)
4 = 2^2
12 = 2^2 × 3
6 = 2 × 3
585 = 3^2 × 5 × 13
42 = 2 × 3 × 7
8400 = 2^4 × 3 × 5^2 × 7
930 = 2 × 3 × 5 × 31
1110 = 2 × 3 × 5 × 37
1974 = 2 × 3 × 7 × 47
13860 = 2^2 × 3^2 × 5 × 7 × 11
44310 = 2 × 3 × 5 × 7 × 211
87360 = 2^6 × 3 × 5 × 7 × 13
86940 = 2^2 × 3^3 × 5 × 7 × 23
3361050 = 2 × 3^2 × 5^2 × 7 × 11 × 97
8873304 = 2^3 × 3 × 11 × 19 × 29 × 61
4774770 = 2 × 3^2 × 5 × 7 × 11 × 13 × 53
13988370 = 2 × 3 × 5 × 11 × 19 × 23 × 97
47940480 = 2^7 × 3^2 × 5 × 7 × 29 × 41
42286650 = 2 × 3 × 5^2 × 7 × 17 × 23 × 103
50854650 = 2 × 3 × 5^2 × 7^2 × 11 × 17 × 37
60233040 = 2^4 × 3^2 × 5 × 7 × 17 × 19 × 37
52644900 = 2^2 × 3 × 5^2 × 7 × 11 × 43 × 53
47897850 = 2 × 3 × 5^2 × 7 × 11^2 × 13 × 29
....
The maximum "coprime gap" size after a number n seems to grow in O(ln(n))
It would be faster to iterate constructively by opportunistically accumulate the factors of the input number when they are the outputs of gcd. Worst case, this will run in less than O(#factors num) gcd invokes.
I modified the python script as follows:
import random
import time
bit = 512 # even
start = time.time()
pow = 2**bit
num = random.randrange(pow >> 1, pow - 1)
end = time.time()
print("random number num:")
print(num)
print("time for generating random number: %f"%(end-start))
print()
def sqrt(a,b):
# integer square root (wiki)
res = 0
pow = 2**b
num = a
while pow:
if num >= res + pow:
num -= res + pow
res = (res >> 1) + pow
else:
res >>= 1
pow >>= 2
return res
start = time.time()
sqrn = sqrt(num, bit)
end = time.time()
print("square root number sqrt(num):")
print(sqrn)
print("square of squareroot number:")
print(sqrn*sqrn)
print("time for generating integer square root: %f"%(end-start))
print()
def gcd(a,b):
while a: a,b = b%a,a
return b
def coprime(a, b):
# constructively compute the coprime of a given number a,
# starting from some arbitrary randomness
# input b : any random start number
# input a : number
# output res : with res < a, coprime to a and close(ish) to b
b = 1 + (b % (a - 1)) # make sure 0 < b < a
factors = 1
res = b
while True:
g = gcd(res,a)
if (g == 1): break;
factors *= g # accumulate multiple factors of a found in b
res = b + factors - 1
# now res is coprime to a, and res % a is also coprime to a, and res < a
res %= a
return res
start = time.time()
c = coprime(num, sqrn);
end = time.time()
print("number coprime to num close(ish) to sqrt(num):")
print(c)
print("verify with gcd(num, coprime to num)")
print(gcd(num, c))
print("time for generating co-prime number: %f"%(end-start))
print()
With the modified algorithm, the output of the python script is
random number num:
11185931069012882618484249292312310042666137944360829367669494242527613887036910725486770684387712709721024564190939992975044065122017303009053576484841785
time for generating random number: 0.000012
square root number sqrt(num):
105763562104407596481968445281612018565294009154907045716655815866995991158313
square of squareroot number:
11185931069012882618484249292312310042666137944360829367669494242527613887036832565809732701215533464477407018527101343984451072439242764775553671429005969
time for generating integer square root: 0.000097
number coprime to num close(ish) to sqrt(num):
105763562104407596481968445281612018565294009154907045716655815866995991158404
verify with gcd(num, coprime to num)
1
time for generating co-prime number: 0.000057
Then
6 = 2 × 3 <-- smallest number with 2 gcd calculations
78 = 2 × 3 × 13 <-- smallest number with 3 gcd calculations
13464 = 2^3 × 3^2 × 11 × 17 <-- smallest number with 4 gcd calculations
396825 = 3 × 5^2 × 11 × 13 × 37 <-- smallest number with 5 gcd calculations
13679820 = 2^2 × 3^3 × 5 × 72 × 11 × 47 <-- smallest number with 6 gcd calculations
10360350 = 2 × 3^2 × 5^2 × 7 × 11 × 13 × 23 <-- smallest number with 7 gcd calculations
4894696950 = 2 × 3 × 5^2 × 11 × 13 × 17 × 31 × 433 <-- smallest number with 8 gcd calculations
....
15359277570 = 2 × 3 × 5 × 7 × 13 × 19 × 37 × 53 × 151
....
The worst case of complexity of the modified algorithm seems to grow with the number of distinct prime factors in O(ln(ln(num))).
log(n). That's fine. However, there are, for example, primes of particular classes that are just "known", e.g. Mersenne primes. One could take a couple of those and check a simple division. Mersenne primes are too sparse to get near the sqrt of an arbitrary number though. – Him Sep 15 '17 at 15:52