सबसे तेज कोड अगले प्रधानमंत्री को खोजने के लिए


17

समस्या इस प्रकार है।

इनपुट: एक पूर्णांकn

आउटपुट: से छोटा सबसे बड़ा प्राइम n

चुनौती यह है कि ऐसा करने के लिए सबसे तेज़ कोड संभव है। जब तक यह मेरे कंप्यूटर पर एक मिनट 10 सेकंड से अधिक नहीं लेता , मैं आकार पर मोटे तौर10^8 पर शुरू करने और आकार 10^200में दोगुना होने वाले मूल्यों पर कोड का परीक्षण करूंगा।

जीतने वाला कोड सबसे बड़ा इनपुट आकार के लिए अगला प्रमुख ढूंढेगा।

तुलना के माध्यम से, अजगर में लिखी गई एक साधारण छलनी 10^8लगभग 20सेकंड से भी बड़ी प्राइम को खोजने में सक्षम है ।

आवश्यकता है कि मैं इसे अपने 4 जीबी रैम ubuntu कंप्यूटर पर परीक्षण कर सकता हूं सख्त है। सभी कोड नि: शुल्क (दोनों इंद्रियों में) होने चाहिए और यदि यह पुस्तकालयों का उपयोग करता है तो उन्हें भी स्वतंत्र और आसानी से स्थापित होना चाहिए। रिपोर्ट की गई कोई भी झूठी रिपोर्ट तुरंत सबमिशन को अयोग्य घोषित कर देगी।

मैं प्रत्येक प्रोग्रामिंग भाषा में विजेताओं के लिए अलग-अलग प्रशंसाओं को भी पुरस्कार दूंगा, भले ही कोड पूरी तरह से बाहरी पुस्तकालयों के उपयोग के बिना उस भाषा में लिखा गया हो। मैं सबसे तेज़ समय की एक रनिंग टेबल भी रखूंगा क्योंकि प्रतियोगिता आगे बढ़ती है ताकि लोग देख सकें कि वे कैसे कर रहे हैं।

अब तक की तालिका

  • अजगर। एक आश्चर्यजनक 357अंकों की प्राइमरी 34323988300653048574909503995406966086347176500716527046972317295927715916988280260612798203307272774886481556957404290185609939998583219062870141455575285760000000000000000000000000000000000000000287228479275893091260118904341195105085235761365897897120859609763409550080883251025969376198213520860328719954679500069780772860947616315643835603516615682061110 सेकंड के तहत अंतिम संख्या होती है, जिसके द्वारा आपूर्ति किए गए कोड का उपयोग किया जाता है primo। क्या कोई इस पहली एंट्री को हरा पाएगा?


@PeterTaylor यह प्रश्न मुझे लगता है कि समय की जटिलता के बारे में है। यह सेकंड में व्यावहारिक गति के बारे में है। मुझे लगता है कि वे दो चीजें काफी भिन्न हो सकती हैं।
felipa

यकीन है, अगर आप छोटे परीक्षण मामलों से चिपके रहते हैं। लेकिन जब से किसी ने अन्य प्रश्न के लिए एकेएस को लागू करने की जहमत नहीं उठाई, तो आपको वही जवाब मिलने वाले हैं।
पीटर टेलर

3
@PeterTaylor मुझे असहमत होने की अनुमति देता है। आखिरकार, साइट के 90% ट्रैफ़िक को खोज इंजन से आना चाहिएतेजी से अर्धवृत्ताकार कारक और एकाधिक बहुपद चतुर्भुज चलनी के लिए एक Google खोज मूल समस्या है जो मैंने अपने कोड को क्रमशः # 2 और # 4 से लिया है। मैं कुछ बिंदु पर कल्पना करता हूं, यह समस्या काफी हद तक fast next prime functionअच्छी होगी।
प्रिमो

1
मुझे लगता है कि ओपी उत्तर के अपने परीक्षणों को अद्यतन करने में विफल रहा है ...
mbomb007

जवाबों:


21

पायथन ~ 451 अंक

