Racine carrée un nombre

13

La tâche est la suivante: étant donné un entier positif xet un nombre premier n > x, sortez le plus petit entier positif ytel que (y * y) mod n = x. Une partie importante de cette question est le délai spécifié ci-dessous qui exclut les solutions de force brute.

S'il n'y a pas une telle valeur, yvotre code devrait sortir N.

Cas de 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)

Entrée et sortie

Vous pouvez prendre une entrée et donner une sortie de la manière qui vous convient. Si vous n'aimez pas sortir, Nn'importe quelle Falseyvaleur fera l'affaire.

Restrictions

Votre code doit répondre à tous les cas de test en moins d'une minute sur un bureau standard. Ce délai est uniquement destiné à empêcher les réponses par force brute et je m'attends à ce que les bonnes réponses s'exécutent presque instantanément. Vous ne pouvez pas utiliser de bibliothèque ou de module intégré qui résout ce problème ou qui teste si un nombre est un résidu quadratique.


la source
2
Ainsi, les langues sans prise en charge du type de données à grand entier sont exclues. Dommage
Luis Mendo
1
@LuisMendo Pas si vous pouvez coder le support pour 1267650600228229401496703205653vous-même ou si vous avez un support 128 bits comme __int128dans gcc. Il existe également un certain nombre de bibliothèques int 256 bits pour différentes langues. Enfin, de nombreuses langues ont une bibliothèque int de précision arbitraire.

Réponses:

7

Pyth, 83 82 octets

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

Suite de tests

Ce programme implémente l' algorithme Tonelli-Shanks . Je l'ai écrit en suivant de près la page Wikipedia. Il faut en entrée (n, p).

L'absence d'une racine carrée est signalée par l'erreur suivante:

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

Il s'agit d'un code très complexe, écrit dans le style impératif, par opposition au style fonctionnel plus courant de Pyth.

Le seul aspect subtil de Pyth que j'utilise est celui =qui, s'il n'est pas immédiatement suivi d'une variable, recherche dans le programme la variable suivante, puis assigne le résultat de l'expression suivante à cette variable, puis renvoie ce résultat. Je ferai référence tout au long de l'explication à la page wikipedia: algorithme Tonelli-Shanks , car c'est l'algorithme que j'implémente.

Explication:

=eAQ

Aprend un tuple à 2 en entrée, attribue les valeurs à Get Hrespectivement, et renvoie son entrée. Qest l'entrée initiale. erenvoie le dernier élément d'une séquence. Après cet extrait, Gest n, Het Qest p.

M.^GHQ

Mdéfinit une fonction à 2 entrées g, où les entrées sont Get H. .^est la fonction d'exponentiation modulaire rapide de Pyth. Cet extrait définit gcomme signifiant le mod d'exponentiation Q.

Kf%=/H=2;1

fdéfinit une répétition jusqu'à une fausse boucle et renvoie le nombre d'itérations pour lesquelles il s'exécute, donné 1en entrée. À chaque itération de la boucle, nous divisons Hpar 2, réglons Hsur cette valeur et vérifions si le résultat est impair. Une fois qu'il est, nous nous arrêtons. Kstocke le nombre d'itérations nécessaires.

Une chose très délicate est le =2;bit. =recherche à l'avance la variable suivante, qui est Tdonc Tdéfinie sur 2. Cependant, à l' Tintérieur d'une fboucle se trouve le compteur d'itérations, que nous utilisons ;pour obtenir la valeur de Tde l'environnement global. Ceci est fait pour économiser quelques octets d'espace blanc qui seraient autrement nécessaires pour séparer les nombres.

Après cet extrait, Kprovient Sde l'article de wikipedia (wiki), et Hest Qdu wiki, et l' Test 2.

=gftgT/Q;1H

Maintenant, nous devons trouver un mod quadratique non résiduel p. Nous allons forcer cela en utilisant le critère d'Euler. /Q2est (p-1)/2, puisque /est la division au sol, ftgT/Q;1trouve donc le premier entier TT ^ ((p-1)/2) != 1, comme vous le souhaitez. Rappelez-vous que ;tire à nouveau Tde l'environnement mondial, qui est toujours 2. Ce résultat est zdu wiki.

