Python、83 82 79 76 73バイト
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バイト
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
この関数はLucas–Lehmerの素数性テストを実装しているため、他のPython製品のいくつかほど短くはありませんが、巨大な入力の処理ははるかに高速です。
Python 2または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)
出力
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、すべてのループでf
再テストしないわずかに効率的なバージョンがありm
ます:
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