Quadratwurzel eine Zahl


13

Die Aufgabe lautet wie folgt: Geben Sie bei einer positiven Ganzzahl xund einer Primzahl n > xdie kleinste positive Ganzzahl yso aus, dass (y * y) mod n = x. Ein wichtiger Teil dieser Frage ist die unten angegebene Frist, die Brute-Force-Lösungen ausschließt.

Wenn es keinen solchen Wert gibt, ysollte Ihr Code ausgegeben werden N.

Testfälle

(2, 5, N), 
(3, 5, N), 
(4, 5, 2),
(524291, 1048583, N),
(529533, 1048583, N),
(534775, 1048583, 436853),
(540017, 1048583, 73675),
(536870913, 1073741827, 375394238),
(542239622, 1073741827, 267746399),
(547608331, 1073741827, N),
(552977040, 1073741827, 104595351),
(1099511627676, 1099511627791, N),
(1099511627677, 1099511627791, 269691261521),
(1099511627678, 1099511627791, 413834069585),
(1267650600228229401496703204376, 1267650600228229401496703205653, 5312823546347991512233563776),
(1267650600228229401496703204476, 1267650600228229401496703205653, N)
(1267650600228229401496703204576, 1267650600228229401496703205653, N)
(1267650600228229401496703204676, 1267650600228229401496703205653, 79905476259539917812907012931)

Ein- und Ausgabe

Sie können Eingaben vornehmen und Ausgaben auf eine bequeme Weise geben. Wenn Sie nicht ausgeben Nmöchten, reicht ein beliebiger FalseyWert aus.

Beschränkungen

Ihr Code muss alle Testfälle in weniger als 1 Minute auf einem Standarddesktop beantworten. Dieses Zeitlimit dient nur dazu, Brute-Force-Antworten zu verhindern, und ich erwarte, dass gute Antworten fast sofort ausgeführt werden. Sie dürfen keine Bibliothek oder eingebaute Bibliothek verwenden, die dieses Problem löst oder testet, ob eine Zahl ein quadratischer Rest ist.


2
Sprachen ohne Unterstützung für Big-Integer-Datentypen sind daher ausgeschlossen. Schade
Luis Mendo

1
@ LuisMendo Nicht, wenn Sie die Unterstützung für sich 1267650600228229401496703205653selbst verschlüsseln können oder wenn Sie 128-Bit-Unterstützung haben, wie __int128in gcc. Es gibt auch eine Reihe von 256-Bit-Int-Bibliotheken für verschiedene Sprachen. Schließlich haben viele Sprachen eine beliebige Genauigkeit in der Bibliothek.

Antworten:


7

Pyth, 83 82 Bytes

=eAQM.^GHQKf%=/H=2;1=gftgT/Q;1HJg~gGHh/H2WtG=*J=gT^2t-K=Kfq1gG^2T1=%*G=^T2Q;hS%_BJ

Testsuite

Dieses Programm implementiert den Tonelli-Shanks-Algorithmus . Ich habe es geschrieben, indem ich der Wikipedia-Seite genau gefolgt bin. Es nimmt als Eingabe (n, p).

Das Fehlen einer Quadratwurzel wird durch den folgenden Fehler gemeldet:

TypeError: pow() 3rd argument not allowed unless all arguments are integers

Dies ist ein sehr komplexer Code, der im imperativen Stil geschrieben ist, im Gegensatz zu dem allgemeineren funktionalen Stil von Pyth.

Der eine subtile Aspekt von Pyth, den ich verwende, ist =, dass, wenn nicht unmittelbar gefolgt von einer Variablen, im Programm nach der nächsten Variablen gesucht wird, dann das Ergebnis des folgenden Ausdrucks dieser Variablen zugewiesen wird und dann dieses Ergebnis zurückgegeben wird. Ich werde während der Erklärung auf die Wikipedia-Seite verweisen: Tonelli-Shanks-Algorithmus , da dies der Algorithmus ist, den ich implementiere.

Erläuterung:

