Miller-Rabin Güçlü Sahte


16

Negatif olmayan bir tamsayı göz önüne alındığında N, ilk Nana tabanların tümüne güçlü bir yalancı suç olan en küçük tek pozitif tamsayıyı çıktılayın .

Bu OEIS dizisi A014233'tür .

Test Durumları (tek dizinli)

1       2047
2       1373653
3       25326001
4       3215031751
5       2152302898747
6       3474749660383
7       341550071728321
8       341550071728321
9       3825123056546413051
10      3825123056546413051
11      3825123056546413051
12      318665857834031151167461
13      3317044064679887385961981

İçin test senaryoları N > 13kullanılamıyor çünkü bu değerler henüz bulunamadı. Sıradaki sonraki terimleri bulmayı başarırsanız, söz konusu terimleri OEIS'e gönderdiğinizden emin olun!

kurallar

  • NSıfır dizinli veya tek dizinli bir değer olarak almayı seçebilirsiniz .
  • Çözümünüzün yalnızca dilinizin tamsayı aralığında temsil edilebilen değerlerde ( N = 12imzasız 64 bit tamsayılara kadar) çalışması kabul edilebilir, ancak çözümünüzün, dilinizin rastgele uzunluk tamsayılarını desteklediği varsayımı ile herhangi bir girdi için teorik olarak çalışması gerekir.

Arka fon

Herhangi pozitif çift tam sayı xbiçiminde yazılabilir garip. ve bölüm 2 ile bölünemez hale gelinceye kadar art arda 2'ye bölünerek hesaplanabilir. bu son bölümdür ve 2'nin bölme sayısıdır .x = d*2^sddsndsn

Pozitif bir tamsayı asalsan , Fermat'ın küçük teoremi şunları belirtir:

Fermat

Herhangi birinde sonlu alanda Z/pZ (burada p, sadece karekök bazı asal) 1olan 1ve -1(veya buna eşdeğer 1ve p-1).

Bu üç olguyu, aşağıdaki iki ifadeden birinin bir asal için doğru olması gerektiğini kanıtlamak için kullanabiliriz n(burada d*2^s = n-1ve riçinde bir tamsayı vardır [0, s)):

Miller-Rabin koşulları

Miller-Rabin asallık testi , yukarıda istemin karşıt ters test çalışır: bir taban olup olmadığını ayukarıdaki koşulların her ikisi de yanlış şekilde, o zaman nasal değildir. Bu tabana tanıka denir .

Şimdi, her üssü test etmek [1, n)büyük hesaplama süresinde çok pahalı olacaktır n. Miller-Rabin testinin sonlu alanda sadece rastgele seçilen bazı bazları test eden olasılıklı bir varyasyonu vardır. Bununla birlikte, sadece asal abazların test edilmesinin yeterli olduğu ve bu nedenle testin verimli ve belirleyici bir şekilde gerçekleştirilebileceği keşfedilmiştir . Aslında, tüm temel tabanların test edilmesi gerekmez - yalnızca belirli bir sayı gereklidir ve bu sayı, önceliklilik için test edilen değerin boyutuna bağlıdır.

Yetersiz sayıda asal baz test edilirse, test yanlış pozitifler üretebilir - testin kompozitliklerini kanıtlayamadığı tek bileşik tamsayılar. Spesifik olarak, bir baz atek bir kompozit sayının kompozititesini kanıtlayamazsa, bu sayı tabana güçlü bir yalancı suç denir a. Bu zorluk, Nasal sayıdan küçük veya ona eşit olan tüm bazlara güçlü portedoprimes olan tek kompozit sayıları bulmakla ilgilidir (bu, asal sayıdan küçük veya asal sayıya eşit olan tüm asal bazlara güçlü sahte olduklarını söylemekle eşdeğerdir N) .


1
Korumalı alan yayını (şimdi silindi)
Mego

Kurallar tarafından izin verilen güçlü sahte öncelik için 1'den tüm tek değerleri test eden bir algoritma var mı?
user202729

