Browse Source

add discrete log

Olivier Marty 8 years ago
parent
commit
d761be7f27
5 changed files with 59 additions and 12 deletions
  1. 26 0
      code/DiscreteLog.cpp
  2. 20 0
      code/DiscreteLog_test.cpp
  3. 5 11
      code/Euclid.cpp
  4. 4 0
      code/Makefile
  5. 4 1
      main.tex

+ 26 - 0
code/DiscreteLog.cpp

@@ -0,0 +1,26 @@
+//return a^p (mod n)
+int pow_mod(int a, int p, int n){
+	if (p == 0) return 1;
+	int ans = pow_mod(a, p/2, n);
+	ans = (ans*ans) % n;
+	if (p % 2 == 1) ans = (ans*a) % n;
+	return ans;
+}
+// Baby-Step-Giant-Step Algorithm. O(n^(0.5)*logn)
+// solve a^x = b (mod n). Return -1 for non solution
+int log_mod(int a, int b, int n) {
+	int m, v, e = 1, i;
+	m = (int) sqrt(n + 0.5);
+	v = mod_inverse(pow_mod(a, m, n), n);
+	map <int , int > x;
+	x[1] = 0;
+	for (i = 1; i < m; i++) {
+		e = (e * a) % n;
+		if (!x.count(e)) x[e] = i;
+	}
+	for (i = 0; i < m; i++){
+		if (x.count(b)) return i*m + x[b];
+		b = (b * v) % n;
+	}
+	return -1;
+}

+ 20 - 0
code/DiscreteLog_test.cpp

@@ -0,0 +1,20 @@
+#include <bits/stdc++.h>
+using namespace std;
+
+typedef vector<int> VI;
+typedef pair<int, int> PII;
+
+#include "Euclid.cpp"
+#include "DiscreteLog.cpp"
+
+int main() {
+  srand(time(NULL));
+  assert(log_mod(407, 2891, 1459) == 276);
+  for(int t = 0; t < 100; t++) {
+    int a = rand()%5000;
+    int b = rand()%5000;
+    int n = rand()%5000;
+    int r = log_mod(a, b, n);
+    assert(r == -1 || pow_mod(a, r, n) == b%n);
+  }
+}

+ 5 - 11
code/Euclid.cc → code/Euclid.cpp

@@ -16,17 +16,11 @@ int gcd(int a, int b) {
 int lcm(int a, int b) {
   return a/gcd(a,b)*b;
 }
-// returns d = gcd(a,b); finds x,y such that d = ax + by
+// returns d = gcd(a,b); finds x,y such that d = ax + by,
+// with |x|+|y| minimal.
 int extended_euclid(int a, int b, int &x, int &y) {
-  int xx = y = 0;
-  int yy = x = 1;
-  while (b) {
-    int q = a/b;
-    int t = b; b = a%b; a = t;
-    t = xx; xx = x-q*xx; x = t;
-    t = yy; yy = y-q*yy; y = t;
-  }
-  return a;
+	if (!b) { x = 1; y = 0; return a; }
+	else { int d = extended_euclid(b, a%b, y, x); y -= x*(a/b); return d; }
 }
 // finds all solutions to ax = b (mod n)
 VI modular_linear_equation_solver(int a, int b, int n) {
@@ -79,7 +73,7 @@ void linear_diophantine(int a, int b, int c, int &x, int &y) {
     y = (c-a*x)/b;
   }
 }
-int main() {
+int test() {
   // expected: 2
   cout << gcd(14, 30) << endl;
   // expected: 2 -2 1

+ 4 - 0
code/Makefile

@@ -18,6 +18,10 @@ LongestIncreasingSubsequence2_test: LongestIncreasingSubsequence2_test.cpp Longe
 	@echo Compiling $@...
 	@$(CC) -o $@ $<
 
+DiscreteLog_test: DiscreteLog_test.cpp DiscreteLog.cpp Euclid.cpp
+	@echo Compiling $@...
+	@$(CC) -o $@ $<
+
 clean:
 	rm -f $(TEST_EXE)
 

+ 4 - 1
main.tex

@@ -107,7 +107,10 @@ Temps de cuisson : $O(n)$
 \section{Algorithmes numériques}
 
 \subsection{Number theoretic algorithms (modular, Chinese remainder, linear Diophantine)}
-{\scriptsize\lstinputlisting{code/Euclid.cc}}
+{\scriptsize\lstinputlisting{code/Euclid.cpp}}
+
+\subsection{Discrete Logarithm $O(\sqrt n\log n)$}
+{\scriptsize\lstinputlisting{code/DiscreteLog.cpp}}
 
 \subsection{Euler's function}
 {\scriptsize\lstinputlisting{code/Euler.cpp}}