diff --git a/ipynb/Euler3.ipynb b/ipynb/Euler3.ipynb index 1c88980..4f9be45 100644 --- a/ipynb/Euler3.ipynb +++ b/ipynb/Euler3.ipynb @@ -156,7 +156,7 @@ { "data": { "text/plain": [ - "[11, 'out of', 11, 'tests pass']" + "[12, 'out of', 12, 'tests pass']" ] }, "execution_count": 4, @@ -173,11 +173,12 @@ " 6: 3, # composite\n", " 32: 2, # power of 2\n", " 49: 7, # square of a prime\n", - " 97: 97, # bigger prime\n", - " 99991: 99991, # even bigger prime\n", - " 97**9: 97, # even bigger power of a prime\n", " 360: 5, # test case for equations above\n", - " 600851475143: 6857 # Project Euler #3\n", + " 997: 997, # bigger prime\n", + " 997**9: 997, # bigger power of a prime\n", + " 99991: 99991, # even bigger prime\n", + " 600851475143: 6857, # Project Euler #3\n", + " 99999989: 99999989 # An 8-digit prime number\n", " }\n", " correct = sum(largest_prime_factor(n) == cases[n] for n in cases)\n", " return [correct, 'out of', len(cases), 'tests pass']\n", @@ -192,7 +193,7 @@ "source": [ "## Efficiency\n", "\n", - "How long does it take to get our answer? We can use `%time` to see it is just a few hundred microseconds (μs):" + "How long does it take to run all the test cases?" ] }, { @@ -205,14 +206,14 @@ "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 181 μs, sys: 0 ns, total: 181 μs\n", - "Wall time: 183 μs\n" + "CPU times: user 2.01 s, sys: 15 ms, total: 2.02 s\n", + "Wall time: 2.03 s\n" ] }, { "data": { "text/plain": [ - "6857" + "[12, 'out of', 12, 'tests pass']" ] }, "execution_count": 5, @@ -221,45 +222,7 @@ } ], "source": [ - "%time largest_prime_factor(600851475143)" - ] - }, - { - "cell_type": "markdown", - "id": "c8ead8e9-199f-47c6-ad76-360b1ebdaa02", - "metadata": {}, - "source": [ - "The algorithm is slowest when *n* is prime, because the `for` loop has to go all the way up to *n*. How long would it take for the largest 8-digit prime, 99,999,989?" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "7323d528-96d7-4c05-a05d-125e99605443", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 1.9 s, sys: 18.4 ms, total: 1.92 s\n", - "Wall time: 1.92 s\n" - ] - }, - { - "data": { - "text/plain": [ - "99999989" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "n8 = 99999989 # An 8-digit number that happens to be prime \n", - "%time largest_prime_factor(n8)" + "%time tests()" ] }, { @@ -269,14 +232,14 @@ "source": [ "About 2 seconds. Maybe that's good enough. But could we speed things up?\n", "\n", - "In trying to find a *p* that evenly divides *n*, the algorithm tests all the integers from 2 to *n*. But do we really have to test all those potential factors? No! Either *n* is prime, or it has two factors *p* and *q* such that *p* × *q* = *n*. Of those two factors, one must be less than or equal to the square root of *n*. So to determine if *n* has a prime factor other than itself, we only have to check integers up to √*n*, not all the way up to *n*. That's a big difference! for an 8-digit prime it is the difference between roughly 100 million steps versus a mere 10 thousand steps.\n", + "In trying to find a *p* that evenly divides *n*, the algorithm tests all the integers from 2 to *n*. But do we really have to test all those potential factors? No! Either *n* is prime, or it has two factors *p* and *q* such that *p* × *q* = *n*. Of those two factors, one must be less than or equal to the square root of *n*. So to determine if *n* has a prime factor other than itself, we only have to check integers up to √*n*, not all the way up to *n*. That's a big difference! For an 8-digit prime it is the difference between roughly 100 million steps versus a mere 10 thousand steps.\n", "\n", "Let's change the definition of `largest_prime_factor` to incorporate this new trick. (We will `import` the square root function, `sqrt`, from the `math` module.)" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 6, "id": "b90b5407-4666-4925-99d2-6a3a6b192fac", "metadata": {}, "outputs": [], @@ -294,46 +257,17 @@ " return n # n is prime or 1" ] }, - { - "cell_type": "markdown", - "id": "c39b08b9-06ed-49c0-a277-db248de909fd", - "metadata": {}, - "source": [ - "Any time you change a function, you should re-run the tests to give you some confidence that you didn't introduce a bug:" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "4026dc87-a0aa-4c75-b92a-96ec24cda1b7", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[11, 'out of', 11, 'tests pass']" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "tests()" - ] - }, { "cell_type": "markdown", "id": "6cddf393-a0fd-4cc2-9eef-3341339106bd", "metadata": {}, "source": [ - "Now we can see how fast the new function is on the 8-digit prime:" + "Now we can see how fast the new function is, and verify that it still passes all the tests:" ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 7, "id": "d3d0c13e-5c01-4112-b372-60f7eb302d25", "metadata": {}, "outputs": [ @@ -341,23 +275,23 @@ "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 196 μs, sys: 0 ns, total: 196 μs\n", - "Wall time: 196 μs\n" + "CPU times: user 523 μs, sys: 5 μs, total: 528 μs\n", + "Wall time: 548 μs\n" ] }, { "data": { "text/plain": [ - "99999989" + "[12, 'out of', 12, 'tests pass']" ] }, - "execution_count": 9, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "%time largest_prime_factor(n8)" + "%time tests()" ] }, { @@ -365,14 +299,14 @@ "id": "82b008ea-f6b5-4bcd-8768-09c8dab089cb", "metadata": {}, "source": [ - "As predicted, this is about 10,000 times faster.\n", + "This is thousands of times faster.\n", "\n", "We should be able to handle a 16-digit prime in about 2 seconds:" ] }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 8, "id": "9b6030ef-626a-4195-aedb-ef2edac65da4", "metadata": {}, "outputs": [ @@ -380,8 +314,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 1.96 s, sys: 19.3 ms, total: 1.97 s\n", - "Wall time: 1.97 s\n" + "CPU times: user 2.12 s, sys: 13 ms, total: 2.13 s\n", + "Wall time: 2.14 s\n" ] }, { @@ -390,7 +324,7 @@ "9927935178558959" ] }, - "execution_count": 10, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -414,17 +348,25 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 9, "id": "0308612c-6860-49b0-bcd6-856fa08133b1", "metadata": {}, "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 522 μs, sys: 1 μs, total: 523 μs\n", + "Wall time: 525 μs\n" + ] + }, { "data": { "text/plain": [ - "[11, 'out of', 11, 'tests pass']" + "[12, 'out of', 12, 'tests pass']" ] }, - "execution_count": 11, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -440,9 +382,10 @@ "\n", "def smallest_prime_factor(n):\n", " \"\"\"The smallest prime that evenly divides n (or n itself if no prime divisors).\"\"\"\n", - " return next((p for p in range(2, int(sqrt(n) + 1)) if n % p == 0), n)\n", + " divisors = (p for p in range(2, int(sqrt(n) + 1)) if n % p == 0)\n", + " return next(divisors, n)\n", "\n", - "tests()" + "%time tests()" ] }, { @@ -455,17 +398,25 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 10, "id": "b8907a8f-872f-4531-825c-fae9c70211c1", "metadata": {}, "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 490 μs, sys: 1 μs, total: 491 μs\n", + "Wall time: 492 μs\n" + ] + }, { "data": { "text/plain": [ - "[11, 'out of', 11, 'tests pass']" + "[12, 'out of', 12, 'tests pass']" ] }, - "execution_count": 12, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -485,15 +436,23 @@ " p = p + 1\n", " return max(n, largest)\n", " \n", - "tests()" + "%time tests()" ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4f44c6ec-7126-4bc8-9ce2-3fb23154791d", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "Python [conda env:base] *", "language": "python", - "name": "python3" + "name": "conda-base-py" }, "language_info": { "codemirror_mode": {