Fermat primality test too slow - issues with big integers - python

This is my code for Fermat's primality test:
def fermat(n):
counter = 0
prime = False
if n >= 40:
upper_bound = 40
else:
upper_bound = n - 1
for a in range(2, upper_bound + 1):
print(a)
if pow_mod(a, n - 1, n) == 1:
counter += 1
if counter == n - 2 and upper_bound == n - 1 or counter == 39 and upper_bound == 40:
prime = True
return prime
pow_mod function calculates a^b mod n with repeated multiplication, applying mod n each time, like this:
def pow_mod(a, b, n):
result = 1
for i in range(b):
result = result * a % n
return result
It works for relatively small primes. However, if I run it for a large prime such as 67280421310721, it doesn't produce a result in a desirable amount of time. Is it due to the large numbers? How do I fix this?

It's because your pow_mod is terribly slow. Use a fast algorithm or just use Python's built-in pow function.
Btw, if I understand your rather convoluted code correctly, you're simply checking whether all tests were successful. Which can be written more clearly:
def fermat(n):
upper_bound = 40 if n >= 40 else n - 1
return all(pow(a, n - 1, n) == 1
for a in range(2, upper_bound + 1))

Related

What's the most efficient way to find Wilson Prime number using python?

I have written a code of Wilson prime numbers and my code is working for most of the numbers but it's giving OverflowError: int too large to convert to float for very large numbers. Is there any way to write Wilson prime number code for very large numbers.
The main problem is for checking Wilson prime Wilson primes it should satisfy the following condition. Where P represents a prime number.
Then ((P-1)! + 1) / (P * P) should give a whole number.
And as you can see factorials are involved in this procedure, so for very large numbers it's pretty difficult.
My Code :
def am_i_wilson(n):
import math
n1 = math.sqrt(n)
n1 = math.ceil(n1)
c = 0
def fact(n):
num = 1
for i in range(2,n+1):
num = num*i
return num
if n <= 1:
return False
for i in range(2, n1 + 1):
if n%i == 0:
c+ = 1
if c != 0:
return False
x = (fact(n-1)+1)/((n**2)*1.0)
return x.is_integer()
In my code, I am returning True if the number is Wilson Prime else False. Here n is the number to check if it's Wilson prime or not.
I think this is the most efficient way
import math
def am_i_wilson(num):
if num < 2 or not all(n % i for i in range(2, num)):
return False
return (math.factorial(num - 1) + 1) % (num ** 2) == 0
or you can try this too
import math
def am_i_wilson(n):
if n <= 2:
return False
fact=math.factorial(n-1)
#this conditional checks that the number is prime or not
#this condition is called wilson theorem in number theory
if (fact+1)%n==0:
x = (fact+1)%(n**2)
if x==0:
return True
else:
return False
else:
return False
if anyone has any better method then please answer it.
Your program primarily relies on testing for primes and computing factorials. You separate out the factorial logic but embed an inefficient prime test -- it keeps testing remainders after it knows the number isn't prime! I would separate both out so that they can be tested and optimized independently of the Wilson prime test itself:
def factorial(n):
number = 1
for i in range(2, n + 1):
number *= i
return number
def am_i_prime(n):
if n < 2:
return False
if n % 2 == 0:
return n == 2
for divisor in range(3, int(n ** 0.5) + 1, 2):
if n % divisor == 0:
return False
return True
def am_i_wilson(n):
return am_i_prime(n) and (factorial(n - 1) + 1) % n ** 2 == 0
A more efficient approach, given a fixed target to test up to, would be to implement a prime sieve and for each prime encountered, while you're computing the sieve, test if it's a Wilson prime.
I've been experimenting with prime sieves recently. I did a quick modification (i.e. hack) to one of them written by Robert William Hanks and came up with this. Output first:
$ ./wilson_primes.py 10000
[5, 13, 563]
...so I suspect the Wikipedia article about Wilson primes is correct ;-)
import sys
def fact(n):
num = 1
for i in range(2, n+1):
num *= i
return num
def is_wilson(n):
return (fact(n-1)+1) % n**2 == 0
def rwh_primes1(n):
""" Returns a list of primes < n """
sieve = [True] * (n/2)
for i in range(3,int(n**0.5)+1,2):
if sieve[i/2]:
sieve[i*i/2::i] = [False] * ((n-i*i-1)/(2*i)+1)
# return [2] + [2*i+1 for i in xrange(1,n/2) if sieve[i]]
for i in range(1,n/2):
if sieve[i]:
p = 2*i + 1 # convert index to normal prime
if is_wilson(p): #
yield p #
if len(sys.argv) > 1:
N = int(float(sys.argv[1]))
else:
N = 10000 # default: 1e4 10,000
print [p for p in rwh_primes1(N)]
First I tried just the fact() function and was pleasantly surprised to see it can produce huge results. But it is very slow compared to the original prime sieve. Perhaps it could be made to run faster by remembering the last factorial computed and re-use that to skip part of next factorial computation.
EDIT
I changed fact() to remember its last result, as follows:
last_fact = 1
last_n = 1
def fact2(n):
global last_fact, last_n
num = last_fact
for i in range(last_n+1, n+1):
num *= i
last_n = n
last_fact = num
return num
def is_wilson(n):
return (fact2(n-1)+1) % n**2 == 0
That did speed it up quite a bit. cProfile shows that is_wilson() is now the bottleneck. I can't think of an easy way to make it faster.

