Radice quadrata un numero


13

Il compito è il seguente: Dato un numero intero positivo xe un numero primo n > x, emette il numero intero positivo più piccolo ytale che (y * y) mod n = x. Una parte importante di questa domanda è il limite di tempo specificato di seguito che esclude le soluzioni di forza bruta.

Se non esiste tale valore, yil codice dovrebbe essere generato N.

Casi test

(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)

Ingresso e uscita

Puoi prendere input e dare output in qualsiasi modo sia conveniente. Se non ti piace l'output, Nqualsiasi Falseyvalore lo farà.

restrizioni

Il tuo codice deve rispondere a tutti i casi di test in meno di 1 minuto su un desktop standard. Questo limite di tempo serve solo a prevenire le risposte della forza bruta e mi aspetto che le risposte valide vengano eseguite quasi all'istante. Non è possibile utilizzare alcuna libreria o built-in che risolva questo problema o che verifica se un numero è un residuo quadratico.


2
Pertanto, le lingue senza supporto per il tipo di dati a numero intero sono escluse. Peccato
Luis Mendo il

1
@LuisMendo Non se puoi codificare il supporto per 1267650600228229401496703205653te stesso o se hai un supporto a 128 bit come __int128in gcc. Esistono anche diverse librerie int a 256 bit per varie lingue. Infine, molte lingue hanno una libreria int di precisione arbitraria.

Risposte:


7

Pyth, 83 82 byte

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

Suite di test

Questo programma implementa l' algoritmo Tonelli-Shanks . L'ho scritto seguendo da vicino la pagina di Wikipedia. Ci vuole come input (n, p).

L'assenza di una radice quadrata è segnalata dal seguente errore:

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

Questo è un codice molto complicato, scritto nello stile imperativo, in contrapposizione allo stile funzionale più comune di Pyth.

L'unico aspetto sottile di Pyth che sto usando è =, che, se non immediatamente seguito da una variabile, cerca in avanti nel programma la variabile successiva, quindi assegna il risultato della seguente espressione a quella variabile, quindi restituisce quel risultato. Farò riferimento in tutta la spiegazione alla pagina di Wikipedia: algoritmo Tonelli-Shanks , in quanto è l'algoritmo che sto implementando.

Spiegazione:

=eAQ

Aprende un 2-tuple come input, e assegna i valori Ge H, rispettivamente, e restituisce il suo ingresso. Qè l'input iniziale. erestituisce l'ultimo elemento di una sequenza. Dopo questo frammento, Gè n, He Qsono p.

M.^GHQ

Mdefinisce una funzione a 2 ingressi g, dove sono gli ingressi Ge H. .^è la funzione esponenziale modulare rapida di Pyth. Questo frammento definisce gmod esponenziale Q.

Kf%=/H=2;1

fdefinisce una ripetizione fino a false loop e restituisce il numero di iterazioni per cui viene eseguita, dato 1come input. Durante ogni iterazione del loop, dividiamo Hper 2, impostiamo Hsu quel valore e controlliamo se il risultato è dispari. Una volta che lo è, ci fermiamo. Kmemorizza il numero di iterazioni necessarie.

Una cosa molto delicata è la parte =2;. =cerca in anticipo la prossima variabile, che è T, quindi Tè impostata su 2. Tuttavia, Tall'interno di un fciclo si trova il contatore di iterazioni, quindi usiamo ;per ottenere il valore Tdall'ambiente globale. Questo viene fatto per salvare un paio di byte di spazio bianco che altrimenti sarebbero necessari per separare i numeri.

Dopo questo frammento, Kviene Sdall'articolo di Wikipedia (wiki), ed Hè Qdal wiki, e lo Tè 2.

=gftgT/Q;1H

Ora, dobbiamo trovare un mod quadratico non residuo p. Lo faremo forzare brutalmente usando il criterio di Eulero. /Q2è (p-1)/2, poiché /è la divisione floored, quindi ftgT/Q;1trova il primo numero intero Tdove T ^ ((p-1)/2) != 1, come desiderato. Ricordiamo che ;tira ancora Tdall'ambiente globale, che è ancora 2. Questo risultato è zdal wiki.

