【SICP练习】8 练习1.21-1.28

练习1.21

这道题几乎没有难度,除非在把书中函数写入到Edwin中时输入错误。

(smallest-divisor 199)

;Value: 199

(smallest-divisor 1999)

;Value: 1999

(smallest-divisor 19999)

;Value: 19999

练习1.22

这道题中需要判断素数的部分书中都已经列出来了,但要求是要找出多个素数,因此我们要有一个能够不断求素数的函数。在C等语言中我们可以通过一个for循环来轻易地求出来,在Scheme中我们完全可以用迭代来实现这一功能。另外因为是要的素数,因此完全不用考虑偶数了。于是我们先来写一个不断求奇数的函数。

(define (odd-after-x x)

(if (odd? x)

(+ 2 x)

(+ 1 x)))

通过将偶数加1、奇数加2,轻易地求出了x之后的奇数。

判断素数的函数我们直接列出了:

(define (prime? n)

(define (smallest-divisor n)

(find-divisor n 2))

(define (find-divisor n test-divisor)

(cond ((> (square test-divisor) n) n)

((divides? test-divisor n) test-divisor)

(else (find-divisor n (+ test-divisor 1)))))

(define (divides? a b)

(= (remainder b a) 0))

(= n (smallest-divisor n)))

下面我们利用这两个函数来定义一个不断产生素数的函数:

(define (prime-after-prime n count)

(cond ((= count 0) (display “These are all prime numbers”))

((prime? n) (display n)

(newline)

(prime-after-prime (odd-after-x n) (- count 1)))

(else (prime-after-prime (odd-after-x n) count))))

如此一来便能够按照书中的要求算出一千、一万等的3个最小的素数了,不过还不能计算所需时间。而要求时间,我们可以用real-time-clock,这在【Scheme归纳】7中有相关介绍。下面我们就来将计算时间的功能加入进去。

(define (get-time&prime n)

(let ((start-time (real-time-clock)))

(prime-after-prime n 3)        由于题目中只要求求出3个最小的素数即可。

(- (real-time-clock) start-time)))

下面我们就来开始测试了:

(get-time&prime 1000)

1009

1013

1019

These are all prime numbers

;Value: 0

时间太短记为0了我也没办法,下面再来几组大的。

(get-time&prime 10000)

10007

10009

10037

These are all prime numbers

;Value: 0

还是0,莫非函数错了?再来一次。

(get-time&prime 100000)

100003

100019

100043

These are all prime numbers

;Value: 0

我也不知道为什么会这样了,用一百万测试的还是0,难度是i7的速度快?不过:

(get-time&prime 10000000)

10000019

10000079

10000103

These are all prime numbers

;Value: 15

继续,一亿用了47微秒,10亿用了157微秒。100亿、一千亿、一万亿用了672、1750、5156。一亿亿用了621890秒,3个最小的素数分别是10000000000000061、10000000000000069、10000000000000079。

后来在网上也看到相同的函数,而对方评论下说对方写错了。我再看看书中的内容发现果然如此,我也看错了,第36页上面说的是检查每个素数所需要的时间,应该是意味着每个素数都要有个时间吧?如是将函数改成了这样:

(define (get-time&prime n)

(let ((start-time (real-time-clock)))

(define (prime-after-prime n count)

(cond ((= count 0) (display "These are all prime numbers."))

((prime? n) (display n)

(display (- (real-time-clock) start-time))

(newline)

(prime-after-prime (odd-after-x n) (- count 1)))

(else (prime-after-prime (odd-after-x n) count)))))

(prime-after-prime n 3)))

因为觉得返回更多的素数结果会更加准确,于是我在测试的时候将最后一行代码的3改成了5。通过测试,在1000和10000中的每个素数的计算时间都是0。10万和100万也都是零。我觉得是因为这本书的历史比较久远了,当时的硬件比不上现在的了。于是我又用了一千万来测试,返回的5个时间分别是0、15、15、15、31,用一亿来测试返回的5个时间分别是15、31、47、62、78,和根号10的差距不是太遥远吧。十亿返回的5个时间分别是47、94、141、297、391。至此这道习题就算做完了,稍有不足都请读者列出。

练习1.23

首先我们按照题目要求来写出相应的next函数,然后再修改find-divisor函数。

(define (next x)

(if (= x 2)

3

(+ n 2)))

(define(find-divisor n test-divisor)

(cond ((> (square test-divisor) n) n)

((divides? test-divisor n) test-divisor)

(else (find-divisor n (next test-divisor)))))

