Wprowadzenie
Rozważ proces pobierania dodatniej liczby całkowitej n w pewnej bazie b i zastępowania każdej cyfry jej reprezentacją w podstawie cyfry po prawej stronie.
- Jeśli cyfra po prawej to 0, użyj podstawy b .
- Jeśli cyfra po prawej to 1, użyj unarskiego z zerami jako znakami sumy.
- Jeśli po prawej stronie nie ma cyfry (tzn. Jesteś w tym samym miejscu), zapętl się do najbardziej znaczącej cyfry.
Jako przykład niech n = 160 ib = 10. Uruchomienie procesu wygląda następująco:
The first digit is 1, the digit to the right is 6, 1 in base 6 is 1.
The next digit is 6, the digit to the right is 0, 0 is not a base so use b, 6 in base b is 6.
The last digit is 0, the digit to the right (looping around) is 1, 0 in base 1 is the empty string (but that's ok).
Concatenating '1', '6', and '' together gives 16, which is read in the original base b = 10.
Można również wykonać dokładnie tę samą procedurę, ale przesuwając w lewo zamiast w prawo :
The first digit is 1, the digit to the left (looping around) is 0, 0 is not a base so use b, 1 in base b is 1.
The next digit is 6, the digit to the left is 1, 6 in base 1 is 000000.
The last digit is 0, the digit to the left is 6, 0 in base 6 is 0.
Concatenating '1', '000000', and '0' together gives 10000000, which is read in the original base b = 10.
Tak więc stworzyliśmy dwie liczby związane ze 160 (dla b = 10): 16 i 10000000.
Zdefiniujemy n jako sprytną liczbę, jeśli równomiernie podzieli co najmniej jedną z dwóch liczb wygenerowanych w tym procesie na 2 lub więcej części
W przykładzie n jest przebiegły, ponieważ 160 dzieli 10000000 dokładnie 62500 razy.
203 NIE jest przebiegły, ponieważ wynikowe liczby to 2011 i 203, które 203 nie mogą równomiernie zmieścić się 2 lub więcej razy.
Wyzwanie
(W pozostałej części problemu rozważymy tylko b = 10.)
Wyzwanie polega na napisaniu programu, który znajdzie najwyższą podstępną liczbę, która jest również liczbą pierwszą.
Pierwsze 7 przebiegłych liczb pierwszych (i wszystko, co do tej pory znalazłem) to:
2
5
3449
6287
7589
9397
93557 <-- highest so far (I've searched to 100,000,000+)
Nie jestem oficjalnie pewien, czy jest ich więcej, ale spodziewam się, że tak. Jeśli możesz udowodnić, że jest ich wiele (lub nie ma ich wcale), dam ci +200 nagród.
Zwycięzcą zostanie osoba, która może zapewnić najwyższą podstępną liczbę pierwszą, pod warunkiem, że jest oczywiste, że byli aktywni w poszukiwaniu i nie celowo czerpią chwały od innych.
Zasady
- Możesz użyć dowolnego narzędzia do znajdowania najlepszych wyników.
- Możesz użyć probabilistycznych testerów pierwszych.
- Możesz ponownie użyć kodu innych osób z atrybutami . To wspólny wysiłek. Taktyki przełomu nie będą tolerowane.
- Twój program musi aktywnie wyszukiwać liczbę pierwszą. Możesz rozpocząć wyszukiwanie od najwyższej znanej podstępnej liczby pierwszej.
- Twój program powinien być w stanie obliczyć wszystkie znane sprytne liczby pierwsze w ciągu 4 godzin od wystąpienia Amazon EC2 t2.medium (cztery jednocześnie lub jedna przez cztery godziny lub coś pomiędzy nimi). Nie będę ich na nich testować, a ty na pewno nie musisz. To tylko punkt odniesienia.
Oto mój kod Python 3, którego użyłem do wygenerowania powyższej tabeli: (uruchamia się za sekundę lub dwie)
import pyprimes
def toBase(base, digit):
a = [
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
['', '0', '00', '000', '0000', '00000', '000000', '0000000', '00000000', '000000000' ],
['0', '1', '10', '11', '100', '101', '110', '111', '1000', '1001'],
['0', '1', '2', '10', '11', '12', '20', '21', '22', '100'],
['0', '1', '2', '3', '10', '11', '12', '13', '20', '21'],
['0', '1', '2', '3', '4', '10', '11', '12', '13', '14'],
['0', '1', '2', '3', '4', '5', '10', '11', '12', '13'],
['0', '1', '2', '3', '4', '5', '6', '10', '11', '12'],
['0', '1', '2', '3', '4', '5', '6', '7', '10', '11'],
['0', '1', '2', '3', '4', '5', '6', '7', '8', '10']
]
return a[base][digit]
def getCrafty(start=1, stop=100000):
for p in pyprimes.primes_above(start):
s = str(p)
left = right = ''
for i in range(len(s)):
digit = int(s[i])
left += toBase(int(s[i - 1]), digit)
right += toBase(int(s[0 if i + 1 == len(s) else i + 1]), digit)
left = int(left)
right = int(right)
if (left % p == 0 and left // p >= 2) or (right % p == 0 and right // p >= 2):
print(p, left, right)
if p >= stop:
break
print('DONE')
getCrafty()
źródło
Odpowiedzi:
Mathematica, znajduje 93,557 w 0,3 s (brak dalszych przebiegłych liczb pierwszych poniżej 2 * 10 10 )
To tylko naiwne wyczerpujące przeszukiwanie wszystkich liczb pierwszych. Na początek sprawdza około 1 000 000 liczb pierwszych co 55 sekund (co z pewnością będzie wolniejsze, gdy liczby pierwsze będą większe).
Korzystam z wielu funkcji pomocniczych:
A następnie ta pętla dokonuje właściwego wyszukiwania:
Będę aktualizować post, jeśli znajdę jakieś liczby pierwsze lub będę mógł pomyśleć o optymalizacji.
Obecnie sprawdza wszystkie liczby pierwsze do 100 000 000 w około 5,5 minuty.
Edycja: postanowiłem pójść za przykładem OP i przełączyłem się na tabelę odnośników do konwersji podstawowej. To dało w przybliżeniu 30% przyspieszenia.
Podstępne liczby ogólnie
Przestaję teraz szukać podstępnych liczb pierwszych, ponieważ potrzebowałbym kilku dni, aby nadrobić zaległości w odpowiedzi na pytanie Perla. Zamiast tego zacząłem szukać wszystkich podstępnych liczb. Może ich rozkład pomaga znaleźć dowód na to, że liczba przebiegłych liczb pierwszych jest skończona lub nieskończona.
Definiuję liczby prawostronne, które dzielą pokrewną liczbę uzyskaną przez zinterpretowanie cyfry po prawej stronie jako nowej bazy, i odpowiednio liczby lewostronne . Prawdopodobnie pomoże to rozwiązać je indywidualnie na dowód.
Oto wszystkie sprytne liczby do 2 210 000 000:
A oto wszystkie trafne liczby w tym zakresie:
Zauważ, że istnieje nieskończona liczba podstępnych i podstępnych liczb, ponieważ istnieje kilka sposobów ich generowania z istniejących:
0
s do dowolnej liczby podstępnej pod lewą, której najmniej znacząca cyfra jest większa niż jej najbardziej znacząca cyfra, aby uzyskać kolejną liczbę podstępną.0
s do dowolnej sprytnej liczby, której najmniej znacząca cyfra jest mniejsza niż jej najbardziej znacząca cyfra. To (i poprzednie stwierdzenie) wynika z tego, że0
zostanie dołączone zarówno do podstępnej liczby, jak i powiązanej z nią liczby, skutecznie mnożąc je przez 10.2
s lub5
s jest podstępna.777
s jest podstępna.28
połączonych przez0
s, jak28028028
zawsze jest podstępna.Inne rzeczy do zapamiętania:
125
. Warto sprawdzić je, aby znaleźć inną regułę produkcji.Przypuszczam, że ta lista byłaby bardziej interesująca, gdybym pominęła tych, których istnienie implikuje mniejsza podstępna liczba, zwłaszcza że nigdy nie są one liczbami pierwszymi według odkrytych dotychczas zasad budowy. Oto wszystkie przebiegłe liczby pierwsze, których nie można zbudować według jednej z powyższych zasad:
Zauważ też, że istnieje kilka podwójnie sprytnych liczb (te, które pojawiają się na obu listach, a zatem dzielą obie powiązane liczby):
Istnieje również nieskończenie wiele z nich.
Ale jak widać, z wyjątkiemZnaleziono kontrprzykład16
,28
,68
to wszystko składa się tylko z jednego (powtarzane) cyfry. Interesujące byłoby również udowodnienie, czy jakiekolwiek większe liczby mogą być podstępnie podstępne bez posiadania tej właściwości, ale może to po prostu wynikać z dowodu na liczby podstępnie pojedynczych.1944919449
.źródło
100540625, 100540625
na swojej trafnej liście?Perl (1e5 w 0,03s, 1e8 w 21s). Maksymalnie 93557 do 1e11.
Bardzo podobny do oryginału. Zmiany obejmują:
Wykonuje pierwsze 1e8 w ciągu 21 sekund na mojej szybkiej maszynie, 3,5 minuty dla 1e9, 34 minuty dla 1e10. Jestem trochę zaskoczony, że w ogóle jest szybszy niż kod Python dla małych danych wejściowych. Możemy to zrobić równolegle (nowy Pari / GP
parforprime
byłby do tego miły). Ponieważ jest to wyszukiwanie, które możemy ręcznie zrównoleglać (forprimes
może przyjąć dwa argumenty).forprimes
jest w zasadzie podobny do Pari / GPforprime
- wykonuje segmentowane sita wewnętrznie i wywołuje blok przy każdym wyniku. Jest to wygodne, ale w przypadku tego problemu nie sądzę, aby był to obszar wydajności.źródło
C ++ 11, z wątkami i GMP
Czas (na MacBooku Air):
Wymagania:
g++ crafty.cpp -o crafty --std=c++11 -ffast-math -lprimesieve -O3 -lgmpxx -lgmp -Wall -Wextra
Wynik:
źródło
C, z GMP, wielowątkowy (1e8 w 17s dla 1 wątku)
Podobny w koncepcji do reszty, z pewnymi optymalizacjami tu i tam.
Skompilować:
gcc -I/usr/local/include -Ofast crafty.c -pthread -L/usr/local/lib -lgmp && ./a.out
Podaruj moc procesora. Nie mam szybkiego komputera.
1e8 w 17 sekund z 1 wątkiem na moim MacBooku Air.
źródło
Python znajduje 93557 w 0,28 s
Bardzo podobny do kodu OP, ponieważ używa również
pyprimes
. Sam to napisałem przez xDDrukuje także czas od początku znalezienia numeru.
Wynik:
Format to
number left right time
. Dla porównania kod OP znajduje około 935570.37
.źródło