=eAQ

Animmt eine 2-Tupel als Eingabe, und ordnet die Werte Gund Hbzw. und kehrt seine Eingabe. Qist die anfängliche Eingabe. eGibt das letzte Element einer Sequenz zurück. Nach diesem Ausschnitt Gist nund Hund Qsind p.

M.^GHQ

Mdefiniert eine 2-Eingangsfunktion g, bei der die Eingänge Gund sind H. .^ist Pyths schnelle modulare Exponentiationsfunktion. Dieses Snippet definiert gals Exponentiation Mod Q.

Kf%=/H=2;1

fDefiniert eine Wiederholung bis zur falschen Schleife und gibt die Anzahl der Iterationen zurück, für die sie ausgeführt wird, angegeben 1als Eingabe. Während jeder Iteration der Schleife teilen wir Hdurch 2, setzen Hdiesen Wert und prüfen, ob das Ergebnis ungerade ist. Sobald es soweit ist, hören wir auf. Kspeichert die Anzahl der Iterationen, die dies dauerte.

Eine sehr schwierige Sache ist das =2;bisschen. =sucht im Voraus nach der nächsten Variablen, die Talso Tauf 2 gesetzt ist. In Teiner fSchleife befindet sich jedoch der Iterationszähler, mit dem wir ;den Wert von Taus der globalen Umgebung abrufen. Dies geschieht, um ein paar Bytes Whitespace zu sparen, die sonst zum Trennen der Zahlen benötigt würden.

Nach diesem Snippet Kist Saus dem Wikipedia-Artikel (Wiki) und Hist Qaus dem Wiki, und Tist 2.

=gftgT/Q;1H

Jetzt müssen wir einen quadratischen Mod ohne Rückstand finden p. Wir werden dies mit dem Euler-Kriterium brachial erzwingen. /Q2ist , (p-1)/2da /Boden Teilung ist, so dass ftgT/Q;1die erste ganze Zahl findet , Two T ^ ((p-1)/2) != 1, wie gewünscht. Denken Sie daran, dass dies ;wieder Taus der globalen Umgebung stammt, die immer noch 2 ist. Dieses Ergebnis stammt zaus dem Wiki.

Als nächstes cmüssen z^Qwir aus dem Wiki erstellen , also wickeln wir das Obige ein g ... Hund weisen das Ergebnis zu T. Jetzt Tkommt caus dem Wiki.

Jg~gGHh/H2

Lassen Sie uns das trennen: ~gGH. ~ist wie =, gibt aber den ursprünglichen Wert der Variablen zurück, nicht ihren neuen Wert. Somit kehrt es zurück G, was naus dem Wiki stammt.

Dies weist Jden Wert von zu n^((Q+1)/2), der Raus dem Wiki stammt.

Nun wird Folgendes wirksam:

~gGH

Dies weist Gden Wert zu n^Q, der taus dem Wiki stammt.

Jetzt haben wir unsere Schleifenvariablen eingerichtet. M, c, t, Raus dem wiki sind K, T, G, J.

Der Text der Schleife ist kompliziert, daher werde ich das Leerzeichen so darstellen, wie ich es geschrieben habe:

WtG
  =*J
    =
      gT^2
        t-
          K
          =Kfq1gG^2T1
  =%*G=^T2Q;

Zuerst prüfen wir, ob 1 Gist. Wenn ja, verlassen wir die Schleife.

Der nächste Code, der ausgeführt wird, ist:

=Kfq1gG^2T1

Hier suchen wir nach dem ersten Wert , iso dass G^(2^i) mod Q = 1, beginnend bei 1. Das Ergebnis in wird gespeichert K.

=gT^2t-K=Kfq1gG^2T1

Hier nehmen wir den alten Wert von K, subtrahieren den neuen Wert von K, subtrahieren 1, erhöhen 2 zu dieser Potenz und erhöhen dann Tzu dieser Potenzmodifikation Qund weisen dann das Ergebnis zu T. Das macht Tgleich baus dem Wiki.

