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 .


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]

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.


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


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;

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.


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

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.

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.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.