Quindi, per creare cdal wiki, abbiamo bisogno z^Q, quindi avvolgiamo quanto sopra g ... He assegniamo il risultato a T. Ora Tè cdal wiki.

Jg~gGHh/H2

Diamo separano questo: ~gGH. ~è come =, ma restituisce il valore originale della variabile, non il suo nuovo valore. Quindi, ritorna G, che nproviene dal wiki.

Questo assegna Jil valore di n^((Q+1)/2), che Rproviene dal wiki.

Ora, ha effetto:

~gGH

Questo assegna Gil valore n^Q, che tproviene dal wiki.

Ora, abbiamo impostato le nostre variabili loop. M, c, t, Rdal wiki sono K, T, G, J.

Il corpo del loop è complicato, quindi lo presenterò con lo spazio bianco, come l'ho scritto:

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

Innanzitutto, controlliamo se Gè 1. In tal caso, usciamo dal loop.

Il prossimo codice che viene eseguito è:

=Kfq1gG^2T1

Qui, cerchiamo il primo valore di itale che G^(2^i) mod Q = 1, a partire da 1. Il risultato viene salvato in K.

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

Qui, prendiamo il vecchio valore di K, sottraggiamo il nuovo valore di K, sottraggiamo 1, aumentiamo 2 a quella potenza, quindi aumentiamo Ta quella mod potenza Q, quindi assegniamo il risultato a T. Ciò Tequivale a bdal wiki.

Questa è anche la linea che termina il ciclo e fallisce se non c'è soluzione, perché in quel caso il nuovo valore di Ksarà uguale al vecchio valore di K, 2 sarà elevato a -1, e l'esponente modulare genererà un errore.

=*J

Successivamente, moltiplichiamo Jper il risultato sopra riportato e lo memorizziamo nuovamente J, mantenendoci Raggiornati.

=^T2

Quindi quadriamo Te memorizziamo il risultato T, Ttornando a cdal wiki.

=%*G=^T2Q

Quindi moltiplichiamo Gper quel risultato, prendiamo mod Qe memorizziamo il risultato G.

;

E terminiamo il ciclo.

Dopo che il ciclo è finito, Jè una radice quadrata di nmod p. Per trovare il più piccolo, utilizziamo il seguente codice:

hS%_BJ

_BJcrea l'elenco di Je la sua negazione, %prende implicitamente Qcome secondo argomento e usa il comportamento predefinito di Pyth da applicare % ... Qa ciascun membro della sequenza. Quindi Sordina l'elenco e haccetta il suo primo membro, il minimo.


11

Python 2, 166 byte

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
Che grande risposta! Hai ripristinato la mia fiducia in PPCG.

5
Scusa la domanda da principiante, ma qual è il PPCG? Gruppo polacco di programmatori Python?
Ingegnere invertito,

Puzzle di programmazione @DaveBoltman e Code Golf.
orlp,


3

Haskell , 326 byte

Di solito mi piacciono le risposte alla forza bruta. Dato che questo è fortemente scoraggiato dal limite di tempo, ecco il modo più efficiente che conosco:

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)

Provalo online!

Sono sicuro che questo può essere ulteriormente approfondito, ma per ora dovrebbe essere così.


Potresti modificare il codice TIO in modo che fornisca le risposte come output? Ho appena ottenuto "True" al momento.


@Lembik Devi sostituirlo testCasescon quelli del TIO originale, si adatta a malapena a un commento anche senza di loro.
Ørjan Johansen,

@ ØrjanJohansen Grazie mille! Ho modificato la mia risposta con il tuo codice e sostituito testCases.
ბიმო

Uh, sto vedendo un bizzarro bug con quel link TIO - se faccio clic su di esso ha il codice ma né funziona né ottiene l'URL dalle opzioni del menu funziona - ma se copio l'URL dalla barra degli indirizzi e lo incollo in un scheda diversa, quindi funziona.
Ørjan Johansen,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.