En büyük kırılgan üssü bulmak


21

Fonksiyonu göz önünde Remove(n, startIndex, count)kaldırır bu countnumaradan basamak npozisyonunda basamak başlayarak startIndex. Örnekler:

Remove(1234, 1, 1) = 234
Remove(123456, 2, 3) = 156
Remove(1507, 1, 2) = 07 = 7
Remove(1234, 1, 4) = 0

Her olası Removeişlem asal olmayan yaparsa asal sayı X kırılgan olarak adlandırılır . Örneğin, 80651 kırılgan bir asaldır, çünkü aşağıdaki sayıların tümü asal değildir:

651, 51, 1, 0, 8651, 851, 81, 8, 8051, 801, 80, 8061, 806, 8065

Hedef

En büyük kırılgan üssü bulan bir program yaz. Düzenleme: zaman sınırı kaldırıldı çünkü onu atlatmanın nispeten adil bir yolu vardı.

Skor, programınız tarafından bulunan kırılgan asal sayıdır. Bir beraberlik durumunda, önceki sunum kazanır.

kurallar

  • Herhangi bir dili ve herhangi bir üçüncü taraf kütüphanesini kullanabilirsiniz.
  • Programı kendi donanımınız üzerinde çalıştırıyorsunuz.
  • Olasılıksal birincillik testlerini kullanabilirsiniz.
  • Her şey 10 numarada.

Lider girişler

  • Qualtagh (Java) tarafından 6629 basamak
  • Emil tarafından 5048 basamak (Python 2)
  • Jakube tarafından 2268 hane (Python 2)

