From 53fc34dd59ac20227ab096c57e2a493c41e4b9a5 Mon Sep 17 00:00:00 2001 From: Denis Smet Date: Fri, 20 Oct 2023 23:58:17 +0400 Subject: [PATCH] Exercise 1.23 --- src/sicp/chapter_1/part_2/ex_1_22.clj | 10 ++--- src/sicp/chapter_1/part_2/ex_1_23.clj | 43 +++++++++++++++++++++ test/sicp/chapter_1/part_2/ex_1_22_test.clj | 2 +- test/sicp/chapter_1/part_2/ex_1_23_test.clj | 40 +++++++++++++++++++ 4 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 src/sicp/chapter_1/part_2/ex_1_23.clj create mode 100644 test/sicp/chapter_1/part_2/ex_1_23_test.clj diff --git a/src/sicp/chapter_1/part_2/ex_1_22.clj b/src/sicp/chapter_1/part_2/ex_1_22.clj index 45a5a56..e7154a6 100644 --- a/src/sicp/chapter_1/part_2/ex_1_22.clj +++ b/src/sicp/chapter_1/part_2/ex_1_22.clj @@ -31,11 +31,11 @@ ; to the number of steps required for the computation? (defn find-primes - [from to] + [from to print-log] (cond (>= from to) (do - ; (println "finish") + (when print-log (println "finish")) from) - (even? from) (find-primes (+ from 1) to) ; Just skip to the next odd + (even? from) (find-primes (+ from 1) to print-log) ; Just skip to the next odd :else (do - ; (println from) - (find-primes (+ from 2) to)))) ; Takes only odds + (when print-log (println from)) + (find-primes (+ from 2) to print-log)))) ; Takes only odds diff --git a/src/sicp/chapter_1/part_2/ex_1_23.clj b/src/sicp/chapter_1/part_2/ex_1_23.clj new file mode 100644 index 0000000..c414718 --- /dev/null +++ b/src/sicp/chapter_1/part_2/ex_1_23.clj @@ -0,0 +1,43 @@ +(ns sicp.chapter-1.part_2.ex-1-23) + +; Exercise 1.23 +; The smallest-divisor procedure shown at the start of this section does lots of needless testing: +; After it checks to see if the number is divisible by 2 there is no point in checking to see +; if it is divisible by any larger even numbers. +; +; This suggests that the values used for test-divisor should not be 2, 3, 4, 5, 6, …, but rather 2, 3, 5, 7, 9, …. +; +; To implement this change, define a procedure next that returns 3 if its input is equal to 2 +; and otherwise returns its input plus 2. +; +; Modify the smallest-divisor procedure to use (next test-divisor) instead of (+ test-divisor 1). +; +; With timed-prime-test incorporating this modified version of smallest-divisor, +; run the test for each of the 12 primes found in Exercise 1.22. +; +; Since this modification halves the number of test steps, you should expect it to run about twice as fast. +; +; Is this expectation confirmed? If not, what is the observed ratio of the speeds of the two algorithms, +; and how do you explain the fact that it is different from 2? + +(defn next-odd + [x] + (if (= x 2) 3 (+ x 2))) + +(defn divides? + [a b] + (= (mod b a) 0)) + +(defn find-divisor + [num test-divisor] + (cond (> (* test-divisor test-divisor) num) num + (divides? test-divisor num) test-divisor + :else (find-divisor num (next-odd test-divisor)))) + +(defn smallest-divisor + [num] + (find-divisor num 2)) + +(defn prime? + [n] + (= n (smallest-divisor n))) diff --git a/test/sicp/chapter_1/part_2/ex_1_22_test.clj b/test/sicp/chapter_1/part_2/ex_1_22_test.clj index 7d6c669..539d0e0 100644 --- a/test/sicp/chapter_1/part_2/ex_1_22_test.clj +++ b/test/sicp/chapter_1/part_2/ex_1_22_test.clj @@ -3,4 +3,4 @@ [sicp.chapter-1.part_2.ex-1-22 :refer [find-primes]])) (deftest find-primes-test - (is (= 5 (find-primes 1 5)))) ; Change arguments and see the output + (is (= 5 (find-primes 1 5 false)))) ; Change arguments and see the output diff --git a/test/sicp/chapter_1/part_2/ex_1_23_test.clj b/test/sicp/chapter_1/part_2/ex_1_23_test.clj new file mode 100644 index 0000000..c254864 --- /dev/null +++ b/test/sicp/chapter_1/part_2/ex_1_23_test.clj @@ -0,0 +1,40 @@ +(ns sicp.chapter-1.part_2.ex-1-23-test + (:require [clojure.test :refer [deftest is]] + [sicp.chapter-1.part_2.ex-1-23 :refer [find-divisor next-odd prime? smallest-divisor]])) + +(deftest next-odd-test + (is (= 3 (next-odd 1))) + (is (= 3 (next-odd 2))) + (is (= 5 (next-odd 3))) + (is (= 6 (next-odd 4))) + (is (= 7 (next-odd 5)))) + +(deftest smallest-divisor-test + (is (= 2 (smallest-divisor 2))) + (is (= 3 (smallest-divisor 3))) + (is (= 2 (smallest-divisor 6))) + (is (= 2 (smallest-divisor 30))) + (is (= 11 (smallest-divisor 11))) + (is (= 31 (smallest-divisor 31)))) + +(deftest find-divisor-test + (is (= 2 (find-divisor 2 4))) + (is (= 5 (find-divisor 5 35))) + (is (= 7 (find-divisor 7 35))) + (is (= 100 (find-divisor 100 100))) + (is (= 10 (find-divisor 10 100)))) + +(deftest prime?-test + ; Prime + (is (= true (prime? 1))) + (is (= true (prime? 2))) + (is (= true (prime? 3))) + (is (= true (prime? 5))) + (is (= true (prime? 7))) + (is (= true (prime? 11))) + (is (= true (prime? 23))) + ; Not prime + (is (= false (prime? 4))) + (is (= false (prime? 6))) + (is (= false (prime? 8))) + (is (= false (prime? 20))))