आरपीथॉन (PyPy 4.0.1), 4032
RPython Python का प्रतिबंधित उपसमूह है, जिसे C में अनुवाद किया जा सकता है और फिर RPython टूलबार का उपयोग करके संकलित किया जा सकता है। इसका व्यक्त उद्देश्य भाषा दुभाषियों के निर्माण में सहायता करना है, लेकिन इसका उपयोग सरल कार्यक्रमों को संकलित करने के लिए भी किया जा सकता है।
संकलन करने के लिए, वर्तमान PyPy स्रोत (PyPy 4.0.1) को डाउनलोड करें, और निम्नलिखित को चलाएँ:
$ pypy /pypy-4.0.1-src/rpython/bin/rpython --opt=3 good-primes.py
परिणामी निष्पादन योग्य का नाम good-primes-c
या वर्तमान कार्य निर्देशिका में समान होगा ।
कार्यान्वयन नोट्स
प्राइम नंबर जनरेटर primes
इरेटोस्थनीज की एक अनबाउंड छलनी है, जो 2 , 3 , 5 , या 7 के किसी भी गुणकों से बचने के लिए एक पहिया का उपयोग करता है । यह अंकन के लिए उपयोग करने के लिए अगले मूल्य को उत्पन्न करने के लिए खुद को पुनरावर्ती भी कहता है। मैं इस जनरेटर से काफी संतुष्ट हूं। लाइन प्रोफाइलिंग से पता चलता है कि सबसे धीमी दो लाइनें हैं:
37> n += o
38> if n not in sieve:
इसलिए मुझे नहीं लगता कि सुधार के लिए बहुत जगह है, शायद एक बड़े पहिये का उपयोग करने के अलावा।
"अच्छाई" की जांच के लिए, दो के सभी कारकों को n-1 से हटा दिया जाता है , दो की सबसे बड़ी शक्ति खोजने के लिए बिट-टिडलिंग हैक का उपयोग करके जो एक भाजक है (n-1 & 1-n)
। क्योंकि p-1 आवश्यक रूप से किसी भी प्रधान p> 2 के लिए भी है , यह इस प्रकार है कि 2 अलग-अलग प्रमुख कारकों में से एक होना चाहिए। जो शेष रह जाता है उसे is_prime_power
फंक्शन में भेजा जाता है , जो उसका नाम बताता है। यह जाँचना कि क्या कोई मान प्रधान शक्ति "लगभग मुफ़्त" है, क्योंकि यह एक साथ प्रायोगिक जाँच के साथ किया जाता है, जिसमें अधिकांश O (log p n) संचालन होते हैं, जहाँ p n का सबसे छोटा प्रधान कारक है। परीक्षण विभाजन थोड़ा भोला लग सकता है, लेकिन मेरे परीक्षण से यह 2 32 से कम मूल्यों के लिए सबसे तेज़ विधि है । मैं छलनी से पहिया का पुन: उपयोग करके थोड़ी बचत करता हूं। विशेष रूप से:
59> while p*p < n:
60> for o in offsets:
लंबाई 48 के एक पहिये पर चलने से, p*p < n
चेक को हजारों बार, कम से कम, 48 अतिरिक्त मॉडुलो ऑपरेशंस के कम मूल्य पर छोड़ दिया जाएगा। यह सभी उम्मीदवारों के 77% से अधिक अंकों को छोड़ देता है, केवल 50% के बजाय केवल बाधाओं को लेकर।
पिछले कुछ आउटपुट हैं:
3588 (987417437 - 987413849) 60.469000s
3900 (1123404923 - 1123401023) 70.828000s
3942 (1196634239 - 1196630297) 76.594000s
4032 (1247118179 - 1247114147) 80.625000s
4176 (1964330609 - 1964326433) 143.047000s
4224 (2055062753 - 2055058529) 151.562000s
कोड भी मान्य पायथन है, और हाल ही में PyPy दुभाषिया के साथ चलने पर 3588 ~ 3900 तक पहुंच जाना चाहिए।
# primes less than 212
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,101,103,107,109,113,127,131,137,139,149,151,
157,163,167,173,179,181,191,193,197,199,211]
# pre-calced sieve of eratosthenes for n = 2, 3, 5, 7
# distances between sieve values, starting from 211
offsets = [
10, 2, 4, 2, 4, 6, 2, 6, 4, 2, 4, 6,
6, 2, 6, 4, 2, 6, 4, 6, 8, 4, 2, 4,
2, 4, 8, 6, 4, 6, 2, 4, 6, 2, 6, 6,
4, 2, 4, 6, 2, 6, 4, 2, 4, 2,10, 2]
# tabulated, mod 105
dindices =[
0,10, 2, 0, 4, 0, 0, 0, 8, 0, 0, 2, 0, 4, 0,
0, 6, 2, 0, 4, 0, 0, 4, 6, 0, 0, 6, 0, 0, 2,
0, 6, 2, 0, 4, 0, 0, 4, 6, 0, 0, 2, 0, 4, 2,
0, 6, 6, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 4, 2,
0, 6, 2, 0, 4, 0, 0, 4, 6, 0, 0, 2, 0, 6, 2,
0, 6, 0, 0, 4, 0, 0, 4, 6, 0, 0, 2, 0, 4, 8,
0, 0, 2, 0,10, 0, 0, 4, 0, 0, 0, 2, 0, 4, 2]
def primes(start = 0):
for n in small_primes[start:]: yield n
pg = primes(6)
p = pg.next()
q = p*p
sieve = {221: 13, 253: 11}
n = 211
while True:
for o in offsets:
n += o
stp = sieve.pop(n, 0)
if stp:
nxt = n/stp
nxt += dindices[nxt%105]
while nxt*stp in sieve: nxt += dindices[nxt%105]
sieve[nxt*stp] = stp
else:
if n < q:
yield n
else:
sieve[q + dindices[p%105]*p] = p
p = pg.next()
q = p*p
def is_prime_power(n):
for p in small_primes:
if n%p == 0:
n /= p
while n%p == 0: n /= p
return n == 1
p = 211
while p*p < n:
for o in offsets:
p += o
if n%p == 0:
n /= p
while n%p == 0: n /= p
return n == 1
return n > 1
def main(argv):
from time import time
t0 = time()
m = 0
p = q = 7
pgen = primes(3)
for n in pgen:
d = (n-1 & 1-n)
if is_prime_power(n/d):
p, q = q, n
if q-p > m:
m = q-p
print m, "(%d - %d) %fs"%(q, p, time()-t0)
return 0
def target(*args):
return main, None
if __name__ == '__main__':
from sys import argv
main(argv)
आरपीथॉन (PyPy 4.0.1), 22596
यह सबमिशन अब तक पोस्ट किए गए अन्य की तुलना में थोड़ा अलग है, जिसमें यह सभी अच्छे प्राइम की जांच नहीं करता है, बल्कि इसके बजाय अपेक्षाकृत बड़े कूदता है। ऐसा करने का एक नुकसान यह है कि सीट्स का उपयोग नहीं किया जा सकता है [मैं सही खड़ा हूं?] , इसलिए किसी को पूरी तरह से व्यावहारिकता परीक्षण पर निर्भर रहना पड़ता है जो व्यवहार में थोड़ा धीमा है। विकास की दर और प्रत्येक बार जाँच किए गए मानों की संख्या के बीच मिलने वाला एक खुशहाल माध्यम भी है। छोटे मान जाँचने के लिए बहुत तेज़ हैं, लेकिन बड़े मानों में बड़े अंतराल होने की अधिक संभावना है।
गणित के देवताओं को खुश करने के लिए, मैंने एक फिबोनाची जैसे अनुक्रम का पालन करने का फैसला किया है, जिसमें अगले शुरुआती बिंदु पिछले दो के योग के रूप में हैं। यदि 10 जोड़ों की जांच के बाद कोई नया रिकॉर्ड नहीं मिलता है, तो स्क्रिप्ट अगले पर चलती है।
पिछले कुछ आउटपुट हैं:
6420 (12519586667324027 - 12519586667317607) 0.364000s
6720 (707871808582625903 - 707871808582619183) 0.721000s
8880 (626872872579606869 - 626872872579597989) 0.995000s
10146 (1206929709956703809 - 1206929709956693663) 4.858000s
22596 (918415168400717543 - 918415168400694947) 8.797000s
जब संकलित किया जाता है, तो 64-बिट पूर्णांक का उपयोग किया जाता है, हालांकि यह कुछ स्थानों पर माना जाता है कि दो पूर्णांकों को अतिप्रवाह के बिना जोड़ा जा सकता है, इसलिए व्यवहार में केवल 63 उपयोग योग्य हैं। 62 महत्वपूर्ण बिट्स तक पहुंचने पर, गणना में अतिप्रवाह से बचने के लिए, वर्तमान मूल्य को दो बार आधा किया जाता है। परिणाम यह है कि स्क्रिप्ट 2 60 - 2 62 रेंज पर मूल्यों के माध्यम से फेरबदल करता है । मूल पूर्णांक सटीकता को पार नहीं करने पर व्याख्या के दौरान स्क्रिप्ट को तेज बना देता है।
इस परिणाम की पुष्टि करने के लिए निम्नलिखित PARI / GP स्क्रिप्ट का उपयोग किया जा सकता है:
isgoodprime(n) = isprime(n) && omega(n-1)==2
for(n = 918415168400694947, 918415168400717543, {
if(isgoodprime(n), print(n" is a good prime"))
})
try:
from rpython.rlib.rarithmetic import r_int64
from rpython.rtyper.lltypesystem.lltype import SignedLongLongLong
from rpython.translator.c.primitive import PrimitiveType
# check if the compiler supports long long longs
if SignedLongLongLong in PrimitiveType:
from rpython.rlib.rarithmetic import r_longlonglong
def mul_mod(a, b, m):
return r_int64(r_longlonglong(a)*b%m)
else:
from rpython.rlib.rbigint import rbigint
def mul_mod(a, b, m):
biga = rbigint.fromrarith_int(a)
bigb = rbigint.fromrarith_int(b)
bigm = rbigint.fromrarith_int(m)
return biga.mul(bigb).mod(bigm).tolonglong()
# modular exponentiation b**e (mod m)
def pow_mod(b, e, m):
r = 1
while e:
if e&1: r = mul_mod(b, r, m)
e >>= 1
b = mul_mod(b, b, m)
return r
except:
import sys
r_int64 = int
if sys.maxint == 2147483647:
mul_mod = lambda a, b, m: a*b%m
else:
mul_mod = lambda a, b, m: int(a*b%m)
pow_mod = pow
# legendre symbol (a|m)
# note: returns m-1 if a is a non-residue, instead of -1
def legendre(a, m):
return pow_mod(a, (m-1) >> 1, m)
# strong probable prime
def is_sprp(n, b=2):
if n < 2: return False
d = n-1
s = 0
while d&1 == 0:
s += 1
d >>= 1
x = pow_mod(b, d, n)
if x == 1 or x == n-1:
return True
for r in xrange(1, s):
x = mul_mod(x, x, n)
if x == 1:
return False
elif x == n-1:
return True
return False
# lucas probable prime
# assumes D = 1 (mod 4), (D|n) = -1
def is_lucas_prp(n, D):
Q = (1-D) >> 2
# n+1 = 2**r*s where s is odd
s = n+1
r = 0
while s&1 == 0:
r += 1
s >>= 1
# calculate the bit reversal of (odd) s
# e.g. 19 (10011) <=> 25 (11001)
t = r_int64(0)
while s:
if s&1:
t += 1
s -= 1
else:
t <<= 1
s >>= 1
# use the same bit reversal process to calculate the sth Lucas number
# keep track of q = Q**n as we go
U = 0
V = 2
q = 1
# mod_inv(2, n)
inv_2 = (n+1) >> 1
while t:
if t&1:
# U, V of n+1
U, V = mul_mod(inv_2, U + V, n), mul_mod(inv_2, V + mul_mod(D, U, n), n)
q = mul_mod(q, Q, n)
t -= 1
else:
# U, V of n*2
U, V = mul_mod(U, V, n), (mul_mod(V, V, n) - 2 * q) % n
q = mul_mod(q, q, n)
t >>= 1
# double s until we have the 2**r*sth Lucas number
while r:
U, V = mul_mod(U, V, n), (mul_mod(V, V, n) - 2 * q) % n
q = mul_mod(q, q, n)
r -= 1
# primality check
# if n is prime, n divides the n+1st Lucas number, given the assumptions
return U == 0
# primes less than 212
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,101,103,107,109,113,127,131,137,139,149,151,
157,163,167,173,179,181,191,193,197,199,211]
# pre-calced sieve of eratosthenes for n = 2, 3, 5, 7
indices = [
1, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,
53, 59, 61, 67, 71, 73, 79, 83, 89, 97,101,103,
107,109,113,121,127,131,137,139,143,149,151,157,
163,167,169,173,179,181,187,191,193,197,199,209]
# distances between sieve values
offsets = [
10, 2, 4, 2, 4, 6, 2, 6, 4, 2, 4, 6,
6, 2, 6, 4, 2, 6, 4, 6, 8, 4, 2, 4,
2, 4, 8, 6, 4, 6, 2, 4, 6, 2, 6, 6,
4, 2, 4, 6, 2, 6, 4, 2, 4, 2,10, 2]
bit_lengths = [
0x00000000, 0x00000001, 0x00000003, 0x00000007,
0x0000000F, 0x0000001F, 0x0000003F, 0x0000007F,
0x000000FF, 0x000001FF, 0x000003FF, 0x000007FF,
0x00000FFF, 0x00001FFF, 0x00003FFF, 0x00007FFF,
0x0000FFFF, 0x0001FFFF, 0x0003FFFF, 0x0007FFFF,
0x000FFFFF, 0x001FFFFF, 0x003FFFFF, 0x007FFFFF,
0x00FFFFFF, 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF,
0x0FFFFFFF, 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF]
max_int = 2147483647
# returns the index of x in a sorted list a
# or the index of the next larger item if x is not present
# i.e. the proper insertion point for x in a
def binary_search(a, x):
s = 0
e = len(a)
m = e >> 1
while m != e:
if a[m] < x:
s = m
m = (s + e + 1) >> 1
else:
e = m
m = (s + e) >> 1
return m
def log2(n):
hi = n >> 32
if hi:
return binary_search(bit_lengths, hi) + 32
return binary_search(bit_lengths, n)
# integer sqrt of n
def isqrt(n):
c = n*4/3
d = log2(c)
a = d>>1
if d&1:
x = r_int64(1) << a
y = (x + (n >> a)) >> 1
else:
x = (r_int64(3) << a) >> 2
y = (x + (c >> a)) >> 1
if x != y:
x = y
y = (x + n/x) >> 1
while y < x:
x = y
y = (x + n/x) >> 1
return x
# integer cbrt of n
def icbrt(n):
d = log2(n)
if d%3 == 2:
x = r_int64(3) << d/3-1
else:
x = r_int64(1) << d/3
y = (2*x + n/(x*x))/3
if x != y:
x = y
y = (2*x + n/(x*x))/3
while y < x:
x = y
y = (2*x + n/(x*x))/3
return x
## Baillie-PSW ##
# this is technically a probabalistic test, but there are no known pseudoprimes
def is_bpsw(n):
if not is_sprp(n, 2): return False
# idea shamelessly stolen from Mathmatica's PrimeQ
# if n is a 2-sprp and a 3-sprp, n is necessarily square-free
if not is_sprp(n, 3): return False
a = 5
s = 2
# if n is a perfect square, this will never terminate
while legendre(a, n) != n-1:
s = -s
a = s-a
return is_lucas_prp(n, a)
# an 'almost certain' primality check
def is_prime(n):
if n < 212:
m = binary_search(small_primes, n)
return n == small_primes[m]
for p in small_primes:
if n%p == 0:
return False
# if n is a 32-bit integer, perform full trial division
if n <= max_int:
p = 211
while p*p < n:
for o in offsets:
p += o
if n%p == 0:
return False
return True
return is_bpsw(n)
# next prime strictly larger than n
def next_prime(n):
if n < 2:
return 2
# first odd larger than n
n = (n + 1) | 1
if n < 212:
m = binary_search(small_primes, n)
return small_primes[m]
# find our position in the sieve rotation via binary search
x = int(n%210)
m = binary_search(indices, x)
i = r_int64(n + (indices[m] - x))
# adjust offsets
offs = offsets[m:] + offsets[:m]
while True:
for o in offs:
if is_prime(i):
return i
i += o
# true if n is a prime power > 0
def is_prime_power(n):
if n > 1:
for p in small_primes:
if n%p == 0:
n /= p
while n%p == 0: n /= p
return n == 1
r = isqrt(n)
if r*r == n:
return is_prime_power(r)
s = icbrt(n)
if s*s*s == n:
return is_prime_power(s)
p = r_int64(211)
while p*p < r:
for o in offsets:
p += o
if n%p == 0:
n /= p
while n%p == 0: n /= p
return n == 1
if n <= max_int:
while p*p < n:
for o in offsets:
p += o
if n%p == 0:
return False
return True
return is_bpsw(n)
return False
def next_good_prime(n):
n = next_prime(n)
d = (n-1 & 1-n)
while not is_prime_power(n/d):
n = next_prime(n)
d = (n-1 & 1-n)
return n
def main(argv):
from time import time
t0 = time()
if len(argv) > 1:
n = r_int64(int(argv[1]))
else:
n = r_int64(7)
if len(argv) > 2:
limit = int(argv[2])
else:
limit = 10
m = 0
e = 1
q = n
try:
while True:
e += 1
p, q = q, next_good_prime(q)
if q-p > m:
m = q-p
print m, "(%d - %d) %fs"%(q, p, time()-t0)
n, q = p, n+p
if log2(q) > 61:
q >>= 2
e = 1
q = next_good_prime(q)
elif e > limit:
n, q = p, n+p
if log2(q) > 61:
q >>= 2
e = 1
q = next_good_prime(q)
except KeyboardInterrupt:
pass
return 0
def target(*args):
return main, None
if __name__ == '__main__':
from sys import argv
main(argv)