Düzenleme: Kendi cevabımı ekledim.

  • Qualtagh algoritmasına göre Suboptimus Prime tarafından 28164 hane (C #)

5
Cevabı zor yazmasam bile, büyük bir kırılgan üssüne çok yakın bir noktada arama yapmaya başlayabilirim . Açıkçası, hiç kimse 1'de aramaya başlamak istemiyor. Bunu yapmamı engelleyen nedir? Cevabı temel olarak kodlamak için çağrılmadan önce, aramalarıma tam olarak ne kadar yaklaşabilirim? Bu arada mücadeleyi seviyorum.
Rainbolt

2
@ SuboptimusPrime Bunun yerine zaman sınırını tamamen kaldırabilirsiniz, çünkü o kadar nadir olacağı bir noktada, bir sonrakini bulmanın çok kolay olacağına inanıyorum. ( Codegolf.stackexchange.com/questions/41021/… ile benzer )
Martin Ender


7
Bilgisayarları yavaş olanları hala dezavantajlı bir durumda bırakıyorsunuz
John Dvorak

11
"En büyük kırılgan üssü bulan bir program yaz" demek, "En büyük kırılgan bir üssü var. Onu bulan bir program yaz" demek değildir. Sanırım çok fazla Proje Euler yaptım. :-P
14:14

Yanıtlar:


9

Java - 3144 3322 6629 basamak

6 0{3314} 8969999

6 0{6623} 49099

Bu çözüm FryAmTheEggman'ın cevabına dayanmaktadır .

  1. Son hane 1 veya 9'dur.
  2. Son rakam 1 ise, önceki rakam 0, 8 veya 9'dur.
  3. Son rakam 9 ise, önceki rakam 0, 4, 6 veya 9'dur.
  4. ...

Ya daha derine inersek?

Bir ağaç yapısı haline gelir:

                        S
             -----------------------
             1                     9
    ------------------         ----------------
    0           8    9         0    4    6    9
---------     -----
0   8   9      ...

R ve bütün sonları birleşik ise, doğru R numaralı kompozit diyelim.

Tüm doğru kompozit sayıları en üstte bir şekilde yineleyeceğiz: 1, 9, 01, 81, 91, 09, 49, 69, 99, 001, 801, 901 vb.

Sıfırla başlayan sayılar, birincillik için kontrol edilmez ancak başka sayılar oluşturmak için gereklidir.

X00 ... 00R biçiminde N hedef numarasını arayacağız, burada X 4, 6, 8 veya 9'dan biri ve R doğru bileşiktir. X asal olamaz. X 0 olamaz. X 1 olamaz çünkü R 1 veya 9 ile bitiyorsa N 11 veya 19 içerir.

Eğer XR "kaldır" işleminden sonra asal sayılar içeriyorsa, XYR bunları herhangi bir Y için de içerir. Bu nedenle, R'den başlayarak dalları geçmemeliyiz.

X'in sabit kalmasına izin verin, 6 diyelim.

pseudocode:

X = 6;
for ( String R : breadth-first-traverse-of-all-right-composites ) {
  if ( R ends with 1 or 9 ) {
    if ( remove( X + R, i, j ) is composite for all i and j ) {
      for ( String zeros = ""; zeros.length() < LIMIT; zeros += "0" ) {
        if ( X + zeros + R is prime ) {
          // At this step these conditions hold:
          // 1. X + 0...0 is composite.
          // 2. 0...0 + R = R is composite.
          // 3. X + 0...0 + R is composite if 0...0 is shorter than zeros.
          suits = true;
          for ( E : all R endings )
            if ( X + zeros + E is prime )
              suits = false;
          if ( suits )
            print R + " is fragile prime";
          break; // try another R
                 // because ( X + zeros + 0...0 + R )
                 // would contain prime ( X + zeros + R ).
        }
      }
    }
  }
}

Sıfır miktarını sınırlamalıyız çünkü X + sıfır + R (veya hepsi birleşikse sonsuza kadar) şeklinde bir asal sayı bulmak çok uzun sürebilir.

Gerçek kod oldukça ayrıntılı ve burada bulunabilir .

Uzun int aralığındaki sayılar için asallık testi, Miller testinin deterministik varyantı ile gerçekleştirilir. BigInteger sayıları için önce deneme bölümü, daha sonra BailliePSW testi yapılır. Olasılıklı ama kesin. Üstelik Miller-Rabin testinden daha hızlı (Miller-Rabin'deki bu kadar büyük rakamlar için yeterince doğruluk elde etmek için birçok yineleme yapmalıyız).

Düzenleme: ilk deneme yanlıştı. Eğer X0 ... 0R asal ise, R ile başlayan dalları göz ardı etmeliyiz. O zaman X0 ... 0YR kırılgandır. Böylece ek bir çek eklendi. Bu çözüm doğru görünüyor.

Düzenleme 2: bir optimizasyon eklendi. (X + R), 3 ile bölünebilir ise, (X + sıfırlar + R), 3 ile de bölünebilir. Bu durumda (X + sıfırlar + R) bu durumda asal olamaz ve bu R'ler atlanabilir.

Düzenleme 3: en son veya ilk konumda değilse, asal rakamları atlamak gerekli değildi. Yani 21 ya da 51 gibi sonlar tamam. Fakat fazla bir şey değiştirmez.

Sonuç:

  1. Son cevabım 100 dakika boyunca kırılgan olup olmadığını kontrol etmekti. Cevabın aranması (önceki tüm varyantları kontrol eden) yaklaşık 15 dakika sürdü. Evet, arama süresini kısıtlamak mantıklı değil (hedef numaradan aramaya başlayabiliriz, bu yüzden zaman sıfır olur). Ancak bu sorudaki gibi kontrol zamanını kısıtlamak anlamlı olabilir .
  2. 60 ... 049099 numaralı cevabın ortasında 4 rakamı vardır. "Kaldır" işlemi dokunduğunda, sayı 3 ile bölünebilir hale gelir. Bu nedenle, sol ve sağ taraflardaki kaldırma işlemlerini kontrol etmeliyiz. Sağ taraf çok kısa. Sol taraf uzunluğu neredeyse n = uzunluk (N).
  3. BPSW ve Miller-Rabin gibi primallik testleri sabit miktarda modüler ekspresyon kullanıyor. Karmaşıklığı, bu sayfaya göre O (M (n) * n) 'dir , burada M (n) çarpım karmaşıklığıdır. Java, Toom-Cook ve Karatsuba algoritmalarını kullanıyor, ancak sadelik için bilgin algoritmasını alacağız. M (n) = n- 2 . Asallık test karmaşıklığı Böylece O (n, 3 ).
  4. Tüm sayıları uzunluk = 6'dan 6629'a kadar kontrol etmeliyiz. Ortaklık için min = 1 ve max = n alalım. Bütün kontrol karmaşıklığı O (1 3 + 2 3 + ... + n 3 ) = O ((n * (n + 1) / 2) 2 ) = O (n 4 ).
  5. Emil'in cevabı aynı kontrol asimptotiklerine sahip. Ancak sabit faktör daha düşüktür. Rakam "7" rakamın ortasında duruyor. Sol taraf ve sağ taraf neredeyse eşit olabilir. Bu (n / 2) verir 4 * 2 = n 4 8X: / 8. Hız Arttırma. 9 ... 9Y9 ... 9 formundaki sayılar, aynı kontrol süresine sahip X0 ... 0R formundan 1.7 kat daha uzun olabilir.

1
Kredi için teşekkürler, ama algoritmanız benimkinden çok daha karmaşık! Büyük iş ve PPCG'ye hoş geldiniz! :)
FryAmTheEggman

@FryAmTheEggman: Bu fikir için teşekkür ederiz! İlham verici.
Qualtagh

Kontrol karmaşıklığı analiziniz çok ilginç, ancak arama uygunluğu da önemlidir. Algoritmanızın, büyük bir kırılgan üssü bulmak için büyük sayılarda (Emil'inkiyle karşılaştırıldığında) önemli ölçüde daha az primallik testi gerektirdiğini düşünüyorum. Ve yerel bir kütüphane kullanarak ilkellik testlerini hızlandırabilirsiniz. Mpir.NET kullanıyorum ve numaranızı kırılgan bir asal olarak kontrol etmek sadece birkaç dakika sürer.
Suboptimus Prime

13

Python 2 - 126 1221 1337 1719 2268 basamak

999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999799999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999

'9' * 1944 + '7' + '9' * 323

Yaklaşık len (n) ^ 2 ve sonuçta Kaldır (n, startIndex, count) sayıları vardır. Bu sayıları minimize etmeye çalıştım. Birbirlerinin yanında çok sayıda basamak aynıysa, bu sonuçların çoğu göz ardı edilebilir, çünkü birden çok kez görünürler.

Bu yüzden aşırı, sadece 9 ve ortada biraz asal aldı. Ayrıca 1 milyonun altındaki kırılgan prime bir göz attım ve böyle kırılgan bir primer olduğunu gördüm. Sonunda 2 9'lu sayıları aramak gerçekten iyi çalışıyor, neden olduğundan emin değilim. Sonunda 1 sayı, 3 veya 4 9, daha küçük kırılgan primerlerle sonuçlanır.

Pyprimes modülünü kullanır . İyi olup olmadığından emin değilim. Miller_rabin testini kullanır, bu yüzden olasılıklıdır.

Program bu 126 basamaklı kırılgan üssü yaklaşık 1 dakika içinde bulur ve kalan süre boyunca başarı olmadan arar.

biggest_found = 80651

n = lambda a,b,c: '9'*a + b + '9'*c

for j in range(1000):
   for digit in '124578':
      for i in range(2000):
         number = int(n(i,digit,j))
         if is_prime(number):
            if (number > biggest_found):
               if all(not is_prime(int(n(i,digit,k))) for k in range(j)):
                  biggest_found = number
                  print(i+j+1, biggest_found)
            break

Düzenle:

Az önce gördüm, zaman sınırını kaldırdın. Programı gece boyunca çalıştıracağım, belki de bazı büyük hassas kırılganlıklar ortaya çıkar.

düzenleme 2:

Orijinal programımı daha hızlı yaptım, bu yüzden 126 basamaktan fazla olan bir çözüm yok. Böylece trene atladım ve x 9s + 1 rakam + y 9s aradım. Bunun avantajı, düzeltmek için O (n) sayılarını öncelik için kontrol etmeniz gerekmesidir. Çok hızlı bir şekilde 1221 bulur.

düzenleme 3:

Aynı programı kullandığım 2268 rakamı için, çalışmayı yalnızca birkaç çekirdeğe böldüm.


3
"yaklaşık 1 dakika içinde" - üzgünüm, çoğullaştırma "bug" ını bildirmek zorundasınız. : P
hichris123

Değirmenci-rabinin olası doğası, son birkaç girişim için beni ısırdı. Siz de başka bir algoritma ile doğrulamak isteyebilirsiniz.
John Meacham

Niçin sadece rakamları uçtan kaldırırken oluşan sayıların kompozit olduğunu kontrol ediyorsunuz? Neden rakamları önden kaldırarak oluşan rakamları kontrol etmiyorsunuz?
isaacg

1
Çünkü bunları daha önce 'for' döngüsünde kontrol ettim. Burada başında 9'lar ekliyorum ve bir kontrol yapalım. Bu formun ilk asal sayısını bulduğumda, başlangıçta 9'dan daha az olan tüm sayıların asal olmadığını biliyorum. Ve sonunda 9'ları kaldırmayı kontrol ettikten sonra dururum (kırılır), çünkü şimdi her sayının içinde bir asal sayı vardır ve bu yüzden asal değildir.
Jakube

Ah, çok zekice.
isaacg

7

Python 2,7 - 429623069 99993799

Şimdiye kadar hiçbir iyileştirme yok. Sadece kırılgan astarlar hakkında bazı önemsiz gözlemler kullanarak (sohbetteki Rainbolt sayesinde):

  1. Kırılgan astarlar 1 veya 9 ile bitmelidir (Asallar bile değildir ve son rakamlar asal olmamalıdır)
  2. 1 ile biten kırılgan astarlar 8 ya da 9 ile başlamalıdır (ilk sayı asal olamaz, 11, 41 ve 61 ve hepsi asaldır)
  3. 9'da biten kırılgan astarlar, 4,6 veya 9 ile başlamalıdır (1'in nedenine bakın, ancak yalnızca 89 asaldır)

Sadece topu yuvarlamaya çalışıyorum :)

Bu teknik olarak 15 dakika boyunca biraz çalışır, ancak fazladan sadece tek bir sayıyı kontrol eder.

is_primealınır burada (isaacg kullandı burada ) ve olasılık olduğunu.

def substrings(a):
    l=len(a)
    out=set()
    for i in range(l):
        for j in range(l-i):
            out.add(a[:i]+a[len(a)-j:])
    return out

import time

n=9
while time.clock()<15*60:
    if is_prime(n):
        if not any(map(lambda n: n!='' and is_prime(int(n)), substrings(`n`))):
            print n
    t=`n`
    if n%10==9 and t[0]=='8':n+=2
    elif n%10==1 and t[0]!='8':n+=8
    elif t[0]=='1' or is_prime(int(t[0])):n+=10**~-len(t)
    else:n+=10

Sadece bir not, buna başladığımda n=429623069kalkarım 482704669. Ekstra rakam gerçekten bu stratejiyi öldürüyor gibi görünüyor ...


Bir başlangıç ​​için fena değil! Her ne kadar is_prime, 32 bitlik değerler için tam bir deteterministik kontrol gerçekleştiriyor, bu da biraz fazla. Deneme bölümünün tamamını okuyacağınız takdirde is_prime yönteminin daha hızlı çalışacağını düşünüyorum
Suboptimus Prime

@ SuboptimusPrime Oh, teşekkürler. Buna
bakmadım

@ SuboptimusPrime Bence tam belirleyici kontrolün küçük değerler için daha hızlı olduğunu düşünüyorum çünkü yazar aday faktörler arasında atılacak adımları tanımladı. Fikir için tekrar teşekkürler, ama bunu bırakırken çok daha hızlı görünüyor :)
FryAmTheEggman