यह लाइब्रेरी का एक हिस्सा है जिसे मैंने एक अर्ध-भागीय कारक समस्या के लिए लिखा था , अनावश्यक कार्यों को हटा दिया गया था। यह Baillie-PSW primality परीक्षण का उपयोग करता है , जो तकनीकी रूप से एक संभाव्य परीक्षण है, लेकिन आज तक, कोई ज्ञात छद्म संज्ञाएं नहीं हैं - और एक नकद इनाम भी है यदि आप एक को खोजने में सक्षम हैं (या एक प्रमाण की आपूर्ति के लिए जो कि मौजूद नहीं है) ।

संपादित करें : मुझे महसूस नहीं हुआ कि पायथन में निर्मित मॉड्यूलर घातांक है। लगभग 33% के प्रदर्शन को बढ़ावा देने के लिए अंतर्निहित परिणामों के लिए मेरी खुद की जगह।

my_math.py

# legendre symbol (a|m)
# note: returns m-1 if a is a non-residue, instead of -1
def legendre(a, m):
  return pow(a, (m-1) >> 1, m)

# strong probable prime
def is_sprp(n, b=2):
  d = n-1
  s = 0
  while d&1 == 0:
    s += 1
    d >>= 1

  x = pow(b, d, n)
  if x == 1 or x == n-1:
    return True

  for r in range(1, s):
    x = (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):
  P = 1
  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 = 0
  while s > 0:
    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 > 0:
    if t&1 == 1:
      # U, V of n+1
      U, V = ((U + V) * inv_2)%n, ((D*U + V) * inv_2)%n
      q = (q * Q)%n
      t -= 1
    else:
      # U, V of n*2
      U, V = (U * V)%n, (V * V - 2 * q)%n
      q = (q * q)%n
      t >>= 1

  # double s until we have the 2**r*sth Lucas number
  while r > 0:
      U, V = (U * V)%n, (V * V - 2 * q)%n
      q = (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 = set([
    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]

max_int = 2147483647

# an 'almost certain' primality check
def is_prime(n):
  if n < 212:
    return n in small_primes

  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:
    i = 211
    while i*i < n:
      for o in offsets:
        i += o
        if n%i == 0:
          return False
    return True

  # Baillie-PSW
  # this is technically a probabalistic test, but there are no known pseudoprimes
  if not is_sprp(n): return False
  a = 5
  s = 2
  while legendre(a, n) != n-1:
    s = -s
    a = s-a
  return is_lucas_prp(n, a)

# 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:
    while True:
      if n in small_primes:
        return n
      n += 2

  # find our position in the sieve rotation via binary search
  x = int(n%210)
  s = 0
  e = 47
  m = 24
  while m != e:
    if indices[m] < x:
      s = m
      m = (s + e + 1) >> 1
    else:
      e = m
      m = (s + e) >> 1

  i = int(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

एक नमूना परीक्षण स्क्रिप्ट:

from time import clock
from my_math import *

n = i = 317**79
while True:
  i *= 317
  time1 = clock()
  n, o = next_prime(i), n
  span = clock()-time1
  if span > 10:
    break
  print(len(str(n)), span)
print(o)

317 का एक कारक चुना गया, क्योंकि यह लगभग वर्गमूल है 10000 , इसमें लगभग 2.5 अंक प्रति पुनरावृत्ति जोड़ रहा है (और क्योंकि दोहरीकरण बहुत धीमा था)। आउटपुट अंकों की वर्तमान संख्या और समय को दर्शाता है।

नमूना परिणाम:

201 0.13121248650317288
203 0.059535499623555505
206 0.9157767258129175
208 0.2583420518529589
211 0.15367400046653978
213 0.32343915218274955
216 1.3962866788935466
218 0.5986165839513125
221 0.973842206202185
223 2.346910291671148
...
428 0.932809896229827
431 4.345940056627313
433 9.511724255457068
436 6.089835998709333
438 1.3793498894412721
441 4.290633027381972
443 3.5102506044762833
446 3.1629148397352083
448 3.364759208223404
451 7.34668009481652
1551197868099891386459896063244381932060770425565921999885096817830297496627504652115239001983985153119775350914638552307445919773021758654815641382344720913548160379485681746575245251059529720935264144339378936233043585239478807971817857394193701584822359805681429741446927344534491412763713568490429195862973508863067230162660278070962484418979417980291904500349345162151774412157280412235743457342694749679453616265540134456421369622519723266737913

सभी कोड अब अजगर 3 संगत है।


यह आश्चर्यजनक तेजी है! मैं इसे कुछ दिनों (और एक निर्धारक प्राणशक्ति परीक्षण) में दोगुने आकार के साथ ठीक से चलाऊंगा और सबसे बड़ी संख्या तालिका में रखूंगा। मुझे संदेह है कि आप पहले से ही विजेता हो सकते हैं।
felipa

1
एफडब्ल्यूआईडब्ल्यू, सेज में, next_prime((2^520)*(10^200))मेरी मशीन पर लगभग 15 सेकंड, इसलिए पहले ब्लश पर यह काफी प्रभावशाली है। हालांकि ... next_prime((2^520)*(10^200),proof=False)0.4 सेकंड लगते हैं क्योंकि यह केवल स्यूडोप्रिमलिटी की जांच करता है। आपका दावा "कोई ज्ञात छद्म संज्ञाएं नहीं हैं" लुप्त हो रही हैं क्योंकि बिट्स की संख्या 64 से अधिक हो जाती है। 357 अंकों के लिए, मैं काउंटरटेम्पल की कमी से भी दूर से आश्वस्त नहीं हूं।
बूथ

@boothby यह ध्यान देने योग्य है कि यह मेपल द्वारा उपयोग की जाने वाली एक ही विधि है । यह विधि 33 साल पहले प्रकाशित हुई थी, और अभी भी कोई ज्ञात स्यूडोप्रेम इसकी सटीकता की डिग्री के लिए नहीं बोलता है।
प्रिमो

1
यही कारण है कि मैं ऋषि का उपयोग करता हूं। "असफल नहीं जाना जाता है" वास्तव में "काम करने के लिए जाना जाता है" जैसा नहीं है। मान लीजिए कि 400 अंकों के तहत एक गलत छद्म अपराध था। इसे ढूंढने में अरबों-खरबों साल लग जाएंगे - लेकिन यह अभी भी वहीं होगा, 'छद्मप्राइम = प्राइम' साबित करने की किसी भी कोशिश को नाकाम करते हुए। मैं हमेशा "समाधान" को नीचा दिखाऊंगा जो शून्य गारंटी के साथ प्रोबैलेलिस्टिक तरीकों का उपयोग करते हैं। मौंटे कारलो? ज़रूर। "यह प्रमुख है क्योंकि एक जादूगर ने मुझे बताया कि यह शायद था"? नहीं।
बूथ

1
@boothby आपको एक उत्तर जोड़ने की आवश्यकता है ताकि हम इसके तहत टिप्पणी कर सकें :)
felipa

6

सीएमपी जीएमपी के साथ: 567 अंक

जीएमपी में मिलर-राबिन कार्यान्वयन का उपयोग करता है। यह एक गलत सकारात्मक लौट सकता है, लेकिन सौभाग्य वास्तव में संभावना 2 ^ -200 के साथ एक को मार रहा है।

#include <gmp.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h>

double time() {
  struct timeval t;
  gettimeofday(&t, NULL);
  return t.tv_usec  * 1e-6 + t.tv_sec;
}

int main(int argc, char *argv[]) {
  mpz_t n, m;
  mpz_init_set_ui(n, 10);
  mpz_pow_ui(n, n, 200);
  mpz_init(m);
  for (int i = 0; true; i++, mpz_mul_ui(n, n, 2)) {
    double start = time();
    for (mpz_add_ui(m, n, 1); !mpz_millerrabin(m, 100); mpz_add_ui(m, m, 2)) ;
    double t = time() - start;
    gmp_printf("%d %Zd %f\n", i, m, t);
    if (t > 10.0) break;
  }
}

10^200 * 2^1216 + 361मेरे धीमे लैपटॉप पर समय के साथ चलने से पहले प्राइम (567 अंक) पाता है ।


3

जीएमपी मॉड्यूल के साथ पर्ल, 1300 अंक

मेरे मॉड्यूल का उपयोग करना :: प्राइम :: यूटिल और इसका जीएमपी बैक एंड । सटीक क्रॉसओवर बिंदु आपके कंप्यूटर पर निर्भर करेगा और चाहे आपके पास नवीनतम जीएमपी लाइब्रेरी हो। सभी कोड मुफ़्त है (मॉड्यूल जीथब और सीपीएएन पर हैं, और जीएमपी स्वतंत्र रूप से उपलब्ध है)। मैंने उन्हें AWS के उबंटू और साथ ही एक डेस्कटॉप उबंटू (और फेडोरा, और AIX, और NetBSD, आदि) पर चलाया है।

कोर कोड C और C + GMP में है। MP_ से अगला_प्रेम देखता है कि संख्या बहुत बड़ी है और यह GMP बैक एंड (या यदि बैक एंड इंस्टॉल नहीं है तो प्योर पर्ल कोड) है। वह स्ट्रिंग करता है और एक mpz में धर्मान्तरित होता है, और परिणाम को इनपुट ऑब्जेक्ट प्रकार या गणित :: BigInt में वापस बदल देगा। next_prime खुद करता है:

  • एक आधुनिक 30 पहिया
  • शेष mod 23 # का ट्रैक रखता है, इसलिए यह 23 तक के अपराधों के लिए देशी modulos कर सकता है
  • पास होने वाली चीजों पर संभावित प्रधान परीक्षण।

संभावित प्राइम टेस्ट है:

  • mpz_gcd_ui का उपयोग करते हुए छोटे विभाजकों के लिए जाँच करें (इनमें से 64-बिट दो में 101 तक की जाँच करें)
  • एकल-गणना वाले बड़े प्राइमरी का उपयोग करके छोटे विभाजक के लिए जाँच करें। यह या तो इनपुट आकार के आधार पर 10k या 40k तक का है।
  • 2 ^ 1600 से बड़े मूल्यों के लिए, ट्रीसिव का उपयोग करके आगे का परीक्षण प्रभाग करता है। यह अधिक कुशलता से किया जा सकता था।
  • अंत में, ईएस बीपीएसडब्ल्यू किया जाता है (बेस 2 के साथ मिलर-राबिन परीक्षण एक अतिरिक्त मजबूत लुकास परीक्षण के बाद )।

ES BPSW से पहले सब कुछ सिर्फ अनुकूलन है, जो निश्चित रूप से हम अगले_प्राइम के लिए चाहते हैं। अगली_प्राइम भी मैटल :: बिगइंट मॉड्यूल का उपयोग करके पर्ल में लागू किया गया है (कोर में वैकल्पिक परी और जीएमपी बैक एंड्स के साथ)। यह एईएस बीपीएसडब्ल्यू (परी की तरह) करता है लेकिन उतना अनुकूलित नहीं है।

मैंने उदाहरण के लिए, 2 मेरिट की एक सीमा का उपयोग करते हुए एक आंशिक-छलनी-आधारित संस्करण के गुणों के बारे में सोचा है। मुझे यकीन नहीं है कि अगर यह वास्तव में बेहतर होगा, क्योंकि अधिकांश समय हम अनावश्यक sieving कर रहे होंगे क्योंकि अंतर छोटा था, और कभी-कभी बड़े अंतराल के लिए हमें इसे कई बार दोहराना होगा।

पुस्तकालय ECPP (प्रमाण पत्र सहित) को लागू करता है, इसलिए हम परिणाम पर एक प्रमाण चला सकते हैं, लेकिन शामिल बहुपद के छोटे डिफ़ॉल्ट सेट के लिए 1200 अंक वास्तव में बहुत बड़े हैं (बड़े सेट डाउनलोड करने के लिए एक विधि है - प्रमाण थोड़ा सा लगेगा 15 मिनट जो कि Pari के APR-CL से थोड़ा तेज है लेकिन WraithX के mpz_aplcl से थोड़ा धीमा है)। ECPP बनाम APR-CL का एक नकारात्मक पहलू यह है कि इसमें अधिक समय विचरण होता है इसलिए औसत संख्या के वहां पहुंचने से पहले कुछ संख्या में इसके 10 सेकंड से अधिक होने की अच्छी संभावना है। एक प्रमाण के साथ मुझे लगता है कि हम 400 अंकों की सीमा में कुछ तक सीमित हैं जब तक कि हम बहु-थ्रेडेड सॉफ़्टवेयर की अनुमति नहीं देते हैं।

#!/usr/bin/env perl
use warnings;
use strict;
use Math::Prime::Util ":all";
use Math::Prime::Util::GMP;  # Barf if the backend isn't installed
use Time::HiRes qw(gettimeofday tv_interval);
use Math::GMP;

my $n = Math::GMP->new(10) ** 200;
while (1) {
  my $start = [gettimeofday];
  my $np = next_prime($n);
  my $sec = tv_interval($start);
  my $len = length($n);
  die "next_prime $len = +",$np-$n," in $sec seconds\n" if $sec > 10;
  warn "  next_prime $len = +",$np-$n," in $sec seconds\n";
  $n *= 10;
}

मैंने प्राइमो द्वारा उपयोग किए गए उसी अनुक्रम के साथ प्रयास करने का निर्णय लिया। यह 1191 अंकों पर पहुंच गया, क्योंकि हमने 18138 के अंतराल पर हिट किया था। मैंने नवीनतम my_math.py का उपयोग करके प्राइमो के कोड का भी परीक्षण किया। यह 10 ^ ई अनुक्रम और 641 के साथ 630 अंक उसके अनुक्रम के साथ हो जाता है। बहुत सारे ढोंग के बिना कॉम्पैक्ट ऑल-पायथन कोड के लिए बहुत प्रभावशाली।


मैं अभी भी नहीं मिल सकता है कि यह मॉड्यूल कितना तेज है। यह एक नंबर-क्रंचिंग टूल के रूप में पर्ल में मेरी रुचि का सम्मान करता है। मैं वर्तमान Math::GMPमें एक ऐसे तरीके से पुनर्लेखन कर रहा हूं जो कि mpz संदर्भ निर्माण / विनाश के साथ बहुत बेकार नहीं है।
प्रिमो

असली काम सभी सी + जीएमपी में है, इसलिए यह सभी पायथन में भी काम कर सकता है। पायथन में बड़ी संख्या के लिए पर्ल 5 पर कुछ गंभीर फायदे हैं, जो कि मैं चाहता हूं कि इसे हल किया जा सके। Math :: GMPz, वैसे, Math :: GMP से तेज है और मूल रूप से पूरे mpz एपीआई को उजागर किया है, हालांकि कभी-कभी कॉल करने के लिए अधिक भंगुर और थोड़ा अजीब है। मैथ में कुछ चीजों को ठीक करना :: कई अन्य चीजों के पीछे भी जीएमपी मेरी टूडू सूची में है। रे MPU, मैंने विकास को प्रभावित करने और इसे दो C पुस्तकालयों में बनाने के बारे में सोचा है, तो पर्ल मॉड्यूल का उपयोग करें। यह इसे कहीं और इस्तेमाल करने में मदद करेगा।
DANJ

मैं अच्छी प्रगति कर रहा हूं। निम्नलिखित लूप 10 गुना तेजी से चलता है , केवल बेहतर संदर्भ प्रबंधन के कारण $x = new Math::GMP(0); $x += 3 for 1..1000000। जब मैं समाप्त कर लूंगा, तब मैं कोप्पन को पोस्ट करूंगा; आप पहले जानने वाले लोगों में से एक होंगे;)
प्रिमो
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.