Dies ist auch die Zeile, die die Schleife beendet und fehlschlägt, wenn es keine Lösung gibt, da in diesem Fall der neue Wert von Kgleich dem alten Wert von ist K, 2 auf das erhöht -1wird und die modulare Exponentiation einen Fehler auslöst.

=*J

Als nächstes multiplizieren wir Jmit dem obigen Ergebnis und speichern es zurück J, wobei wir es auf dem neuesten RStand halten .

=^T2

Dann haben wir Platz Tund das Ergebnis zurück in T, Einstellung Tzurück zu caus dem Wiki.

=%*G=^T2Q

Dann multiplizieren wir Gmit diesem Ergebnis, nehmen den Mod Qund speichern das Ergebnis wieder in G.

;

Und wir beenden die Schleife.

Nachdem die Schleife vorbei ist, Jist eine Quadratwurzel von nmod p. Um den kleinsten zu finden, verwenden wir den folgenden Code:

hS%_BJ

_BJErstellt die Liste Jund deren Negation, %nimmt implizit Qals zweites Argument und wendet das Standardverhalten von Pyth % ... Qauf jedes Mitglied der Sequenz an. Dann Ssortiert die Liste und hnimmt sein erstes Mitglied, das Minimum.


11

Python 2, 166 Bytes

def Q(x,n,a=0):
 e=n/2
 while pow(a*a-x,e,n)<2:a+=1
 w=a*a-x;b=r=a;c=s=1
 while e:
    if e%2:r,s=(r*b+s*c*w)%n,r*c+s*b
    b,c=(b*b+c*c*w)%n,2*b*c;e/=2
 return min(r,-r%n)

%timeit Q(1267650600228229401496703204676,1267650600228229401496703205653) 100 loops, best of 3: 2.83 ms per loop :)

3
Was für eine großartige Antwort! Sie haben mein Vertrauen in PPCG wiederhergestellt.

5
Entschuldigen Sie die Anfängerfrage, aber was ist PPCG? Polnische Python-Codierer-Gruppe?
Reverse Engineer

@ DaveBoltman Programmierpuzzles & Code Golf.
Orlp


3

Haskell , 326 Bytes

Normalerweise mag ich Brute-Force-Antworten. Da dies vom Zeitlimit stark abgehalten wird, ist dies der effizienteste Weg, den ich kenne:

r p=((\r->min(mod(-r)p)r)$).f p
f p x|p==2=x|q x=f 0 0|mod p 4==3=x&div(p+1)4|let(r,s)=foldl i(p-1,0)[1..t 1o]=m$x&(d$r+1)*(b&d s)where q a=1/=a&o;m=(`mod`p);a&0=1;a&e|even e=m$a&d e^2|0<1=m$(a&(e-1))*a;b=[n|n<-[2..],q n]!!0;i(a,b)_|m(x&d a*b&d b)==p-1=(d a,d b+o)|0<1=(d a,d b);o=d p;t y x|even x=t(y+1)(d x)|0<1=y;d=(`div`2)

Probieren Sie es online!

Ich bin mir sicher, dass dies weiter verbessert werden kann, aber dies sollte vorerst reichen.


Könnten Sie den TIO-Code so ändern, dass er die Antworten als Ausgabe liefert? Ich bekomme gerade "True".


@Lembik Du musst testCasesmit denen aus dem Original TIO ersetzen , es passt auch ohne sie kaum in einen Kommentar.
Ørjan Johansen

@ ØrjanJohansen Vielen Dank! Ich habe meine Antwort mit Ihrem Code angepasst und ersetzt testCases.
10.

Huh, ich sehe einen bizarren Fehler mit diesem TIO-Link - wenn ich darauf klicke, hat er den Code, läuft aber nicht und die URL aus den Menüoptionen funktioniert nicht - aber wenn ich die URL aus der Adressleiste kopiere und in einen kopiere andere Registerkarte, dann funktioniert es.
Ørjan Johansen
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.