Cevabınıza Küçük düzeltme: 91 = 13x7, böylece 91 kompozit ve 1 ile biten kırılgan asal aslında 9 ile başlayabilirsiniz
Suboptimus Prime

@ SuboptimusPrime Oldukça doğru, bunu nasıl batırdığımı bilmiyorum. Gönderdiğim değer hala geçerli olmalı, çünkü bazı olası değerleri atlıyordum.
FryAmTheEggman

7

Python 2, 828 basamak 5048 basamak

99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999799999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
155*'9'+'7'+4892*'9'

@ Jakube'un belirttiği gibi, gönderdiğim ilk ana koddaki bir hata nedeniyle kırılgan değildi. Hatayı düzeltmek kolaydı ancak algoritmayı da oldukça yavaşlattı.

Kendimi, sadece 9 rakamından ve tam olarak bir rakam 7'den oluşan kırılgan astarların kolayca aranabilen bir alt kümesiyle sınırlandırdım.

def fragile_prime_generator(x, b_max):
  bs, cs = set(), set()
  prime = dict()

  def test_prime(b,c):
    if (b,c) not in prime:
      prime[(b,c)] = is_prime(int('9'*b+`x`+'9'*c))
    return prime[(b,c)]

  def test_frag(b,c):
    for b2 in xrange(b):
      if test_prime(b2,c):
        bs.add(b2)
        return False
    for c2 in xrange(c):
      if test_prime(b,c2):
        cs.add(c2)
        return False
    return True

  a = 1
  while len(bs)<b_max:
    for b in xrange(min(a, b_max)):
      c = a-b
      if b not in bs and c not in cs and test_prime(b,c):
        bs.add(b)
        cs.add(c)
        if test_frag(b,c): yield b,c
    a += 1
  print "no more fragile primes of this form"