@ user202729 Neden olmasın anlamıyorum. Sana bunun ne düşündürdü?
Mego

Çoğu cevap sadece kaba kuvvet olacak, çünkü bu en hızlı kod soru yapma öneriyoruz .
Neil

@NeilA. Bunun en hızlı kod olarak daha iyi olacağına katılmıyorum. Cevapların neredeyse kesinlikle kaba kuvvet olacağı doğru olsa da (başka bir algoritma henüz geliştirilmediğinden ve PPCG'nin bunu yapmasını beklemiyorum), kod golf çok daha basit, giriş için çok daha düşük bir engel var kendi çözümlerini puanlayabilir), her çözümü çalıştırmamı ve puanlandırmamı (ve fahiş çalışma zamanlarıyla başa çıkmamı) gerektirmez ve sorun bir golf meydan okuması olarak yeterince ilginçtir.
Mego

Yanıtlar:


4

C 349 295 277 267 255 bayt

N,i;__int128 n=2,b,o,l[999];P(m){i<N&&P(m<2?l[i++]=n:n%m?m-1:n++);}main(r){for(P(scanf("%d",&N));r|!b;)for(++n,b=i=N;i--&&b;){for(b=n-1,r=0;~b&1;b/=2)++r;for(o=1;b--;o=o*l[i]%n);for(b=o==1;r--;o=o*o%n)b|=o>n-2;for(o=r=1;++o<n;r&=n%o>0);}printf("%llu",n);}

Stdin ile ilgili 1 tabanlı girdi alır, örneğin:

echo "1" | ./millerRabin

Kesinlikle yakında dizide yeni değerler bulamayacak, ancak işi halledecek. GÜNCELLEME: şimdi daha da yavaş!

  • Neil A'nın cevabından ilham alarak biraz daha hızlı ve daha kısa ( a^(d*2^r) == (a^d)^(2^r))
  • Bu zorluğa yönelik tüm çözümlerin garip olacağını fark ettikten sonra tekrar önemli ölçüde yavaşlar , bu yüzden sadece tek sayıları kontrol etmemize açıkça gerek yoktur.
  • Şimdi __int128daha unsigned long longbüyük sayılarla çalışırken daha kısa olan GCC'leri kullanıyor ! Ayrıca küçük endian makinelerde, printf %lluhala iyi çalışıyor.

Az-minified

N,i;
__int128 n=2,b,o,l[999];
P(m){i<N&&P(m<2?l[i++]=n:n%m?m-1:n++);}
main(r){
    for(P(scanf("%d",&N));r|!b;)
        for(++n,b=i=N;i--&&b;){
            for(b=n-1,r=0;~b&1;b/=2)++r;
            for(o=1;b--;o=o*l[i]%n);
            for(b=o==1;r--;o=o*o%n)b|=o>n-2;
            for(o=r=1;++o<n;r&=n%o>0);
        }
    printf("%llu",n);
}

(Eski) Dağılım

unsigned long long                  // Use the longest type available
n=2,N,b,i,d,p,o,                    // Globals (mostly share names with question)
l[999];                             // Primes to check (limited to 999, but if you
                                    // want it to be "unlimited", change to -1u)
m(){for(o=1;p--;o=o*l[i]%n);}       // Inefficiently calculates (l[i]^p) mod n

// I cannot possibly take credit for this amazing prime finder;
// See /codegolf//a/5818/8927
P(m){i<N&&P(m<2?l[i++]=n:n%m?m-1:n++);}

main(r){
    for(
        P(scanf("%llu",&N));        // Read & calculate desired number of primes
        r|!b;){                     // While we haven't got an answer:
        n=n+1|1;                    // Advance to next odd number
        for(b=1,i=N;i--&&b;){       // For each prime...
            for(d=n-1,r=0;~d&1;d/=2)++r; // Calculate d and r: d*2^r = n-1
            // Check if there exists any r such that a^(d*2^r) == -1 mod n
            // OR a^d == 1 mod n
            m(p=d);
            for(b=o==1;r--;b|=o==n-1)m(p=d<<r);
            // If neither of these exist, we have proven n is not prime,
            // and the outer loop will keep going (!b)
        }
        // Check if n is actually prime;
        // if it is, the outer loop will keep going (r)
        for(i=r=1;++i<n;r&=n%i!=0);
    }
    printf("%llu",n);               // We found a non-prime; print it & stop.
}

Belirtildiği gibi, bu 1 tabanlı giriş kullanır. Ancak n = 0 için, ilgili diziyi takip eden 9 üretilir . Artık değil; şimdi 0'da duruyor.

Tüm n için çalışmalıdır (en azından çıktı 2 ^ 64'e ulaşana kadar), ancak inanılmaz derecede yavaştır. N = 0, n = 1 ve ( çok fazla bekledikten sonra ), n = 2'de doğruladım .


Çözümümde bir atılım yapıyorum ve sonra sadece bire bir beni ... Güzel!
Neil

@NeilA. Afedersiniz! Güncellemenizi göndermeden önce daha kısa int türleriyle oynuyordum. Eminim bir yerde 2 bayt bulacaksınız; bu 2 farklı golf dilini göz önünde bulundurarak şaşırtıcı derecede rekabetçi olduğu ortaya çıktı: D
Dave

3

Python 2, 633 465 435 292 282 275 256 247 bayt

0 endeksli

Uygulamanızı sorgulayın ve yeni bir şeyler deneyin

Bir işlevden bir programa dönüştürmek bazı baytları bir şekilde kaydeder ...

Python 2 bana aynı şeyi yapmanın daha kısa bir yolunu verirse, Python 2'yi kullanacağım. Division varsayılan olarak tamsayıdır, bu yüzden 2'ye bölmenin daha kolay bir yoludur ve printparantez gerekmez.

n=input()
f=i=3
z={2}
a=lambda:min([i%k for k in range(2,i)])
while n:
 if a():z|={i};n-=1
 i+=2
while f:
 i+=2;d,s,f=~-i,0,a()
 while~d&1:d/=2;s+=1
 for y in z:
  x=y**d%i
  if x-1:
   for _ in[]*s:
    x*=x
    if~x%i<1:break
   else:f=1
print i

Çevrimiçi deneyin!

Python diğer dillere kıyasla çok yavaş.

Mutlak doğruluk için bir deneme bölümü testi tanımlar, ardından bir sahte suç bulunana kadar Miller-Rabin testini tekrar tekrar uygular.

Çevrimiçi deneyin!

EDIT : Sonunda cevap golf

DÜZENLEME : minDeneme bölümü öncelik testi için kullanılır ve a olarak değiştirilir lambda. Daha az verimli, ancak daha kısa. Ayrıca kendime yardım edemedim ve birkaç bitsel operatör kullandı (uzunluk farkı yok). Teorik olarak (biraz) daha hızlı çalışmalıdır.

DÜZENLE : Teşekkürler @Dave. Editörüm beni trol etti. Sekmeler kullandığımı sanıyordum ama bunun yerine 4 boşluğa dönüştürülüyordu. Ayrıca hemen hemen her Python ipucundan geçti ve uyguladı.

DÜZENLEME : 0 dizinlemeye geçildi, asalleri üreterek birkaç bayt kaydetmeme izin veriyor. Ayrıca birkaç karşılaştırma tekrarladı

EDIT : for/elseifadelerin yerine testlerin sonucunu saklamak için bir değişken kullanılır .

DÜZENLE : lambdaParametre ihtiyacını ortadan kaldırmak için işlevin içine taşındı .

EDIT : Bayt kaydetmek için bir programa dönüştürüldü

EDIT : Python 2 bana bayt kazandırır! Ayrıca girişi dönüştürmek zorunda değilimint


Kullanım şekliniz için +1 a^(d*2^r) mod n!
Dave

Python'da tek boşluklu (veya tek sekmeli) girinti kullanabileceğinizi biliyor musunuz… aslında bir sürü bayt, aslında
Dave

@Dave: Girinti seviyesi başına 1 sekme kullanıyor
Neil A.

Bence IDE'niz sizinle uğraşıyor ve sekmeler kullandığını söylerken yerden tasarruf sağlıyor; bunları tek boşluklar için değiştirdiğimde, sadece 311 baytlık bir bayt sayımı alıyorum! Çevrimiçi deneyin!
Dave

@Dave: Tamam, bu garip, teşekkürler, cevabı güncelleyeceğim.
Neil

2

Perl + Matematik :: Prime :: Util, 81 + 27 = 108 bayt

1 until!is_provable_prime(++$\)&&is_strong_pseudoprime($\,2..nth_prime($_));$_=""

Şununla koş: -lpMMath::Prime::Util=:all (27 baytlık cezası, ah).

açıklama

Temelde her şey için yerleşik olan sadece Mathematica değil. Perl, ilk büyük kütüphane havuzlarından biri olan CPAN'a sahiptir ve bu gibi görevler için çok sayıda hazır çözüm koleksiyonuna sahiptir. Ne yazık ki, varsayılan olarak içe aktarılmazlar (veya kurulmazlar), yani kullanmak için asla iyi bir seçenek olmadığı anlamına gelir , ancak bunlardan biri soruna mükemmel bir şekilde uyduğunda…

Biz 2 ila bütün tamsayı üsleri asal değil birini, ve henüz güçlü bir pseudoprime bulana kadar ardışık tamsayılar üzerinden çalışmasını n inci asal. Komut satırı seçeneği, söz konusu yerleşkeyi içeren kitaplığı içe aktarır ve ayrıca örtük girdiyi ayarlar (her seferinde bir satıra; Math::Prime::Utiltamsayılarındaki satır satırlarını sevmeyen kendi yerleşik bignum kitaplığına sahiptir). Bu, $\garip ayrıştırmaları azaltmak ve çıktının dolaylı olarak oluşturulmasına izin vermek için bir değişken olarak standart Perl hile (çıkış hattı ayırıcı) kullanmaktadır .

is_provable_primeBurada olasılıklı bir asal test istemek için deterministik bir talep istememiz gerektiğini unutmayın . (Özellikle olasılıkla bir başlangıç ​​testinin muhtemelen Miller-Rabin'i kullanması göz önüne alındığında, bu durumda güvenilir sonuçlar vermeyi bekleyemeyiz!)

Perl + Math :: Prime :: Util, 71 + 17 = 88 bayt, @Dada ile işbirliği içinde

1until!is_provable_prime(++$\)&is_strong_pseudoprime$\,2..n‌​th_prime$_}{

İle çalıştırın -lpMntheory=:all(17 bayt ceza).

Bu, ya bilmediğim birkaç Perl golf hilesi kullanıyor (görünüşte Math :: Prime :: Util'in bir kısaltması var!), Biliyordu ama kullanmayı düşünmedi ( örtük olarak her satırdan ziyade bir kez }{çıktı almak için ) veya biliyordu ama bir şekilde yanlış uygulamayı başardı (işlev çağrılarından parantezler kaldırıldı). @Dada'ya bunları işaret ettiği için teşekkürler. Bunun dışında aynı.$\"$_$\"


Tabii bir golf-ish dili gelir ve gerisini yener. Aferin!
Neil

Bunun ntheoryyerine kullanabilirsiniz Math::Prime::Util. Ayrıca, }{yerine ;$_=""iyi olmalı. 1Birkaç fonksiyon çağrısının ardından gelen alanı ve parantezi atlayabilirsiniz . Ayrıca, &yerine çalışır &&. Bu 88 bayt vermelidir:perl -Mntheory=:all -lpe '1until!is_provable_prime(++$\)&is_strong_pseudoprime$\,2..nth_prime$_}{'
Dada

Tamamen unutmuştum }{. (Garip bir şekilde, parantez şeyi hatırladım ama Perl'de golf oynadığımdan ve dışarıda bırakma kurallarını hatırlayamadığımdan beri bir süredir.) ntheoryKısaltma hakkında hiçbir şey bilmiyordum .
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.