How to get a prime collection within 2^63 - 1 in Python

I want to get a prime number set within 2^63 - 1 in Python,I have seen the following code on the web:
limit = 2**63 - 2
p = [True] * (limit + 1)
# p = bitarray(limit + 1)
p[0] = p[1] = False
for i in range(2, int(math.sqrt(limit) + 1)):
if p[i]:
for j in range(i * i, limit + 1, i):
p[j] = False
prime = [i for i in range(limit + 1) if p[i]]
print(prime)
But when I run this program, the compiler complains that can not fit 'int' into an index-sized integer.
I tried to solve the problem with bitarray, but the index of the array is still too big.
You can use the following code. It is using the Sieve of Eratosthenes in combination with a generator function in order to reduce the memory usage of this algorithm. It is furthermore exploiting the less commonly known fact that every prim number > 4 can be written as 6*n ± 1.
import math
limit = 2 ** 63 - 1
def isPrim(n, belowPrims):
limit = int(math.sqrt(n))
for prim in belowPrims:
if prim > limit: break
if n % prim == 0: return False
return True
def calcPrims():
yield 2
yield 3
toTest, nextN = [], 6
while True:
p1 = nextN - 1
if isPrim(p1, toTest):
yield p1
toTest.append(p1)
p2 = nextN + 1
if isPrim(p2, toTest):
yield p2
toTest.append(p2)
nextN += 6
for prim in calcPrims():
if prim > limit:
break
print(prim)
Edit
This link here https://primes.utm.edu/notes/faq/six.html explains briefly why every prim number can be written in the form 6*n ± 1.
You can use sympy:
import sympy
print(list(sympy.primerange(0,2**63-1)))
but as 2^63 is quite large this will take some time.
if you have a primes() generator of some kind, you could do this:
is_prime_var = 0
MAX = 1 << 5
last_p = 0
for p in primes():
if p > MAX:
break
print(p, p-last_p)
is_prime_var <<= (p - last_p)
is_prime_var |= 1
last_p = p
is_prime_var <<= (MAX - last_p - 1)
now the locations of the primes are stored (in reversed order) in the integer is_prime_var.
then the expression (is_prime >> (MAX-n-1)) & 1 would be 1 if n is prime; 0 otherwise:
def is_prime(n):
return bool((is_prime_var >> (MAX-n-1)) & 1)
you could use primes() from this excellent answer as prime generator.
thers is also this answer of mine about a fast and memory-efficient sieve of eratosthenes. might also be interesting.

Probability of finding a prime (using miller-rabin test)