for b,c in fragile_prime_generator(7, 222):
  print ("%d digit fragile prime found: %d*'9'+'%d'+%d*'9'"
          % (b+c+1, b, x, c))

Aynı is_primeişlevi ( buradan ) @FryAmTheEggman ile kullandım.

Düzenle:

Algoritmayı daha hızlı yapmak için iki değişiklik yaptım:

  • Olabildiğince fazla primallik kontrolünü atlamaya çalışıyorum ve yalnızca kırılgan olduğundan emin olmak için potansiyel bir kırılgan üssü bulunduğunda geri dönüyorum. Az sayıda yinelenen kontrol var, bu yüzden ana kontrol fonksiyonunu kabaca not ettim.

  • Formun sayıları b*'9' + '7' + c*'9'için boyutunu sınırladım b. Limit ne kadar düşükse, o kadar az sayının kontrol edilmesi gerekir, ancak büyük kırılgan bir asal bulmama şansı artar. Ben keyfi olarak 222'yi limit olarak seçtim.

Birkaç bin basamakta, tek bir ana kontrol zaten programımı birkaç saniye sürebilir. Yani, bu yaklaşımla muhtemelen daha iyisini yapamam.

Lütfen gönderimin doğruluğunu kontrol etmekten çekinmeyin. Olasılık ilkelliği kontrolü nedeniyle benim numaram teorik olarak asal olamaz, fakat öyleyse kırılgan olmalıdır. Ya da yanlış bir şey yaptım. :-)


2
Bulunan asal kırılgan değil. Remove (n, 83,838) [İlk 82 hane dışındaki her şeyi kaldır] 'ı çağırırsanız, bir asalla sonuçlanırsınız.
Jakube

