Calculer l'inverse modulaire

16

Étant donné deux nombres positifs xet navec x<2^n, écrivez la fonction la plus courte possible à calculer x^-1 mod 2^n. En d'autres termes, trouvez ytel que x*y=1 mod 2^n.

Votre fonction doit s'achever dans un délai raisonnable pendant au moins n=64, donc une recherche exhaustive ne fonctionnera pas.

Si l'inverse n'existe pas, vous devez l'indiquer à l'appelant d'une manière ou d'une autre (lever une exception, renvoyer une valeur sentinelle, etc.).

Si vous vous demandez par où commencer, essayez l' algorithme euclidien étendu .

Keith Randall
la source
cela va être une seule déclaration dans certains logiciels de mathématiques
st0le
1
@ st0le: D'accord, et vous ne seriez pas autorisé à utiliser une telle fonction dans de tels systèmes. :-D
Chris Jester-Young

Réponses:

2

Python 95 89

cest votre fonction. Renvoie 0 s'il n'y a pas d'inverse (c'est-à-dire lorsque x est pair).

p=lambda x,y,m:y and p(x,y/2,m)**2*x**(y&1)%m or 1
c=lambda x,n:[0,p(x,2**n-1,2**n)][x%2]
Alexandru
la source
3

Python, 29 octets

lambda x,n:pow(x,2**n-1,2**n)

Cela renvoie 0 pour pair x . Il utilise le théorème d'Euler, avec l'observation que 2 ^ n - 1 est divisible par 2 ^ ( n - 1) - 1, via l'exponentiation modulaire rapide intégrée de Python. C'est assez rapide pour n jusqu'à 7000 environ, où cela commence à prendre plus d'une seconde environ.

Anders Kaseorg
la source
2

Mathematica - 22

f=PowerMod[#,-1,2^#2]&

f[x,n]retourne yavec x*y=1 mod 2^n, sinonx is not invertible modulo 2^n

branislav
la source
2

GolfScript (23 caractères)

{:^((1${\.**2^?%}+*}:f;

Le résultat sentinelle pour un inverse inexistant est 0.

Il s'agit d'une application simple du théorème d' Euler . , donc x - 1x 2 n - 1 - 1xφ(2n)1(mod2n)x1x2n11(mod2n)

Malheureusement, c'est une exponentielle un peu trop grande pour être calculée directement, nous devons donc utiliser une boucle et effectuer une réduction modulaire à l'intérieur de la boucle. L'étape itérative est et nous avons le choix du cas de base: soit avecx2k1=(x2k11)2×xk=1

{1\:^(@{\.**2^?%}+*}:f;

ou k=2avec

{:^((1${\.**2^?%}+*}:f;

Je travaille sur une autre approche, mais la sentinelle est plus difficile.

L'observation clé est que nous pouvons construire l'inverse vers le haut peu à peu: si puis x y { 1 , 1 + 2 k - 1xy1(mod2k1) , et si x est impair, nous avons x ( y + x y - 1 ) 1xy{1,1+2k1}(mod2k)x . (Si vous n'êtes pas convaincu, vérifiez les deux cas séparément). Nous pouvons donc commencer à n'importe quel cas de base approprié et appliquer la transformation y = ( x + 1 ) y - 1 un nombre approprié de fois.x(y+xy1)1(mod2k)y=(x+1)y1

Depuis on obtient, par induction0x1(mod20)

x(1(x+1)nx)1(mod2n)

où l'inverse est la somme d'une séquence géométrique. J'ai montré la dérivation pour éviter l'effet lapin hors du chapeau: étant donné cette expression, il est facile de voir que (étant donné que la valeur entre crochets est un entier, qui découle de sa dérivation comme une somme d'un entier séquence) le produit de gauche doit être dans la classe d'équivalence droite si est pair.x+1

Cela donne la fonction 19 caractères

{1$)1$?@/~)2@?%}:f;

qui donne des réponses correctes pour les entrées qui ont un inverse. Cependant, ce n'est pas si simple quand est pair. Une option potentiellement intéressante que j'ai trouvée est d'ajouter plutôt que .xx&11

{1$.1&+1$?@/~)2@?%}:f;

02n1 , mais je ne l'ai pas encore prouvé.

01(x+1)n11n

{1$.1&*)1$?@/~)2@?%}:f;

nn x f

{..1&*)2$?\/~)2@?%}:f;
Peter Taylor
la source
1

Ruby - 88 caractères

Utilisez la fonction f.

def e a,b;a%b==0?[0,1]:(x,y=e(b,a%b);[y,x-(y*(a/b))])end
def f x,n;e(x,2**n)[0]*(x%2)end

La fonction récursive de la page wiki liée renvoie simplement 0 en cas d'erreur.

Nemo157
la source
Vous pouvez enregistrer des caractères par e inline: (e=->a,b{...})[x,2**n][0]. Peut également enregistrer un personnage en testant a%b<1au lieu de a%b==0.
histocrate
1

Haskell, 42 octets

_!1=1
x!n|r<-x!div(n+1)2=(2-r*x)*r`mod`2^n

En utilisant un algorithme basé sur le lemme de Hensel qui double le nombre de chiffres à chaque itération, cela fonctionne en moins d'une seconde pour n jusqu'à environ 30 millions !

Anders Kaseorg
la source
1

Pyth , 9 octets

.^Et^2Q^2

Essayez-le ici!

Prend la saisie dans l'ordre inverse. Ou, 9 octets aussi: .^EtK^2QK.

Explication

. ^ Et ^ 2Q ^ 2 - Programme complet.

. ^ - Fonction Pow. La même chose en Python (pow).
  E - La deuxième entrée.
    ^ 2Q - Et 2 ^ première entrée.
   t - décrémenté.
       ^ 2 - Et 2 ^ la première entrée à nouveau.
M. Xcoder
la source
0

GAP, 39 octets

f:=function(x,n)return 1/x mod 2^n;end;

f(x,n)renvoie l'inverse de xmodulo 2^net donne un message d'erreur

Error, ModRat: for <r>/<s> mod <n>, <s>/gcd(<r>,<s>) and <n> must be coprime

s'il n'y a pas d'inverse.

ahulpke
la source