I've implemented Miller-Rabin primality test and every function seems to be working properly in isolation. However, when I try to find a prime by generating random numbers of 70 bits my program generates in average more than 100000 numbers before finding a number that passes the Miller-Rabin test (10 steps). This is very strange, the probability of being prime for a random odd number of less than 70 bits should be very high (more than 1/50 according to Hadamard-de la Vallée Poussin Theorem). What could be wrong with my code? Would it be possible that the random number generator throws prime numbers with very low probability? I guess not... Any help is very welcome.
import random
def miller_rabin_rounds(n, t):
'''Runs miller-rabin primallity test t times for n'''
# First find the values r and s such that 2^s * r = n - 1
r = (n - 1) / 2
s = 1
while r % 2 == 0:
s += 1
r /= 2
# Run the test t times
for i in range(t):
a = random.randint(2, n - 1)
y = power_remainder(a, r, n)
if y != 1 and y != n - 1:
# check there is no j for which (a^r)^(2^j) = -1 (mod n)
j = 0
while j < s - 1 and y != n - 1:
y = (y * y) % n
if y == 1:
return False
j += 1
if y != n - 1:
return False
return True
def power_remainder(a, k, n):
'''Computes (a^k) mod n efficiently by decomposing k into binary'''
r = 1
while k > 0:
if k % 2 != 0:
r = (r * a) % n
a = (a * a) % n
k //= 2
return r
def random_odd(n):
'''Generates a random odd number of max n bits'''
a = random.getrandbits(n)
if a % 2 == 0:
a -= 1
return a
if __name__ == '__main__':
t = 10 # Number of Miller-Rabin tests per number
bits = 70 # Number of bits of the random number
a = random_odd(bits)
count = 0
while not miller_rabin_rounds(a, t):
count += 1
if count % 10000 == 0:
print(count)
a = random_odd(bits)
print(a)
The reason this works in python 2 and not python 3 is that the two handle integer division differently. In python 2, 3/2 = 1, whereas in python 3, 3/2=1.5.
It looks like you should be forcing integer division in python 3 (rather than float division). If you change the code to force integer division (//) as such:
# First find the values r and s such that 2^s * r = n - 1
r = (n - 1) // 2
s = 1
while r % 2 == 0:
s += 1
r //= 2
You should see the correct behaviour regardless of what python version you use.

An Explanation for the totient finder in this program

I need an explanation for the program suggested in the edit in the first answer over here. It is a program to find the totients of a range of numbers. Can somebody provide a simple explanation? (Ignore the summation part for now, I need to find out how the init method finds the totients.) I know there is an explanation in the answer, but that is an explanation for different programs, I need an explanation for this particular one.
class Totient:
def __init__(self, n):
self.totients = [1 for i in range(n)]
for i in range(2, n):
if self.totients[i] == 1:
for j in range(i, n, i):
self.totients[j] *= i - 1
k = j / i
while k % i == 0:
self.totients[j] *= i
k /= i
def __call__(self, i):
return self.totients[i]
if __name__ == '__main__':
from itertools import imap
totient = Totient(10000)
print sum(imap(totient, range(10000)))
It's a variant of the Sieve of Eratosthenes for finding prime numbers.
If you want to know the totient of a single number n, the best way to find it is to factor n and take the product of 1 less than each factor; for instance, 30 = 2 * 3 * 5, and subtracting 1 from each factor, then multiplying, gives the totient 1 * 2 * 4 = 8. But if you want to find the totients of all the numbers less than a given n, a better approach than factoring each of them is sieving. The idea is simple: Set up an array X from 0 to n, store i in each Xi, then run through the array starting from 0 and whenever Xi = i loop over the multiples of i, multiplying each by i − 1.
Further discussion and code at my blog.
I'm not completely sure what the code is doing -- but frankly it looks pretty bad. It clearly is trying to use that Euler's totient function is multiplicative, meaning that a,b are relatively prime then t(a,b) = t(a)*t(b), together with the fact that if p is a prime then t(p) = p-1. But -- it seems to be using crude trial division to determine such things. If you really want to calculate the totient of all numbers in a given range then you should use an algorithm that sieves the numbers as you go along.
Here is a version which sieves as it goes and exploits the multiplicative nature to the hilt. At each pass through the main loop it starts with a prime, p which hasn't yet been processed. It determines all powers of p <= n and then uses a direct formula for these powers (see https://en.wikipedia.org/wiki/Euler%27s_totient_function ). Once these totients have been added, it forms all possible products <= n of these powers and the numbers for which the totients have been previously computed. This gives a whole slew of numbers to add to the list of previously determined numbers. At most sqrt(n) passes need to be made through the main loop. It runs almost instantly for n = 10000. It returns a list where the ith value is the totient of i (with t(0) = 0 for convenience):
def allTotients(n):
totients = [None]*(n+1) #totients[i] will contain the t(i)
totients[0] = 0
totients[1] = 1
knownTotients = [] #known in range 2 to n
p = 2
while len(knownTotients) < n - 1:
powers = [p]
k = 2
while p ** k <= n:
powers.append(p ** k)
k +=1
totients[p] = p - 1
for i in range(1,len(powers)):
totients[powers[i]] = powers[i] - powers[i-1]
#at this stage powers represent newly discovered totients
#combine with previously discovered totients to get still more
newTotients = powers[:]
for m in knownTotients:
for pk in powers:
if m*pk > n: break
totients[m*pk] = totients[m]*totients[pk]
newTotients.append(m*pk)
knownTotients.extend(newTotients)
#if there are any unkown totients -- the smallest such will be prime
if len(knownTotients) < n-1:
p = totients.index(None)
return totients
For completeness sake, here is a Python implementation of the algorithm to compute the totient of a single number which user448810 described in their answer:
from math import sqrt
#crude factoring algorithm:
small_primes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,
53,59,61,67,71,73,79,83,89,97]
def factor(n):
#returns a list of prime factors
factors = []
num = n
#first pull out small prime factors
for p in small_primes:
while num % p == 0:
factors.append(p)
num = num // p
if num == 1: return factors
#now do trial division, starting at 101
k = 101
while k <= sqrt(num):
while num % k == 0:
factors.append(k)
num = num // k
k += 2
if num == 1:
return factors
else:
factors.append(num)
return factors
def totient(n):
factors = factor(n)
unique_factors = set()
t = 1
for p in factors:
if p in unique_factors:
t *= p
else:
unique_factors.add(p)
t *= (p-1)
return t