1
Ah, teşekkürler @Jakube. Çok zeki olmaya çalışıyordum. Öyle görünüyor ki daha fazla öncelik kontrolünü atlıyordum, sonra yapmalıydım. Düzeltmek için yola çıktım.
Emil

1
Tekrar kontrol ettim, şimdi sonuçlarınız doğru.
Jakube

Aslında, 5048 rakamınız, programıma göre kırılgan bir asal.
Suboptimus Prime

@ SuboptimusPrime: Harika, kontrol ettiğiniz için teşekkürler!
Emil

4

C #, 10039 28164 basamak

6 0{28157} 169669

Düzenleme: Bazı küçük değişikliklerle Qualtagh algoritmasına dayanarak başka bir program yaptım:

  • L L000 ... 000R formunun numaralarını arıyorum, L L kompozit bırakılır, R ise doğru kompozittir. Soldaki kompozit L sayısının çoklu rakamlara sahip olmasına izin verdim, bu çoğunlukla stilistik bir değişiklik olmasına rağmen muhtemelen algoritmanın verimliliğini etkilemiyor.
  • Aramayı hızlandırmak için çoklu okuma ekledim.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Threading;
using System.Threading.Tasks;
using Mpir.NET;

class Program
{
    const int PrimeNotFound = int.MaxValue;

    private static BitArray _primeSieve;
    private static HashSet<Tuple<int, int>> _templatesToSkip = new HashSet<Tuple<int, int>>();

    static void Main(string[] args)
    {
        int bestDigitCount = 0;
        foreach (Tuple<int, int> template in GetTemplates())
        {
            int left = template.Item1;
            int right = template.Item2;
            if (SkipTemplate(left, right))
                continue;

            int zeroCount = GetZeroCountOfPrime(left, right);
            if (zeroCount != PrimeNotFound)
            {
                int digitCount = left.ToString().Length + right.ToString().Length + zeroCount;
                if (digitCount >= bestDigitCount)
                {
                    string primeStr = left + " 0{" + zeroCount + "} " + right;
                    Console.WriteLine("testing " + primeStr);
                    bool isFragile = IsFragile(left, right, zeroCount);
                    Console.WriteLine(primeStr + " is fragile: " + isFragile);

                    if (isFragile)
                        bestDigitCount = digitCount;
                }

                _templatesToSkip.Add(template);
            }
        }
    }

    private static int GetZeroCountOfPrime(int left, int right)
    {
        _zeroCount = 0;

        int threadCount = Environment.ProcessorCount;
        Task<int>[] tasks = new Task<int>[threadCount];
        for (int i = 0; i < threadCount; i++)
            tasks[i] = Task.Run(() => InternalGetZeroCountOfPrime(left, right));
        Task.WaitAll(tasks);

        return tasks.Min(task => task.Result);
    }

    private static int _zeroCount;

    private static int InternalGetZeroCountOfPrime(int left, int right)
    {
        const int maxZeroCount = 40000;
        int zeroCount = Interlocked.Increment(ref _zeroCount);
        while (zeroCount <= maxZeroCount)
        {
            if (zeroCount % 1000 == 0)
                Console.WriteLine("testing " + left + " 0{" + zeroCount + "} " + right);

            if (IsPrime(left, right, zeroCount))
            {
                Interlocked.Add(ref _zeroCount, maxZeroCount);
                return zeroCount;
            }
            else
                zeroCount = Interlocked.Increment(ref _zeroCount);
        }

        return PrimeNotFound;
    }

    private static bool SkipTemplate(int left, int right)
    {
        for (int leftDiv = 1; leftDiv <= left; leftDiv *= 10)
            for (int rightDiv = 1; rightDiv <= right; rightDiv *= 10)
                if (_templatesToSkip.Contains(Tuple.Create(left / leftDiv, right % (rightDiv * 10))))
                    return true;

        return false;
    }

    private static bool IsPrime(int left, int right, int zeroCount)
    {
        return IsPrime(left.ToString() + new string('0', zeroCount) + right.ToString());
    }

    private static bool IsPrime(string left, string right, int zeroCount)
    {
        return IsPrime(left + new string('0', zeroCount) + right);
    }

    private static bool IsPrime(string s)
    {
        using (mpz_t n = new mpz_t(s))
        {
            return n.IsProbablyPrimeRabinMiller(20);
        }
    }

    private static bool IsFragile(int left, int right, int zeroCount)
    {
        string leftStr = left.ToString();
        string rightStr = right.ToString();

        for (int startIndex = 0; startIndex < leftStr.Length - 1; startIndex++)
            for (int count = 1; count < leftStr.Length - startIndex; count++)
                if (IsPrime(leftStr.Remove(startIndex, count), rightStr, zeroCount))
                    return false;

        for (int startIndex = 1; startIndex < rightStr.Length; startIndex++)
            for (int count = 1; count <= rightStr.Length - startIndex; count++)
                if (IsPrime(leftStr, rightStr.Remove(startIndex, count), zeroCount))
                    return false;

        return true;
    }

