Modulare Inverse berechnen

16

Bei zwei positiven Zahlen xund nmitx<2^nSchreiben Sie bei die kürzestmögliche zu berechnende Funktion x^-1 mod 2^n. Mit anderen Worten, finde yso etwas x*y=1 mod 2^n.

Ihre Funktion muss mindestens in einer angemessenen Zeit abgeschlossen sein n=64, damit eine umfassende Suche nicht funktioniert.

Wenn die Umkehrung nicht existiert, müssen Sie dies dem Aufrufer irgendwie anzeigen (eine Ausnahme auslösen, einen Sentinel-Wert zurückgeben usw.).

Wenn Sie sich fragen, wo Sie anfangen sollen, probieren Sie den erweiterten euklidischen Algorithmus .

Keith Randall
quelle
Dies wird eine einzelne Aussage in einigen Mathe-Software sein
st0le
1
@ st0le: Richtig, und Sie könnten eine solche Funktion in solchen Systemen nicht verwenden. :-D
Chris Jester-Young

Antworten:

2

Python 95 89

cist deine Funktion. Gibt 0 zurück, wenn es keine Inverse gibt (dh wenn x gerade ist).

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
quelle
3

Python, 29 Bytes

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

Dies gibt 0 für gerade x zurück . Es verwendet den Satz von Euler mit der Beobachtung, dass 2 ^ n - 1 durch 2 ^ ( n - 1) - 1 durch die in Python eingebaute schnelle modulare Exponentiation teilbar ist. Dies ist schnell genug für n bis zu 7000 oder so, wo es mehr als eine Sekunde dauert.

Anders Kaseorg
quelle
2

Mathematica - 22

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

f[x,n]kehrt ymit x*y=1 mod 2^n, sonstx is not invertible modulo 2^n

Branislav
quelle
2

GolfScript (23 Zeichen)

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

Das Sentinel-Ergebnis für eine nicht vorhandene Inverse ist 0 .

Dies ist eine einfache Anwendung des Satzes von Euler . , also x - 1x 2 n - 1 - 1xφ(2n)1(mod2n)x1x2n11(mod2n)

Leider ist das eine zu große Exponentialgröße, um sie direkt berechnen zu können. Daher müssen wir eine Schleife verwenden und innerhalb der Schleife eine modulare Reduktion durchführen. Der iterative Schritt ist und wir haben die Wahl des Basisfalls: entweder mitx2k1=(x2k11)2×xk=1

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

oder k=2mit

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

Ich arbeite an einem anderen Ansatz, aber der Sentinel ist schwieriger.

Die Schlüsselbeobachtung ist, dass wir die Inverse Stück für Stück aufbauen können: wenn xy1(mod2k1)xy{1,1+2k1}(mod2k)xx(y+xy1)1(mod2k)y=(x+1)y-1

0x1(mod20)

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

x+1 ist.

Das gibt die 19-Zeichen-Funktion

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

xx&11

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

02n-1 , aber ich habe das noch nicht bewiesen.

01-(x+1)n1-1n

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

nn x f

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

Ruby - 88 Zeichen

Nutzen Sie die Funktion 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

Einfach die rekursive Funktion von der verknüpften Wiki-Seite gibt bei einem Fehler 0 zurück.

Nemo157
quelle
Sie können einige Zeichen speichern, indem Sie e: einfügen (e=->a,b{...})[x,2**n][0]. Kann auch ein Zeichen durch Testen a%b<1statt speichern a%b==0.
Histokrat
1

Haskell, 42 Bytes

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

Mit einem Algorithmus, der auf dem Lemma von Hensel basiert und die Anzahl der Stellen in jeder Iteration verdoppelt, läuft dies in weniger als einer Sekunde für n bis zu 30 Millionen !

Anders Kaseorg
quelle
1

Pyth , 9 Bytes

.^Et^2Q^2

Probieren Sie es hier aus!

Nimmt die Eingabe in umgekehrter Reihenfolge vor. Oder 9 Bytes zu: .^EtK^2QK.

Erläuterung

. ^ Et ^ 2Q ^ 2 - Volles Programm.

. ^ - Pow-Funktion. Das selbe in Python (pow).
  E - Die zweite Eingabe.
    ^ 2Q - und 2 ^ erste Eingabe.
   t - dekrementiert.
       ^ 2 - Und 2 ^ erstmal nochmal eingeben.
Mr. Xcoder
quelle
0

GAP, 39 Bytes

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

f(x,n)Gibt die Umkehrung von xModulo zurück 2^nund gibt eine Fehlermeldung aus

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

wenn keine Inverse existiert.

ahulpke
quelle