然后重新编译之前写好的get-time&prime函数,再加以测试这道题就算完成了。

练习1.24

我们先将书中已给出的代码写入Edwin中。

(define (fermat-test n)

(define (try-it a)

(= (expmod a n n) a))

(try-it (+ 1 (random (- n 1)))))

(define (fast-prime? n times)

(cond ((= times 0) true)

((fermat-test n) (fast-prime? n (- times 1)))

(else false)))

(define (expmod base exp m)

(cond ((= exp 0) 1)

((even? exp) (remainder (square (expmod base (/ exp 2) m)) m))

(else (remainder (* base (expmod base (- exp 1) m)) m))))

于是就有了一个新的prime?函数如下:

(define (prime? n)

(fast-prime? n 100))

然后载入上一题中的get-time&prime函数,如果已经在上一题中保存了起来现在就可以直接load了。然后经过一番测试后,结论很明显咯。练习1.22中的get-time&prime函数的复杂度为Θ(√n),而本题中的复杂度为Θ(logn) 。

练习1.25

这道题由Alyssa的一个另一版本的expmod来引出,这个expmod的功能和之前的一样的。但是之前版本的expmod每次都有一个remainder来讲乘幂控制在一个不大的范围内,这样通过不断的迭代,将很大的数字分解开来得以加快计算速度。而题目中这一版本的expmod则只通过了一次remainder。大家可以用2个非常大的数字来测试一番,比如几百亿之类的。

练习1.26

这本书的练习好像很多都和某个人有关,不愧是一本经典著作,通过MIT大量的修修补补。下面我们进入正题吧,Louis的问题就在于计算了2次(expmod base (/ exp 2) m),如果是用的square,则只会计算一次。更何况在这多余的一次里,又是一个漫长的迭代。Lisp最吸引我的就是它的精巧优美了,能短则短吧。

练习1.27

这道题的场景是在注释47中,博主更关心的问题是:(第三行)撞上能欺骗费马检查的值的概率有多少,居然会比什么宇宙射线造成计算机出差。后者个人感觉是永远不会发生的,前者倒是还有可能发生。希望把前者的概率算出来的童鞋将过程列出来啦!

言归正传,题目的意思就是要去验算注释47中的那几个Carmichael,那就来code吧:

(define (find-carmichael n)

(define (find-carmichael-test x n)

(cond ((= x n) #t)

((same-remainder? x n)

(find-carmichael-test (+ x 1) n))

((else #f)))

(define (same-remainder? x n)

(= (expmod x n n) x))

(find-carmichael-test 1 n))

当然了,这里要load保存好的expmod函数。然后就是测试了:

(carmichael-test 6601)

;Value: #t

其他的都一样的返回结果,不然就是函数写错了。

练习1.28

这道题主要分为三个部分:

1、非平凡平方根,并添加到expmod函数中

2、类似于fermat-test的过程

3、通过已知的素数和非素数来检验

下面我们首先来写出能够在遇到非平凡平方根的时候报错的函数,在这个函数中:当x不等于1,x不等于(n-1),并且x的平方对n取余等于1,这三个条件都为真时则可以说遇到了“1取模n的非平凡平方根”。下面是该函数:

(define (not-square-root? x n)

(and (not (= x 1))

(not (= x (- n 1)))

(= 1 (remainder (square x) n))))

然后我们要将这个函数添加到expmod中,在cond里面添加一项即可:

(define (expmod base exp m)

(cond ((= exp 0) 1)

((not-square-root? base m) 0)

((even? exp)

(remainder (square (expmod base (/ exp 2) m)) m))

(else (remainder (* base (expmod base (- exp 1) m)) m))))

第一步我们已经完成了,下面来看看第二步。在fermat-test中,已经有了一个try-it函数,但这个函数在这道题里不适用,因此我们来自己写一个产生随机数的函数。这个函数用来生成大于0并且小于n的随机数。

(define (zero-to-n-random x)

(let ((r (random x)))

(if (not (= r 0))

r

(zero-to-n-random x))))

random并不会参数负数的随机数,也不能用负数作为参数来产生随机数。下面我们来继续完成miller-rabin-prime函数。

(define (miller-rabin-prime? n)

(let ((x (ceiliing (/ n 2))))

(miller-rabin-test n x)))

(define (miller-rabin-test n x)

(cond ((= x 0) #t)

((= (expmod (zero-to-n-random n) (- n 1) n) 1)

(miller-rabin-test n (- x 1)))

(else #f)))

最后还剩下测试的工作了:

(miller-rabin-prime? 1729)

;Value: #f

(miller-rabin-prime? 2821)

;Value: #f

(miller-rabin-prime? 31)

;Value: #t

时间: 2024-08-13 15:06:00

【SICP练习】8 练习1.21-1.28的相关文章

Idea中使用jdbc报错:Wed Mar 21 09:28:33 CST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended...

报错提示: Sat Oct 21 09:28:33 CST 2019 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit opti

在聚会中常玩数七的游戏,七的倍数和带有七的数字都不能说,比如14,27,28。请找出1~100的不能说的数字。

利用ES5的filter高阶函数来实现 var arr =[1,2,3,4,5,6,7,17,27,21,22,28......100], r = arr.filter(function(x){ return (x % 10 == 7|| x % 7 == 0); }); alert(r);//[7,14,17,21,27,28..........97]

练习2-1

dat = read.csv("femaleMiceWeights.csv")mean(dat[13:24,2]) - mean(dat[1:12,2])s = split(dat[,2], dat[,1])stripchart(s, vertical=TRUE, col=1:2)abline(h=sapply(s, mean), col=1:2)abline(h=sapply(s, mean), col=1:2) > sum(dat[13:24,2]<mean(dat[1

(转)625某电商网站数据库宕机故障解决实录(上)

625某电商网站数据库特大故障解决实录(上) 原文:http://oldboy.blog.51cto.com/2561410/1431161 这是一次,惊心动魄的企业级电商网站数据库在线故障解决实录,故障解决的过程遇到了很多问题,思想的碰撞,解决方案的决策,及实际操作的问题困扰,老男孩尽量原汁原味的描述恢复的全部过程及思想思维过程!老男孩教育版权所有,本内容禁止商业用途. 目录: 625某电商网站数据库特大故障解决实录... 1 1接到电商客户报警... 1 1.1与客户初步沟通... 1 1.

【学习】基础知识:数组和矢量计量【Numpy】

Numpy是高性能科学计算和数据分析的基础包.功能如下: ndarray 一个具有矢量算法运算和复杂广播能力的快速且节省空间的多维数组 用于对整组数据进行快速运算的标准数学函数(无需编写循环) 用于读写磁盘数据的工具以及用于操作内存映射文件的工具. 线性代数.随机数生成以及傅里叶变换功能 用于集成由C\C++\Fortran等语言编写的代码的工具 numpy本身并没有提供多么高级的数据分析功能,理解numpy数组以及面向数组的计算将有助于更加高效地使用诸如pandas之类的工具 关注的功能集中在

Python对字典(directory)按key和value排序

distance = {9149: 0, 9150: 26, 9151: 24, 9152: 24, 9153: 24, 9154: 27, 9155: 25, 9156: 30, 9158: 20, 9159: 22, 9160: 25, 9161: 21, 9163: 25, 9164: 23, 9165: 25, 9166: 30, 9167: 20, 9169: 25, 9170: 24, 9171: 23, 9172: 25, 9173: 24, 9174: 29, 9176: 27,

CodeForces 55D Beautiful numbers (数位DP)

题意:给求给定区间中该数能整除每一位的数的数量. 析:dp[i][j][k] 表示前 i 位,取模2520为 j,最小倍数是 k,但是这样,数组开不下啊,那怎么办呢,其实,0-9的最小公倍数的不同各类并没有那么多, 其实就48种,所以我们可以给这48个一个编号,然后就能开出来了. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <strin

Codeforces Round #149 (Div. 2) E. XOR on Segment (线段树成段更新+二进制)

题目链接:http://codeforces.com/problemset/problem/242/E 给你n个数,m个操作,操作1是查询l到r之间的和,操作2是将l到r之间的每个数xor与x. 这题是线段树成段更新,但是不能直接更新,不然只能一个数一个数更新.这样只能把每个数存到一个数组中,长度大概是20吧,然后模拟二进制的位操作.仔细一点就行了. 1 #include <iostream> 2 #include <cstdio> 3 #include <cmath>

XML 数据请求与JSON 数据请求

(1)XML 数据请求 使用 AFNetworking 中的 AFHTTPRequestOperation 和 AFXMLParserResponseSerializer,另外结合第三方框架 XMLDictionary 进行数据转换 使用 XMLDictionary 的好处:有效避免自行实现 NSXMLParserDelegate 委托代理协议方法来进行繁琐的数据拼凑解析 (2)JSON 数据请求 使用 AFNetworking 中的 AFHTTPRequestOperation 或 AFHTT