    private static IEnumerable<Tuple<int, int>> GetTemplates()
    {
        const int maxDigitCount = 8;
        PreparePrimeSieve((int)BigInteger.Pow(10, maxDigitCount));
        for (int digitCount = 2; digitCount <= maxDigitCount; digitCount++)
        {
            for (int leftCount = 1; leftCount < digitCount; leftCount++)
            {
                int rightCount = digitCount - leftCount;
                int maxLeft = (int)BigInteger.Pow(10, leftCount);
                int maxRight = (int)BigInteger.Pow(10, rightCount);

                for (int left = maxLeft / 10; left < maxLeft; left++)
                    for (int right = maxRight / 10; right < maxRight; right++)
                        if (IsValidTemplate(left, right, leftCount, rightCount))
                            yield return Tuple.Create(left, right);
            }

        }
    }

    private static void PreparePrimeSieve(int limit)
    {
        _primeSieve = new BitArray(limit + 1, true);
        _primeSieve[0] = false;
        _primeSieve[1] = false;

        for (int i = 2; i * i <= limit; i++)
            if (_primeSieve[i])
                for (int j = i * i; j <= limit; j += i)
                    _primeSieve[j] = false;
    }

    private static bool IsValidTemplate(int left, int right, int leftCount, int rightCount)
    {
        int rightDigit = right % 10;
        if ((rightDigit != 1) && (rightDigit != 9))
            return false;

        if (left % 10 == 0)
            return false;

        if ((left + right) % 3 == 0)
            return false;

        if (!Coprime(left, right))
            return false;

        int leftDiv = 1;
        for (int i = 0; i <= leftCount; i++)
        {
            int rightDiv = 1;
            for (int j = 0; j <= rightCount; j++)
            {
                int combination = left / leftDiv * rightDiv + right % rightDiv;
                if (_primeSieve[combination])
                    return false;

                rightDiv *= 10;
            }

            leftDiv *= 10;
        }

        return true;
    }

    private static bool Coprime(int a, int b)
    {
        while (b != 0)
        {
            int t = b;
            b = a % b;
            a = t;
        }
        return a == 1;
    }
}

Eski cevap:

8 0{5436} 4 0{4600} 1

Kırılgan astarlar için birkaç kayda değer desen vardır:

600..00X00..009
900..00X00..009
800..00X00..001
999..99X99..999

buradaki X, 1, 2, 4, 5, 7 veya 8 olabilir.

Bu gibi numaralar için sadece olası Removeişlemleri düşünmeliyiz (uzunluk - 1) . Diğer Removeişlemler ya kopyaları ya da açıkça bileşik sayıları üretir. 800 haneye kadar tüm bu rakamları aramaya çalıştım ve geri kalanından 4 örüntü daha sık ortaya çıktığını fark ettim: 8007001, 8004001, 9997999 ve 6004009. biraz çeşitlilik eklemek için.

Algoritmaya aşağıdaki optimizasyonları ekledim:

  • 7000 basamaklı sayılarla aramaya başladım ve daha sonra kırılgan bir asal bulunurken her seferinde 1500 kadar artar. Belirli bir uzunluğa sahip kırılgan bir üssü yoksa, onu 1 7000 ve 1500 artırdım, sadece uygun görünen rastgele sayılardır.
  • Aynı anda farklı uzunluktaki sayıları aramak için çoklu okuma kullanıyorum.
  • Her bir kontrolün sonucu, yinelenen kontrolleri önlemek için bir karma tabloda saklanır.
  • Mpir.NET'ten Miller-Rabin uygulamasını çok hızlı kullanıyorum (MPIR GMP'nin bir çatalı).
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using Mpir.NET;

class Program
{
    const string _template = "8041";

    private static ConcurrentDictionary<Tuple<int, int>, byte> _compositeNumbers = new ConcurrentDictionary<Tuple<int, int>, byte>();
    private static ConcurrentDictionary<int, int> _leftPrimes = new ConcurrentDictionary<int, int>();
    private static ConcurrentDictionary<int, int> _rightPrimes = new ConcurrentDictionary<int, int>();

    static void Main(string[] args)
    {
        int threadCount = Environment.ProcessorCount;
        Task[] tasks = new Task[threadCount];
        for (int i = 0; i < threadCount; i++)
        {
            int index = i;
            tasks[index] = Task.Run(() => SearchFragilePrimes());
        }
        Task.WaitAll(tasks);
    }

    private const int _lengthIncrement = 1500;
    private static int _length = 7000;
    private static object _lengthLock = new object();
    private static object _consoleLock = new object();