Ensuite, pour créer à cpartir du wiki, nous avons besoin z^Q, donc nous enveloppons ce qui précède g ... Het attribuons le résultat à T. Maintenant, Tc'est cdu wiki.

Jg~gGHh/H2

Séparons ce: ~gGH. ~est similaire =, mais renvoie la valeur d'origine de la variable, pas sa nouvelle valeur. Ainsi, il revient G, qui provient ndu wiki.

Cela affecte Jla valeur de n^((Q+1)/2), qui provient Rdu wiki.

Maintenant, ce qui suit prend effet:

~gGH

Cela affecte Gla valeur n^Q, qui provient tdu wiki.

Maintenant, nous avons nos variables de boucle configurées. M, c, t, Rdu wiki sont K, T, G, J.

Le corps de la boucle est compliqué, donc je vais le présenter avec les espaces, comme je l'ai écrit:

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

Tout d'abord, nous vérifions si Gest 1. Si oui, nous quittons la boucle.

Le code suivant qui s'exécute est:

=Kfq1gG^2T1

Ici, nous recherchons la première valeur de itelle sorte que G^(2^i) mod Q = 1, à partir de 1. Le résultat est enregistré dans K.

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

Ici, nous prenons l'ancienne valeur de K, soustrayons la nouvelle valeur de K, soustrayons 1, augmentons 2 à cette puissance, puis augmentons Tà ce mod de puissance Q, puis attribuons le résultat à T. Cela Téquivaut à bpartir du wiki.

C'est également la ligne qui termine la boucle et échoue s'il n'y a pas de solution, car dans ce cas, la nouvelle valeur de Ksera égale à l'ancienne valeur de K, 2 sera élevée à la -1, et l'exponentiation modulaire générera une erreur.

=*J

Ensuite, nous multiplions Jpar le résultat ci-dessus et le stockons à nouveau J, en restant à Rjour.

=^T2

Ensuite, nous corrigeons Tet stockons le résultat dans T, en Trevenant au cwiki.

=%*G=^T2Q

Ensuite, nous multiplions Gpar ce résultat, le prenons mod Qet stockons le résultat G.

;

Et nous terminons la boucle.

Une fois la boucle terminée, Jest une racine carrée de nmod p. Pour trouver le plus petit, nous utilisons le code suivant:

hS%_BJ

_BJcrée la liste de Jet sa négation, %prend implicitement Qcomme deuxième argument et utilise le comportement par défaut de Pyth pour s'appliquer % ... Qà chaque membre de la séquence. STrie ensuite la liste et hprend son premier membre, le minimum.

isaacg
la source
11

Python 2, 166 octets

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)
orlp
la source
%timeit Q(1267650600228229401496703204676,1267650600228229401496703205653) 100 loops, best of 3: 2.83 ms per loop :)
3
Quelle bonne réponse! Vous avez rétabli ma foi en PPCG.
5
Excusez la question du débutant, mais qu'est-ce que PPCG? Groupe de codeurs polonais Python?
Reversed Engineer
@DaveBoltman Programmation Puzzles & Code Golf.
orlp
3

Haskell , 326 octets

Habituellement, j'aime les réponses par force brute. Comme cela est fortement déconseillé par le délai, voici le moyen le plus efficace que je connaisse:

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)

Essayez-le en ligne!

Je suis sûr que cela peut être approfondi, mais cela devrait faire pour l'instant.

ბიმო
la source
Pourriez-vous modifier le code TIO afin qu'il donne les réponses en sortie? Je reçois juste "True" pour le moment.
1
Essayez-le en ligne!
Ørjan Johansen
@Lembik Vous devez le remplacer testCasespar ceux du TIO d'origine, il rentre à peine dans un commentaire même sans eux.
Ørjan Johansen
@ ØrjanJohansen Merci beaucoup! J'ai ajusté ma réponse avec votre code et remplacé testCases.
ბიმო
Huh, je vois un bug bizarre avec ce lien TIO - si je clique dessus, il a le code mais ne fonctionne pas ni que l'URL des options de menu fonctionne - mais si je copie l'URL de la barre d'adresse et la colle dans un onglet différent, alors cela fonctionne.
Ørjan Johansen