RPython (PyPy 4.0.1), 4032
RPythonเป็นชุดย่อยของ Python ที่ถูก จำกัด ซึ่งสามารถแปลเป็น C แล้วคอมไพล์โดยใช้ RPython Toolchain วัตถุประสงค์ของมันคือเพื่อช่วยในการสร้างล่ามภาษา แต่มันยังสามารถใช้ในการรวบรวมโปรแกรมง่าย ๆ
ในการรวบรวมดาวน์โหลดแหล่ง PyPy ปัจจุบัน (PyPy 4.0.1) และเรียกใช้สิ่งต่อไปนี้:
$ pypy /pypy-4.0.1-src/rpython/bin/rpython --opt=3 good-primes.py
ปฏิบัติการที่เกิดขึ้นจะมีชื่อgood-primes-c
หรือคล้ายกันในไดเรกทอรีการทำงานปัจจุบัน
หมายเหตุการใช้งาน
เครื่องกำเนิดไฟฟ้าจำนวนที่สำคัญprimes
เป็นมากมายตะแกรงของ Eratosthenes ซึ่งใช้ล้อเพื่อหลีกเลี่ยงการหลายรายการใด ๆ2 , 3 , 5หรือ7 นอกจากนี้ยังเรียกตัวเองซ้ำเพื่อสร้างค่าต่อไปที่จะใช้สำหรับการทำเครื่องหมาย ฉันค่อนข้างพอใจกับตัวกำเนิดนี้ การทำโปรไฟล์บรรทัดแสดงให้เห็นว่าสองบรรทัดที่ช้าที่สุดคือ:
37> n += o
38> if n not in sieve:
ดังนั้นฉันจึงไม่คิดว่าจะมีพื้นที่สำหรับปรับปรุงมากนักนอกจากใช้ล้อที่ใหญ่กว่า
สำหรับทางด้าน "ความดี" การตรวจสอบครั้งแรกปัจจัยทั้งหมดของทั้งสองจะถูกลบออกจากn-1โดยใช้สับบิต twiddling (n-1 & 1-n)
ที่จะหาพลังงานที่ใหญ่ที่สุดของทั้งสองซึ่งเป็นตัวหาร เนื่องจากp-1นั้นจำเป็นสำหรับแม้แต่ไพรม์พี> 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
รหัสนี้เป็น Python ที่ถูกต้องและควรถึง 3588 ~ 3900 เมื่อเรียกใช้กับล่าม PyPy ล่าสุด
# 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)
RPython (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)