    private static void SearchFragilePrimes()
    {
        int length;
        lock (_lengthLock)
        {
            _length++;
            length = _length;
        }

        while (true)
        {
            lock (_consoleLock)
            {
                Console.WriteLine("{0:T}: length = {1}", DateTime.Now, length);
            }

            bool found = false;
            for (int rightCount = 1; rightCount <= length - 2; rightCount++)
            {
                int leftCount = length - rightCount - 1;
                if (IsFragilePrime(leftCount, rightCount))
                {
                    lock (_consoleLock)
                    {
                        Console.WriteLine("{0:T}: {1} {2}{{{3}}} {4} {2}{{{5}}} {6}",
                            DateTime.Now, _template[0], _template[1], leftCount - 1,
                            _template[2], rightCount - 1, _template[3]);
                    }
                    found = true;
                    break;
                }
            }

            lock (_lengthLock)
            {
                if (found && (_length < length + _lengthIncrement / 2))
                    _length += _lengthIncrement;
                else
                    _length++;
                length = _length;
            }
        }
    }

    private static bool IsFragilePrime(int leftCount, int rightCount)
    {
        int count;
        if (_leftPrimes.TryGetValue(leftCount, out count))
            if (count < rightCount)
                return false;

        if (_rightPrimes.TryGetValue(rightCount, out count))
            if (count < leftCount)
                return false;

        if (!IsPrime(leftCount, rightCount))
            return false;

        for (int i = 0; i < leftCount; i++)
            if (IsPrime(i, rightCount))
                return false;

        for (int i = 0; i < rightCount; i++)
            if (IsPrime(leftCount, i))
                return false;

        return true;
    }

    private static bool IsPrime(int leftCount, int rightCount)
    {
        Tuple<int, int> tuple = Tuple.Create(leftCount, rightCount);
        if (_compositeNumbers.ContainsKey(tuple))
            return false;

        using (mpz_t n = new mpz_t(BuildStr(leftCount, rightCount)))
        {
            bool result = n.IsProbablyPrimeRabinMiller(20);

            if (result)
            {
                _leftPrimes.TryAdd(leftCount, rightCount);
                _rightPrimes.TryAdd(rightCount, leftCount);
            }
            else
                _compositeNumbers.TryAdd(tuple, 0);

            return result;
        }
    }

    private static string BuildStr(int leftCount, int rightCount)
    {
        char[] chars = new char[leftCount + rightCount + 1];
        for (int i = 0; i < chars.Length; i++)
            chars[i] = _template[1];
        chars[0] = _template[0];
        chars[leftCount + rightCount] = _template[3];
        chars[leftCount] = _template[2];
        return new string(chars);
    }
}

İlk cevabınızı doğrulamaya çalışırken, zaten yeni bir tane yolladınız)). Kontrol zaten 24 saat sürdü. Cevap doğru görünüyor. Java’nın BigInteger’ının yerel uygulamalardan daha yavaş olduğuna inanamıyorum. 2, 3, hatta 10 kat daha yavaş düşündüm. Ancak birkaç dakikaya karşı 24 saat çok fazla.
Qualtagh

@Qualtagh Adil olmak gerekirse, 10039 basamaklı sayı, aşağı algoritma nedeniyle bulmak için 35 saat sürdü :) Geçerli programım 6629 basamaklı numaranızı bulmak için yaklaşık 3 dakika, 28164 basamaklı rakamı bulmak için 6 saat sürer.
Suboptimus Prime

İlk cevabınız doğru. Doğrulanmış! Doğrulama 48 saat sürdü. Ve ikinci cevabı doğrulamaya çalışmayacağım bile)). BigInteger'ın neden MPIR'e kıyasla bu kadar yavaş olduğunu merak ediyorum. Sadece JVM / yerli fark mı? Bir "-server" bayrağı belirledim, bu yüzden kodun JIT-derlenmiş olmasını bekleyin. Modüler üstelleştirme algoritmaları farklıdır: Hem Java hem de MPIR, 2 <sup> k </sup> -ary sürgülü pencere kullanır, ancak k = 3, Java'da sabitlenir ve MPIR, üslerin boyutuna göre k seçer. MPIR, birkaç çekirdekte paralel hesaplamalar mı yoksa muhtemelen GPU yetenekleri mi kullanıyor? Java'nın BigInteger'ı değil.
Qualtagh

1
@Qualtagh MPIR'in yalnızca bir CPU çekirdeği kullandığından eminim. Dört çekirdekli bir işlemcide neredeyse 4 kat daha hızlı arama ile sonuçlanan kendimi okuyordum. MPIR ve Java BigInteger'ın iç uygulamasını karşılaştırmamıştım, ancak MPIR'in çarpma ve modüler bölme için daha iyi algoritmalar kullandığını düşünüyorum. Ayrıca, 64-bit CPU'lar için muhtemelen daha iyi optimize edilmiştir ( bu blog gönderisindeki karşılaştırmaya bakın ).
Suboptimus Prime

