diff --git a/ipython/EulerProblem058.ipynb b/ipython/EulerProblem058.ipynb index c68c6d0..322c1b5 100644 --- a/ipython/EulerProblem058.ipynb +++ b/ipython/EulerProblem058.ipynb @@ -33,7 +33,9 @@ { "cell_type": "code", "execution_count": 1, - "metadata": {}, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "def get_last_corner_value(side_length):\n", @@ -81,7 +83,7 @@ " return (base * expmod(base, exp - 1, m) % m)\n", " \n", "\n", - "def fermat_test(n):\n", + "def fermat_test_sicp(n):\n", " if n < 40:\n", " return n in [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 39]\n", " a = n - 3\n", @@ -145,10 +147,10 @@ " return False\n", " return trial_division(n)[0] == n\n", "\n", - "assert(fermat_test(3))\n", - "assert(fermat_test(107))\n", - "assert(fermat_test(108) == False)\n", - "assert(fermat_test(109))" + "assert(fermat_test_sicp(3))\n", + "assert(fermat_test_sicp(107))\n", + "assert(fermat_test_sicp(108) == False)\n", + "assert(fermat_test_sicp(109))" ] }, { @@ -210,44 +212,33 @@ }, { "cell_type": "code", - "execution_count": 5, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "import random\n", - "\n", - "def is_prime(n):\n", - " if n == 1:\n", - " return False\n", - " for _ in range(100):\n", - " a = n - random.randint(1, n - 1)\n", - " if not expmod(a, n, n) == a:\n", - " return False\n", - " return True\n", - "\n", - "assert(fermat_test(3))\n", - "assert(fermat_test(107))\n", - "assert(fermat_test(108) == False)\n", - "assert(fermat_test(109))" - ] - }, - { - "cell_type": "code", - "execution_count": 6, + "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "n: 26641 count_total: 53281 count_primes: 5328 ratio: 0.09999812315834913\n" + "n: 26641 count_total: 53281 count_primes: 5328 ratio: 0.09999812315834913\n", + "26641\n", + "Expected n is 26241.\n" ] } ], "source": [ - "s = get_solution()" + "import random\n", + "\n", + "def is_prime(n):\n", + " if n == 1:\n", + " return False\n", + " for _ in range(10):\n", + " a = n - random.randint(1, n - 1)\n", + " if not expmod(a, n, n) == a:\n", + " return False\n", + " return True\n", + "\n", + "print(get_solution())\n", + "print(\"Expected n is 26241.\")" ] }, { @@ -261,6 +252,65 @@ "Try this algorithm instead [https://en.wikipedia.org/wiki/Miller–Rabin_primality_test](https://en.wikipedia.org/wiki/Miller–Rabin_primality_test)." ] }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "n: 26241 count_total: 52481 count_primes: 5248 ratio: 0.09999809454850327\n", + "26241\n", + "For 561 sicp says True and real test says False.\n", + "For 1105 sicp says True and real test says False.\n", + "For 1729 sicp says True and real test says False.\n", + "For 2465 sicp says True and real test says False.\n", + "For 2821 sicp says True and real test says False.\n", + "For 6601 sicp says True and real test says False.\n" + ] + } + ], + "source": [ + "carmichael_number = [561, 1105, 1729, 2465, 2821, 6601]\n", + "\n", + "def little_fermat(a, p): # SICP uses this\n", + " return (a ** p) % p == a % p\n", + "\n", + "def little_fermat_simple(a, p): # Wikipedia uses this\n", + " assert(a < p)\n", + " return (a ** (p - 1)) % p == 1\n", + "\n", + "def expmod(base, exp, m):\n", + " if exp == 0:\n", + " return 1\n", + " if (exp % 2 == 0):\n", + " return (expmod(base, exp // 2, m) ** 2 % m)\n", + " return (base * expmod(base, exp - 1, m) % m)\n", + "\n", + "def fermat_test(n):\n", + " ps = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 39]\n", + " if n <= ps[-1]:\n", + " return n in ps\n", + " for a in ps:\n", + " #if not little_fermat_simple(a, n):\n", + " if expmod(a, n - 1, n) != 1:\n", + " #print(\"Fermat witness for {} is {}.\".format(n + 1, a))\n", + " return False\n", + " return True\n", + "\n", + "def is_prime(n):\n", + " return fermat_test(n)\n", + "\n", + "print(get_solution())\n", + "\n", + "for n in carmichael_number:\n", + " r_sicp = fermat_test_sicp(n)\n", + " r = fermat_test(n)\n", + " print(\"For {} sicp says {} and real test says {}.\".format(n, r_sicp, r))\n" + ] + }, { "cell_type": "code", "execution_count": null, diff --git a/ipython/html/EulerProblem058.html b/ipython/html/EulerProblem058.html index 063afb0..9b96e8b 100644 --- a/ipython/html/EulerProblem058.html +++ b/ipython/html/EulerProblem058.html @@ -11846,7 +11846,7 @@ div#notebook { return (base * expmod(base, exp - 1, m) % m) -def fermat_test(n): +def fermat_test_sicp(n): if n < 40: return n in [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 39] a = n - 3 @@ -11910,10 +11910,10 @@ div#notebook { return False return trial_division(n)[0] == n -assert(fermat_test(3)) -assert(fermat_test(107)) -assert(fermat_test(108) == False) -assert(fermat_test(109)) +assert(fermat_test_sicp(3)) +assert(fermat_test_sicp(107)) +assert(fermat_test_sicp(108) == False) +assert(fermat_test_sicp(109)) @@ -11989,7 +11989,7 @@ div#notebook {
import random
@@ -11997,27 +11997,14 @@ div#notebook {
def is_prime(n):
if n == 1:
return False
- for _ in range(100):
+ for _ in range(10):
a = n - random.randint(1, n - 1)
if not expmod(a, n, n) == a:
return False
return True
-assert(fermat_test(3))
-assert(fermat_test(107))
-assert(fermat_test(108) == False)
-assert(fermat_test(109))
-s = get_solution()
+print(get_solution())
+print("Expected n is 26241.")
carmichael_number = [561, 1105, 1729, 2465, 2821, 6601]
+
+def little_fermat(a, p): # SICP uses this
+ return (a ** p) % p == a % p
+
+def little_fermat_simple(a, p): # Wikipedia uses this
+ assert(a < p)
+ return (a ** (p - 1)) % p == 1
+
+def expmod(base, exp, m):
+ if exp == 0:
+ return 1
+ if (exp % 2 == 0):
+ return (expmod(base, exp // 2, m) ** 2 % m)
+ return (base * expmod(base, exp - 1, m) % m)
+
+def fermat_test(n):
+ ps = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 39]
+ if n <= ps[-1]:
+ return n in ps
+ for a in ps:
+ #if not little_fermat_simple(a, n):
+ if expmod(a, n - 1, n) != 1:
+ #print("Fermat witness for {} is {}.".format(n + 1, a))
+ return False
+ return True
+
+def is_prime(n):
+ return fermat_test(n)
+
+print(get_solution())
+
+for n in carmichael_number:
+ r_sicp = fermat_test_sicp(n)
+ r = fermat_test(n)
+ print("For {} sicp says {} and real test says {}.".format(n, r_sicp, r))
+