Computing Eulers Totient Function

I am trying to find an efficient way to compute Euler's totient function.
What is wrong with this code? It doesn't seem to be working.
def isPrime(a):
return not ( a < 2 or any(a % i == 0 for i in range(2, int(a ** 0.5) + 1)))
def phi(n):
y = 1
for i in range(2,n+1):
if isPrime(i) is True and n % i == 0 is True:
y = y * (1 - 1/i)
else:
continue
return int(y)
Here's a much faster, working way, based on this description on Wikipedia:
Thus if n is a positive integer, then φ(n) is the number of integers k in the range 1 ≤ k ≤ n for which gcd(n, k) = 1.
I'm not saying this is the fastest or cleanest, but it works.
from math import gcd
def phi(n):
amount = 0
for k in range(1, n + 1):
if gcd(n, k) == 1:
amount += 1
return amount
You have three different problems...
y needs to be equal to n as initial value, not 1
As some have mentioned in the comments, don't use integer division
n % i == 0 is True isn't doing what you think because of Python chaining the comparisons! Even if n % i equals 0 then 0 == 0 is True BUT 0 is True is False! Use parens or just get rid of comparing to True since that isn't necessary anyway.
Fixing those problems,
def phi(n):
y = n
for i in range(2,n+1):
if isPrime(i) and n % i == 0:
y *= 1 - 1.0/i
return int(y)
Calculating gcd for every pair in range is not efficient and does not scales. You don't need to iterate throught all the range, if n is not a prime you can check for prime factors up to its square root, refer to https://stackoverflow.com/a/5811176/3393095.
We must then update phi for every prime by phi = phi*(1 - 1/prime).
def totatives(n):
phi = int(n > 1 and n)
for p in range(2, int(n ** .5) + 1):
if not n % p:
phi -= phi // p
while not n % p:
n //= p
#if n is > 1 it means it is prime
if n > 1: phi -= phi // n
return phi
I'm working on a cryptographic library in python and this is what i'm using. gcd() is Euclid's method for calculating greatest common divisor, and phi() is the totient function.
def gcd(a, b):
while b:
a, b=b, a%b
return a
def phi(a):
b=a-1
c=0
while b:
if not gcd(a,b)-1:
c+=1
b-=1
return c
Most implementations mentioned by other users rely on calling a gcd() or isPrime() function. In the case you are going to use the phi() function many times, it pays of to calculated these values before hand. A way of doing this is by using a so called sieve algorithm.
https://stackoverflow.com/a/18997575/7217653 This answer on stackoverflow provides us with a fast way of finding all primes below a given number.
Oke, now we can replace isPrime() with a search in our array.
Now the actual phi function:
Wikipedia gives us a clear example: https://en.wikipedia.org/wiki/Euler%27s_totient_function#Example
phi(36) = phi(2^2 * 3^2) = 36 * (1- 1/2) * (1- 1/3) = 30 * 1/2 * 2/3 = 12
In words, this says that the distinct prime factors of 36 are 2 and 3; half of the thirty-six integers from 1 to 36 are divisible by 2, leaving eighteen; a third of those are divisible by 3, leaving twelve numbers that are coprime to 36. And indeed there are twelve positive integers that are coprime with 36 and lower than 36: 1, 5, 7, 11, 13, 17, 19, 23, 25, 29, 31, and 35.
TL;DR
With other words: We have to find all the prime factors of our number and then multiply these prime factors together using foreach prime_factor: n *= 1 - 1/prime_factor.
import math
MAX = 10**5
# CREDIT TO https://stackoverflow.com/a/18997575/7217653
def sieve_for_primes_to(n):
size = n//2
sieve = [1]*size
limit = int(n**0.5)
for i in range(1,limit):
if sieve[i]:
val = 2*i+1
tmp = ((size-1) - i)//val
sieve[i+val::val] = [0]*tmp
return [2] + [i*2+1 for i, v in enumerate(sieve) if v and i>0]
PRIMES = sieve_for_primes_to(MAX)
print("Primes generated")
def phi(n):
original_n = n
prime_factors = []
prime_index = 0
while n > 1: # As long as there are more factors to be found
p = PRIMES[prime_index]
if (n % p == 0): # is this prime a factor?
prime_factors.append(p)
while math.ceil(n / p) == math.floor(n / p): # as long as we can devide our current number by this factor and it gives back a integer remove it
n = n // p
prime_index += 1
for v in prime_factors: # Now we have the prime factors, we do the same calculation as wikipedia
original_n *= 1 - (1/v)
return int(original_n)
print(phi(36)) # = phi(2**2 * 3**2) = 36 * (1- 1/2) * (1- 1/3) = 36 * 1/2 * 2/3 = 12
It looks like you're trying to use Euler's product formula, but you're not calculating the number of primes which divide a. You're calculating the number of elements relatively prime to a.
In addition, since 1 and i are both integers, so is the division, in this case you always get 0.
With regards to efficiency, I haven't noticed anyone mention that gcd(k,n)=gcd(n-k,n). Using this fact can save roughly half the work needed for the methods involving the use of the gcd. Just start the count with 2 (because 1/n and (n-1)/k will always be irreducible) and add 2 each time the gcd is one.
Here is a shorter implementation of orlp's answer.
from math import gcd
def phi(n): return sum([gcd(n, k)==1 for k in range(1, n+1)])
As others have already mentioned it leaves room for performance optimization.
Actually to calculate phi(any number say n)
We use the Formula
where p are the prime factors of n.
So, you have few mistakes in your code:
1.y should be equal to n
2. For 1/i actually 1 and i both are integers so their evaluation will also be an integer,thus it will lead to wrong results.
Here is the code with required corrections.
def phi(n):
y = n
for i in range(2,n+1):
if isPrime(i) and n % i == 0 :
y -= y/i
else:
continue
return int(y)

Categories