2
MPIR gerçekten tek çekirdekli ve GPU kullanmıyor. C ve assembler kodunun son derece optimize edilmiş ve iyi ayarlanmış bir karışımıdır. Yalnızca C kullanan (taşınabilirlik nedeniyle) bir MPIR sürümü var, ancak C + ASM sürümü çok daha hızlı. MPIR.Net için kullandığım MPIR sürümü, K8 (1st gen x64) komut setini kullanan C + ASM'dir çünkü MPIR.Net'in tüm x64 PC'lerde çalışmasını istedim. Daha sonraki komut setleri için olan sürümler, benim kripto kıyaslamamda farkedilir şekilde daha hızlı değildi, ama elbette diğer işlemler için farklı olabilir.
John Reynolds,

2

Haskell - 1220 1277 basamak gerçekler için sabit

99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999997999999999999999999999999999999999999999999999999999999999999999999999

9{1150} 7 9{69}

Daha iyi bir - 1277 hane

9{871} 8 9{405}

Haskell kodu

downADigit :: Integer -> [Integer]
downADigit n = f [] 1 where
     f xs a | nma /= n = f (((n `div` a10)*a + nma):xs) a10
            | otherwise = xs where
        a10 = a * 10
        nma = n `mod` a

isFragile = all (not . isPrime') . downADigit
findNextPrime :: Integer -> Integer
findNextPrime n | even n = f (n + 1)
                | otherwise = f n where
    f n | isPrime' n  = n
        | otherwise = f (n + 2)

primesFrom n = f (findNextPrime n) where
    f n = n:f (findNextPrime $ n + 1)

primeLimit = 10000

isPrime' n | n < primeLimit = isPrime n
isPrime' n = all (millerRabinPrimality n) [2,3,5,7,11,13,17,19,984,7283,6628,8398,2983,9849,2739]

-- (eq. to) find2km (2^k * n) = (k,n)
find2km :: Integer -> (Integer,Integer)
find2km n = f 0 n
    where 
        f k m
            | r == 1 = (k,m)
            | otherwise = f (k+1) q
            where (q,r) = quotRem m 2        

-- n is the number to test; a is the (presumably randomly chosen) witness
millerRabinPrimality :: Integer -> Integer -> Bool
millerRabinPrimality n a
    | a <= 1 || a >= n-1 = 
        error $ "millerRabinPrimality: a out of range (" 
              ++ show a ++ " for "++ show n ++ ")" 
    | n < 2 = False
    | even n = False
    | b0 == 1 || b0 == n' = True
    | otherwise = iter (tail b)
    where
        n' = n-1
        (k,m) = find2km n'
        b0 = powMod n a m
        b = take (fromIntegral k) $ iterate (squareMod n) b0
        iter [] = False
        iter (x:xs)
            | x == 1 = False
            | x == n' = True
            | otherwise = iter xs

-- (eq. to) pow' (*) (^2) n k = n^k
pow' :: (Num a, Integral b) => (a->a->a) -> (a->a) -> a -> b -> a
pow' _ _ _ 0 = 1
pow' mul sq x' n' = f x' n' 1
    where 
        f x n y
            | n == 1 = x `mul` y
            | r == 0 = f x2 q y
            | otherwise = f x2 q (x `mul` y)
            where
                (q,r) = quotRem n 2
                x2 = sq x

mulMod :: Integral a => a -> a -> a -> a
mulMod a b c = (b * c) `mod` a
squareMod :: Integral a => a -> a -> a
squareMod a b = (b * b) `rem` a

-- (eq. to) powMod m n k = n^k `mod` m
powMod :: Integral a => a -> a -> a -> a
powMod m = pow' (mulMod m) (squareMod m)

-- simple for small primes
primes :: [Integer]
primes = 2:3:primes' where
    1:p:candidates = [6*k+r | k <- [0..], r <- [1,5]]
    primes'        = p : filter isPrime candidates
    isPrime n      = all (not . divides n)
                                   $ takeWhile (\p -> p*p <= n) primes'
    divides n p    = n `mod` p == 0
isPrime :: Integer -> Bool
isPrime n | n < 2 = False
          | otherwise = f primes where
            f (p:ps) | p*p <= n = if n `rem` p == 0 then False else f ps
                     | otherwise = True

main = do
    print . head $ filter isFragile (primesFrom $ 10^1000)

Son 3 hariç her şeyi kaldırabilirim ...
Sp3000

son 3'ü kaldırdığımda 5 ile bitiyor, böylece 5'e bölünebilir
John Meacham

2
Hayır, son üçe sahip olana kadar herşeyi çıkarmaktan bahsediyorum, ki bu asal olan şey.
Sp3000

1
@JohnMeacham Programım, soldan 386 basamağı kaldırırsanız, bu sayının asal sayıya dönüştüğünü önerir.
Suboptimus Prime

1
Lütfen, göndermeden önce numaralarınızı doğrulayın. Soldaki 1256 basamağı 1276 basamaklı numaranızdan kaldırırsanız, asal olan 99999994999999999999 değerini alırsınız.
Suboptimus Prime
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.