Python, 83 82 79 76 73 bytes
def f(m):
s,n=(m!=3)*4,m>>2
while-~m&m<n:s,n=(s*s-2)%m,n>>1
return s<1
Python 2, 71 bytes
def f(m):
s,n=(m!=3)*4,m/4
while-~m&m<n:s,n=(s*s-2)%m,n/2
return s<1
This function implements the Lucas–Lehmer primality test, so while it isn't as short as some of the other Python offerings it's much faster at handling huge inputs.
Here's some test code that runs on Python 2 or Python 3.
from __future__ import print_function
def primes(n):
""" Return a list of primes < n """
# From http://stackoverflow.com/a/3035188/4014959
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 range(1, n//2) if sieve[i]]
def lucas_lehmer_old(p):
m = (1 << p) - 1
s = 4
for i in range(p - 2):
s = (s * s - 2) % m
return s == 0 and m or 0
# much faster
def lucas_lehmer(p):
m = (1 << p) - 1
s = 4
for i in range(p - 2):
s = s * s - 2
while s > m:
s = (s & m) + (s >> p)
return s == 0 or s == m and m or 0
def f(m):
s,n=(m!=3)*4,m>>2
while-~m&m<n:s,n=(s*s-2)%m,n>>1
return s<1
# Make a list of some Mersenne primes
a = [3]
for p in primes(608):
m = lucas_lehmer(p)
if m:
print(p, m)
a.append(m)
print()
# Test that `f` works on all the numbers in `a`
print(all(map(f, a)))
# Test `f` on numbers that may not be Mersenne primes
for i in range(1, 525000):
u = f(i)
v = i in a
if u or v:
print(i, u, v)
if u != v:
print('Error:', i, u, v)
output
3 7
5 31
7 127
13 8191
17 131071
19 524287
31 2147483647
61 2305843009213693951
89 618970019642690137449562111
107 162259276829213363391578010288127
127 170141183460469231731687303715884105727
521 6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151
607 531137992816767098689588206552468627329593117727031923199444138200403559860852242739162502265229285668889329486246501015346579337652707239409519978766587351943831270835393219031728127
True
3 True True
7 True True
31 True True
127 True True
8191 True True
131071 True True
524287 True True
FWIW, here's a slightly more efficient version of f
that doesn't re-test m
on every loop:
def f(m):
s,n=m!=3and 4,m>>2
if-~m&m<1:
while n:
s=(s*s-2)%m
n>>=1
return s<1