Der Devx-Link ist nicht sehr nützlich, es gibt andere einfache Methoden in der Zahlentheorie für solche Dinge, AFAIK.
Priyank Bolia
1
@Priyank Bolia: Keine Sorge, es ist unwahrscheinlich, dass diese Frage geschlossen wird. Das ist eine gute Frage. Wenn es geschlossen ist, werden viele Leute für die Wiedereröffnung stimmen.
Jason
4
Ja, viele von uns sind sich bewusst, dass Informatik manchmal Mathematik beinhaltet.
Cascabel
13
@JB King: MathOverflow ist für Mathematik auf Hochschulniveau und höher; Diese Frage würde dort verpönt sein.
Jason
Antworten:
100
Okay, du willst also rechnen a^b mod m. Zuerst werden wir einen naiven Ansatz verfolgen und dann sehen, wie wir ihn verfeinern können.
Reduzieren Sie zunächst a mod m. Das heißt, finden Sie eine Nummer, a1damit 0 <= a1 < mund a = a1 mod m. Dann wiederholt in einer Schleife mit multiplizieren a1und wieder reduzieren mod m. Also im Pseudocode:
a1 = a reduced mod m
p = 1
for(int i = 1; i <= b; i++) {
p *= a1
p = p reduced mod m
}
Auf diese Weise vermeiden wir Zahlen, die größer als sind m^2. Das ist der Schlüssel. Der Grund, warum wir Zahlen vermeiden, die größer sind als, m^2ist, dass bei jedem Schritt 0 <= p < mund 0 <= a1 < m.
Als Beispiel berechnen wir 5^55 mod 221. Erstens 5ist bereits reduziert mod 221.
1 * 5 = 5 mod 221
5 * 5 = 25 mod 221
25 * 5 = 125 mod 221
125 * 5 = 183 mod 221
183 * 5 = 31 mod 221
31 * 5 = 155 mod 221
155 * 5 = 112 mod 221
112 * 5 = 118 mod 221
118 * 5 = 148 mod 221
148 * 5 = 77 mod 221
77 * 5 = 164 mod 221
164 * 5 = 157 mod 221
157 * 5 = 122 mod 221
122 * 5 = 168 mod 221
168 * 5 = 177 mod 221
177 * 5 = 1 mod 221
1 * 5 = 5 mod 221
5 * 5 = 25 mod 221
25 * 5 = 125 mod 221
125 * 5 = 183 mod 221
183 * 5 = 31 mod 221
31 * 5 = 155 mod 221
155 * 5 = 112 mod 221
112 * 5 = 118 mod 221
118 * 5 = 148 mod 221
148 * 5 = 77 mod 221
77 * 5 = 164 mod 221
164 * 5 = 157 mod 221
157 * 5 = 122 mod 221
122 * 5 = 168 mod 221
168 * 5 = 177 mod 221
177 * 5 = 1 mod 221
1 * 5 = 5 mod 221
5 * 5 = 25 mod 221
25 * 5 = 125 mod 221
125 * 5 = 183 mod 221
183 * 5 = 31 mod 221
31 * 5 = 155 mod 221
155 * 5 = 112 mod 221
112 * 5 = 118 mod 221
118 * 5 = 148 mod 221
148 * 5 = 77 mod 221
77 * 5 = 164 mod 221
164 * 5 = 157 mod 221
157 * 5 = 122 mod 221
122 * 5 = 168 mod 221
168 * 5 = 177 mod 221
177 * 5 = 1 mod 221
1 * 5 = 5 mod 221
5 * 5 = 25 mod 221
25 * 5 = 125 mod 221
125 * 5 = 183 mod 221
183 * 5 = 31 mod 221
31 * 5 = 155 mod 221
155 * 5 = 112 mod 221
Daher 5^55 = 112 mod 221.
Jetzt können wir dies verbessern, indem wir die Potenzierung durch Quadrieren verwenden . Dies ist der berühmte Trick, bei dem wir die Potenzierung so reduzieren, dass statt nur log bMultiplikationen erforderlich sind b. Beachten Sie, dass Sie mit dem oben beschriebenen Algorithmus, der Potenzierung durch Quadrierverbesserung, die Binärmethode von rechts nach links erhalten .
a1 = a reduced mod m
p = 1
while (b > 0) {
if (b is odd) {
p *= a1
p = p reduced mod m
}
b /= 2
a1 = (a1 * a1) reduced mod m
}
Somit ist da 55 = 110111 binär
1 * (5^1 mod 221) = 5 mod 221
5 * (5^2 mod 221) = 125 mod 221
125 * (5^4 mod 221) = 112 mod 221
112 * (5^16 mod 221) = 112 mod 221
112 * (5^32 mod 221) = 112 mod 221
Daher lautet die Antwort 5^55 = 112 mod 221. Der Grund, warum dies funktioniert, ist, weil
55 = 1 + 2 + 4 + 16 + 32
damit
5^55 = 5^(1 + 2 + 4 + 16 + 32) mod 221
= 5^1 * 5^2 * 5^4 * 5^16 * 5^32 mod 221
= 5 * 25 * 183 * 1 * 1 mod 221
= 22875 mod 221
= 112 mod 221
In dem Schritt, in dem wir usw. berechnen 5^1 mod 221, stellen 5^2 mod 221wir fest, dass 5^(2^k)= 5^(2^(k-1)) * 5^(2^(k-1))weil, 2^k = 2^(k-1) + 2^(k-1)damit wir zuerst berechnen 5^1und reduzieren können mod 221, dies dann quadrieren und reduzieren mod 221, um 5^2 mod 221usw. zu erhalten .
Nun, die meisten Programmiersprachen haben dafür einen eingebauten Operator. In C-abgeleiteten Sprachen ist der %Operator beispielsweise der Moduloperator. Somit int p = 625 % 221würde zuweisen 183zu p. Sie können dieselbe Funktionalität erreichen, indem Sie 625durch 221eine Ganzzahldivision dividieren und die Antwort erhalten 2. Dann nimmst du, 625 - 2 * 221um den Rest zu bekommen. In diesem Fall 625 - 2 * 221 = 183ist das die Antwort.
Jason
2
Ja, wie ich im Abschnitt am Ende beschrieben habe, potenzieren Sie durch Quadrieren.
Jason
6
Sie können tatsächlich viel besser als die Potenzierung durch Quadrieren tun, insbesondere im Fall eines großen Exponenten. Beachten Sie, dass Sie das gefunden haben 5^16 == 1 (mod 221). Daher 5^k == 5^(k%16) (mod 221).
Cascabel
2
@ Jason: Du hast geschrieben: Reduziere zuerst einen Mod m. Das heißt, finden Sie eine Zahl a1, so dass 0 <= a1 <m und a = a1 mod m. Es sieht so aus, als ob die letzte Gleichung einen Tippfehler enthält. Sollte es nicht stattdessen a1 = a mod m sein ?
Timofey
2
@ Jason zum größten Teil, wenn Sie gerade ";" (und ein paar andere Zeichen) zu Ihrem Pseudocode wäre es C.
haneefmubarak
28
Um Jasons Antwort zu ergänzen:
Sie können den Prozess beschleunigen (was für sehr große Exponenten hilfreich sein kann), indem Sie die binäre Erweiterung des Exponenten verwenden. Berechnen Sie zuerst 5, 5 ^ 2, 5 ^ 4, 5 ^ 8 mod 221 - Sie tun dies durch wiederholtes Quadrieren:
Sie können sehen, dass dies für sehr große Exponenten viel schneller sein wird (ich glaube, es ist log im Gegensatz zu linear in b, aber nicht sicher.)
Ich vermute, dass es tatsächlich (im Allgemeinen) viel schneller ist, die Exponentiation durch Quadrieren zu vermeiden und stattdessen direkt nach dem kleinsten Exponenten $ k $ zu suchen, so dass $ 5 ^ k == 5 (mod 221) $. Dies hängt natürlich von der Größe des Exponenten gegenüber dem Modul ab, aber sobald Sie diesen Exponenten haben, benötigen Sie nur eine einzige Berechnung (Exponentenmod k) und eine Suche. Beachten Sie daher, dass es auch definitiv besser ist, wenn Sie ähnliche Berechnungen wiederholen müssen. (Sie können im Allgemeinen nicht nach $ a ^ k == 1 (mod 221) $ suchen, da dies nur passiert, wenn $ a $ und 221 relativ prim sind)
Cascabel
1
Nun, nein, im Allgemeinen ist das Finden des kleinsten Exponenten mit dieser Eigenschaft viel langsamer als das Quadrieren und Multiplizieren. Wenn Sie jedoch die Faktorisierung des Moduls kennen, können Sie leicht die Carmichael-Lambda-Funktion berechnen, die ein Vielfaches Ihres k ist.
Präsident James K. Polk
12
/* The algorithm is from the book "Discrete Mathematics and Its
Applications 5th Edition" by Kenneth H. Rosen.
(base^exp)%mod
*/
int modular(int base, unsigned int exp, unsigned int mod)
{
int x = 1;
int power = base % mod;
for (int i = 0; i < sizeof(int) * 8; i++) {
int least_sig_bit = 0x00000001 & (exp >> i);
if (least_sig_bit)
x = (x * power) % mod;
power = (power * power) % mod;
}
return x;
}
Der chinesische Restsatz kommt als Anfangspunkt in den Sinn: 221 = 13 * 17. Teilen Sie dies also in zwei Teile auf, die am Ende kombiniert werden, einen für Mod 13 und einen für Mod 17. Zweitens glaube ich, dass es einige Beweise gibt von a ^ (p-1) = 1 mod p für alle ungleich Null a, was auch dazu beiträgt, Ihr Problem zu reduzieren, da 5 ^ 55 für den Fall mod 13 zu 5 ^ 3 wird, da 13 * 4 = 52. Wenn Sie unter dem Thema "Endliche Felder" nachsehen, finden Sie möglicherweise einige gute Ergebnisse zur Lösung dieses Problems.
EDIT: Der Grund, warum ich die Faktoren erwähne, ist, dass dies eine Möglichkeit schafft, Null in Nicht-Null-Elemente zu zerlegen, als ob Sie etwas wie 13 ^ 2 * 17 ^ 4 mod 221 ausprobiert hätten. Die Antwort ist Null, da 13 * 17 = 221. Viele große Zahlen werden keine Primzahlen sein, obwohl es Möglichkeiten gibt, große Primzahlen zu finden, da sie in der Kryptographie und anderen Bereichen der Mathematik häufig verwendet werden.
Nun, ich kenne die Fakultäten überhaupt nicht und versuche mit dem Miller-Rabin-Algorithmus zu beweisen, dass die Zahl eine Primzahl ist. Ich bin also am anderen Ende.
Priyank Bolia
Hier gibt es keine Fakultäten, aber es gibt eine andere Faktorisierung. Die Fakultät einer ganzen Zahl n ist definiert als das Produkt aller positiven ganzen Zahlen kleiner als n, z. B. 2! = 2, 3! = 6 usw. und wird häufig mit! Symbol. Die Faktorisierung ist anders und es gibt kein gemeinsames Symbol, das verwendet wird, um eine Ganzzahl auszudrücken, die faktorisiert wird.
JB King
2
Dies ist Teil des Codes, den ich für die IBAN-Validierung erstellt habe. Fühlen Sie sich frei zu benutzen.
static void Main(string[] args)
{
int modulo = 97;
string input = Reverse("100020778788920323232343433");
int result = 0;
int lastRowValue = 1;
for (int i = 0; i < input.Length; i++)
{
// Calculating the modulus of a large number Wikipedia http://en.wikipedia.org/wiki/International_Bank_Account_Number
if (i > 0)
{
lastRowValue = ModuloByDigits(lastRowValue, modulo);
}
result += lastRowValue * int.Parse(input[i].ToString());
}
result = result % modulo;
Console.WriteLine(string.Format("Result: {0}", result));
}
public static int ModuloByDigits(int previousValue, int modulo)
{
// Calculating the modulus of a large number Wikipedia http://en.wikipedia.org/wiki/International_Bank_Account_Number
return ((previousValue * 10) % modulo);
}
public static string Reverse(string input)
{
char[] arr = input.ToCharArray();
Array.Reverse(arr);
return new string(arr);
}
Anstatt 19 direkt mit Strom zu versorgen, können Sie Folgendes tun:
(((19 mod 7) * 19) mod 7) * 19) mod 7
Dies kann jedoch aufgrund vieler sequentieller Multiplikationen auch lange dauern, sodass Sie mit quadratischen Werten multiplizieren können:
x mod N -> x ^ 2 mod N -> x ^ 4 mod -> ... x ^ 2 |log y| mod N
Der modulare Exponentiationsalgorithmus geht davon aus, dass:
x ^ y == (x ^ |y/2|) ^ 2 if y is even
x ^ y == x * ((x ^ |y/2|) ^ 2) if y is odd
Und so sieht der rekursive modulare Exponentiationsalgorithmus in Java folgendermaßen aus:
/**
* Modular exponentiation algorithm
* @param x Assumption: x >= 0
* @param y Assumption: y >= 0
* @param N Assumption: N > 0
* @return x ^ y mod N
*/
public static long modExp(long x, long y, long N) {
if(y == 0)
return 1 % N;
long z = modExp(x, Math.abs(y/2), N);
if(y % 2 == 0)
return (long) ((Math.pow(z, 2)) % N);
return (long) ((x * Math.pow(z, 2)) % N);
}
Besonderer Dank geht an @chux für den gefundenen Fehler mit falschem Rückgabewert beim Vergleich von y und 0.
Vielen Dank für Ihr Feedback. Können Sie bitte Eingabedaten angeben, die zu einer falschen Ausgabe führen?
Stepan Pogosyan
1
Vielen Dank für den gefundenen Fehler. Ich habe auf 1% N korrigiert.
Stepan Pogosyan
0
Geben Sie einfach eine weitere Implementierung von Jasons Antwort von C.
Nachdem ich mit meinen Klassenkameraden diskutiert habe, basierend auf Jasons Erklärung, mag ich die rekursive Version mehr, wenn Sie sich nicht sehr für die Leistung interessieren:
Zum Beispiel:
#include<stdio.h>
int mypow( int base, int pow, int mod ){
if( pow == 0 ) return 1;
if( pow % 2 == 0 ){
int tmp = mypow( base, pow >> 1, mod );
return tmp * tmp % mod;
}
else{
return base * mypow( base, pow - 1, mod ) % mod;
}
}
int main(){
printf("%d", mypow(5,55,221));
return 0;
}
Antworten:
Okay, du willst also rechnen
a^b mod m
. Zuerst werden wir einen naiven Ansatz verfolgen und dann sehen, wie wir ihn verfeinern können.Reduzieren Sie zunächst
a mod m
. Das heißt, finden Sie eine Nummer,a1
damit0 <= a1 < m
unda = a1 mod m
. Dann wiederholt in einer Schleife mit multiplizierena1
und wieder reduzierenmod m
. Also im Pseudocode:Auf diese Weise vermeiden wir Zahlen, die größer als sind
m^2
. Das ist der Schlüssel. Der Grund, warum wir Zahlen vermeiden, die größer sind als,m^2
ist, dass bei jedem Schritt0 <= p < m
und0 <= a1 < m
.Als Beispiel berechnen wir
5^55 mod 221
. Erstens5
ist bereits reduziertmod 221
.1 * 5 = 5 mod 221
5 * 5 = 25 mod 221
25 * 5 = 125 mod 221
125 * 5 = 183 mod 221
183 * 5 = 31 mod 221
31 * 5 = 155 mod 221
155 * 5 = 112 mod 221
112 * 5 = 118 mod 221
118 * 5 = 148 mod 221
148 * 5 = 77 mod 221
77 * 5 = 164 mod 221
164 * 5 = 157 mod 221
157 * 5 = 122 mod 221
122 * 5 = 168 mod 221
168 * 5 = 177 mod 221
177 * 5 = 1 mod 221
1 * 5 = 5 mod 221
5 * 5 = 25 mod 221
25 * 5 = 125 mod 221
125 * 5 = 183 mod 221
183 * 5 = 31 mod 221
31 * 5 = 155 mod 221
155 * 5 = 112 mod 221
112 * 5 = 118 mod 221
118 * 5 = 148 mod 221
148 * 5 = 77 mod 221
77 * 5 = 164 mod 221
164 * 5 = 157 mod 221
157 * 5 = 122 mod 221
122 * 5 = 168 mod 221
168 * 5 = 177 mod 221
177 * 5 = 1 mod 221
1 * 5 = 5 mod 221
5 * 5 = 25 mod 221
25 * 5 = 125 mod 221
125 * 5 = 183 mod 221
183 * 5 = 31 mod 221
31 * 5 = 155 mod 221
155 * 5 = 112 mod 221
112 * 5 = 118 mod 221
118 * 5 = 148 mod 221
148 * 5 = 77 mod 221
77 * 5 = 164 mod 221
164 * 5 = 157 mod 221
157 * 5 = 122 mod 221
122 * 5 = 168 mod 221
168 * 5 = 177 mod 221
177 * 5 = 1 mod 221
1 * 5 = 5 mod 221
5 * 5 = 25 mod 221
25 * 5 = 125 mod 221
125 * 5 = 183 mod 221
183 * 5 = 31 mod 221
31 * 5 = 155 mod 221
155 * 5 = 112 mod 221
Daher
5^55 = 112 mod 221
.Jetzt können wir dies verbessern, indem wir die Potenzierung durch Quadrieren verwenden . Dies ist der berühmte Trick, bei dem wir die Potenzierung so reduzieren, dass statt nur
log b
Multiplikationen erforderlich sindb
. Beachten Sie, dass Sie mit dem oben beschriebenen Algorithmus, der Potenzierung durch Quadrierverbesserung, die Binärmethode von rechts nach links erhalten .Somit ist da 55 = 110111 binär
1 * (5^1 mod 221) = 5 mod 221
5 * (5^2 mod 221) = 125 mod 221
125 * (5^4 mod 221) = 112 mod 221
112 * (5^16 mod 221) = 112 mod 221
112 * (5^32 mod 221) = 112 mod 221
Daher lautet die Antwort
5^55 = 112 mod 221
. Der Grund, warum dies funktioniert, ist, weildamit
In dem Schritt, in dem wir usw. berechnen
5^1 mod 221
, stellen5^2 mod 221
wir fest, dass5^(2^k)
=5^(2^(k-1)) * 5^(2^(k-1))
weil,2^k = 2^(k-1) + 2^(k-1)
damit wir zuerst berechnen5^1
und reduzieren könnenmod 221
, dies dann quadrieren und reduzierenmod 221
, um5^2 mod 221
usw. zu erhalten .Der obige Algorithmus formalisiert diese Idee.
quelle
%
Operator beispielsweise der Moduloperator. Somitint p = 625 % 221
würde zuweisen183
zup
. Sie können dieselbe Funktionalität erreichen, indem Sie625
durch221
eine Ganzzahldivision dividieren und die Antwort erhalten2
. Dann nimmst du,625 - 2 * 221
um den Rest zu bekommen. In diesem Fall625 - 2 * 221 = 183
ist das die Antwort.5^16 == 1 (mod 221)
. Daher5^k == 5^(k%16) (mod 221)
.Um Jasons Antwort zu ergänzen:
Sie können den Prozess beschleunigen (was für sehr große Exponenten hilfreich sein kann), indem Sie die binäre Erweiterung des Exponenten verwenden. Berechnen Sie zuerst 5, 5 ^ 2, 5 ^ 4, 5 ^ 8 mod 221 - Sie tun dies durch wiederholtes Quadrieren:
Jetzt können wir schreiben
Sie können sehen, dass dies für sehr große Exponenten viel schneller sein wird (ich glaube, es ist log im Gegensatz zu linear in b, aber nicht sicher.)
quelle
quelle
x * power
undpower * power
unterliegen einem Überlauf, wennmod*mod > UINT_MAX + 1
.x * power
, um OF zu vermeiden. Falls keine verfügbar sind , können Code verwenden diese .quelle
Was Sie suchen, ist modulare Exponentiation, insbesondere modulare binäre Exponentiation. Dieser Wikipedia-Link hat einen Pseudocode.
quelle
Der chinesische Restsatz kommt als Anfangspunkt in den Sinn: 221 = 13 * 17. Teilen Sie dies also in zwei Teile auf, die am Ende kombiniert werden, einen für Mod 13 und einen für Mod 17. Zweitens glaube ich, dass es einige Beweise gibt von a ^ (p-1) = 1 mod p für alle ungleich Null a, was auch dazu beiträgt, Ihr Problem zu reduzieren, da 5 ^ 55 für den Fall mod 13 zu 5 ^ 3 wird, da 13 * 4 = 52. Wenn Sie unter dem Thema "Endliche Felder" nachsehen, finden Sie möglicherweise einige gute Ergebnisse zur Lösung dieses Problems.
EDIT: Der Grund, warum ich die Faktoren erwähne, ist, dass dies eine Möglichkeit schafft, Null in Nicht-Null-Elemente zu zerlegen, als ob Sie etwas wie 13 ^ 2 * 17 ^ 4 mod 221 ausprobiert hätten. Die Antwort ist Null, da 13 * 17 = 221. Viele große Zahlen werden keine Primzahlen sein, obwohl es Möglichkeiten gibt, große Primzahlen zu finden, da sie in der Kryptographie und anderen Bereichen der Mathematik häufig verwendet werden.
quelle
Dies ist Teil des Codes, den ich für die IBAN-Validierung erstellt habe. Fühlen Sie sich frei zu benutzen.
quelle
Jasons Antwort in Java (Anmerkung
i < exp
).quelle
Dies wird als modulare Exponentiation bezeichnet ( https://en.wikipedia.org/wiki/Modular_exponentiation ).
Nehmen wir an, Sie haben den folgenden Ausdruck:
Anstatt 19 direkt mit Strom zu versorgen, können Sie Folgendes tun:
Dies kann jedoch aufgrund vieler sequentieller Multiplikationen auch lange dauern, sodass Sie mit quadratischen Werten multiplizieren können:
Der modulare Exponentiationsalgorithmus geht davon aus, dass:
Und so sieht der rekursive modulare Exponentiationsalgorithmus in Java folgendermaßen aus:
Besonderer Dank geht an @chux für den gefundenen Fehler mit falschem Rückgabewert beim Vergleich von y und 0.
quelle
Geben Sie einfach eine weitere Implementierung von Jasons Antwort von C.
Nachdem ich mit meinen Klassenkameraden diskutiert habe, basierend auf Jasons Erklärung, mag ich die rekursive Version mehr, wenn Sie sich nicht sehr für die Leistung interessieren:
Zum Beispiel:
quelle