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)