Python程序设计(第三版)课后题答案 第八章
编程练习题
- 1.斐波那契数列开始是1,1,2,3,4,5,8,……前两个数字之后,序列中的每个数字都是前两个数字之和。编写一个程序,计算并输出第n个斐波那契数,其中n是用户输入的值。
答案:
def main(): # 循环计算斐波那契数列
n = eval(input('请输入要计算第几位的斐波那契数:'))
a, b = 1, 1
i = 1
while i < n:
a, b = b, a + b
i = i + 1
print('第{0}位的斐波那契数为:{1}'.format(n, a))
main()
输出结果如下:
请输入要计算第几位的斐波那契数:7
第7位的斐波那契数为:13
请输入要计算第几位的斐波那契数:3
第3位的斐波那契数为:2
- 2.国家气象局使用以下公式计算风寒指数:
35.74 + 0.6215 T − 35.75 ( V 0.16 ) + 0.4275 T ( V 0.16 ) 35.74 + 0.6215T - 35.75( V^{0.16}) + 0.4275T(V^{0.16}) 35.74+0.6215T−35.75(V0.16)+0.4275T(V0.16)
其中,T是以华氏温度为单位的温度,V是以小时为单位的风速。
编程打印一张格式漂亮的风寒指数表格。行代表风速为0~50,以5英里/小时为增量,列表示温度从-20 ~ +60,以10为增量。注意:该公式仅适用于每小时超过3英里的风速。
答案:
def main(): # 编程打印一张风寒指数表格
v = 0
t = -20
print(' T\V | ', end='')
while v <= 50:
print(v, end=' ')
v = v + 5
print('\n-----------------------------------------------------------------------------------')
while -20 <= t <= 60:
print(str(t).center(5), end='|')
v = 0
while v <= 50:
if v <= 0:
print(str('###').rjust(6), end=' ')
else:
index = 35.74 + 0.6215 * t - 35.75 * (v ** 0.16) + 0.4275 * t * (v ** 0.16)
print(str(round(index, 2)).rjust(6), end=' ')
v = v + 5
print('\n')
t = t + 10
main(
输出结果如下:(速度为0时不满足要求,不予计算)
T\V | 0 5 10 15 20 25 30 35 40 45 50
-----------------------------------------------------------------------------------
-20 | ### -34.0 -40.72 -45.01 -48.23 -50.83 -53.03 -54.93 -56.62 -58.14 -59.53
-10 | ### -22.26 -28.33 -32.21 -35.11 -37.46 -39.45 -41.17 -42.7 -44.07 -45.32
0 | ### -10.51 -15.93 -19.4 -22.0 -24.09 -25.86 -27.4 -28.77 -29.99 -31.11
10 | ### 1.24 -3.54 -6.59 -8.88 -10.72 -12.28 -13.64 -14.84 -15.92 -16.9
20 | ### 12.98 8.85 6.22 4.24 2.65 1.3 0.13 -0.91 -1.84 -2.69
30 | ### 24.73 21.25 19.03 17.36 16.02 14.88 13.89 13.02 12.23 11.52
40 | ### 36.47 33.64 31.84 30.48 29.39 28.46 27.66 26.95 26.31 25.73
50 | ### 48.22 46.04 44.64 43.6 42.76 42.04 41.43 40.88 40.38 39.93
60 | ### 59.96 58.43 57.45 56.72 56.13 55.63 55.19 54.81 54.46 54.14
- 3.用while循环编程,来确定投资在特定利率下翻倍需要多长时间。输入是年利率,输出是投资增加一倍的年数。注:初始投资金额无关紧要,你可以用1元。
答案:
def main(): # 计算投资翻倍的年限
rate = eval(input('请输入年利率:'))
pricipal = eval(input('请输入投资金额:'))
invest = pricipal
n = 0
while invest < (2 * pricipal):
n = n + 1
invest = pricipal * (1 + n * rate)
print('第{0}年投资能够增加一倍。'.format(n))
main()
输出结果如下:
请输入年利率:0.03
请输入投资金额:1
第34年投资能够增加一倍。
- 4.Syracuse(也称“Collatz”或“Hailstone”)序列的生成从一个自然数开始,重复应用以下函数,直到达到1:
s
y
r
(
x
)
=
{
x
/
2
,
x
为偶数
3
x
+
1
,
x
为奇数
syr(x)= \begin{cases} \ \ \ \ \ x/2, \ \ x为偶数\\ 3x+1,\ \ x为奇数\\ \end{cases}
syr(x)={ x/2, x为偶数3x+1, x为奇数
例如,从5开始的Syracuse序列是5,16,8,4,2,1。数学中有一个悬而未决的问题:对于每个可能的起始值,该序列是否总会到达1。
编程从用户获取起始值,然后打印该起始值的Syracuse序列。
答案:
def main(): # Syracuse序列
initial = eval(input('请输入初始值(大于0):'))
print('{0}的Syracuse序列是:{0}'.format(initial), end=' ')
while initial != 1:
while judge_odd_number(initial):
initial = 3 * initial + 1
print(initial, end=' ')
while judge_even_number(initial):
initial = int(initial / 2)
print(initial, end=' ')
main()
输出结果如下:
请输入初始值(大于0):5
5的Syracuse序列是:5 16 8 4 2 1
请输入初始值(大于0):15
15的Syracuse序列是:15 46 23 70 35 106 53 160 80 40 20 10 5 16 8 4 2 1
- 5.正整数n>2是素数,如果2和n(不含n)之间的数字都不能整除n。编程接受n值作为输入,并确定该值是否为素数。如果n不是素数,那么程序应该在发现能整除n的值后立即退出。
答案:
def main(): # 判断素数
n = eval(input('请输入要判断的数(n>2):'))
for i in range(2, n):
if n % i == 0:
print('{0}不是素数'.format(n))
break
elif i + 1 == n:
print('{0}是素数'.format(n))
main()
输出结果如下:
请输入要判断的数(n>2):4
4不是素数
请输入要判断的数(n>2):7
7是素数
请输入要判断的数(n>2):9
9不是素数
- 6.修改上一个程序,找出小于或等于n的每个素数。
答案:
def judge_prime_number(n): # 判断素数
# n = eval(input('请输入要判断的数(n>2):'))
for i in range(2, n):
if n % i == 0:
return False
# print('{0}不是素数'.format(n))
# break
elif i + 1 == n:
return True
# print('{0}是素数'.format(n))
def main(): # 找出<=n的素数
n = eval(input('请输入要找的数(n>2):'))
for i in range(n+1):
if judge_prime_number(i):
print(i, end=' ')
main()
输出结果如下:
请输入要找的数(n>2):17
3 5 7 11 13 17
请输入要找的数(n>2):101
3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101
- 7.哥德巴赫猜想认为每个偶数都是两个素数之和。编程从用户那里获取一个数字,检查以确保它是偶数,然后找到两个素数,和为该数字。
答案:
def main(): # 2个素数之和为偶数,找这两个素数
n = eval(input('请输入一个数:'))
if judge_even_number(n) and n > 2:
p = [1]
for i in range(n + 1):
if judge_prime_number(i):
p = p + [i]
q = []
for i in range(len(p)):
for j in range(len(p)):
if p[i] + p[j] == n:
q = q + [(p[i], p[j])]
if judge_even_number(len(q)):
print('可能得素数组合有:', q[0:int(len(q) / 2)])
else:
print('可能得素数组合有:', q[0:(int(len(q)/2) + 1)])
else:
print('输入的数不符合要求!')
main()
输出结果如下:
请输入一个数:8
可能得素数组合有: [(1, 7), (3, 5)]
请输入一个数:7
输入的数不符合要求!
请输入一个数:100
可能得素数组合有: [(3, 97), (11, 89), (17, 83), (29, 71), (41, 59), (47, 53)]
- 8.可以用欧几里得的算法计算两个值的最大公约数(GCD)。从值m和n开始,我们反复应用公式:n,m = m,n%m,直到m为0。这时,n就是原始m和n的GCD。用这个算法编程求两个数字的GCD。
答案:
def main(): # 计算最大公约数
m, n = eval(input('请输入两个数:'))
while m != 0:
n, m = m, n % m
print('这两个数的最大公约数是:', n)
main()
输出结果如下:
请输入两个数:24,96
这两个数的最大公约数是: 24
请输入两个数:63,91
这两个数的最大公约数是: 7
- 9.编程计算多段旅游的燃油效率。该程序会首先提示输入开始时里程表的读数,然后获取有关一系列分段旅程的信息。对于每个分段,用户输入当前的里程表读数和使用的汽油量(用空格分隔)。用户用空白行来表示行程结束。该程序打印出每段旅程上每加仑的英里数以及旅程的总MPG(英里/加仑)。
答案:
def main(): # 计算旅程,英里/加仑
initial_odometer = eval(input('请输入当前里程表的读数:'))
str = input('请输入当前分段旅程的里程表读数和使用汽油量:')
tmile, tgasoline = 0, 0
while str != '':
current_odometer = float(str.split(' ')[0])
gasoline = float(str.split(' ')[1])
mile = current_odometer - initial_odometer
mile_gasoline = mile / gasoline
tmile = tmile + mile
tgasoline = tgasoline + gasoline
mpg = tmile / tgasoline
print('本段里程的每加仑的英里数为:{0:0.2f},总的MPG为:{1:0.2f}。'.format(mile_gasoline, mpg))
str = input('请输入当前分段旅程的里程表读数和使用汽油量:')
main()
输出结果如下:
请输入当前里程表的读数:0
请输入当前分段旅程的里程表读数和使用汽油量:50 10
本段里程的每加仑的英里数为:5.00,总的MPG为:5.00。
请输入当前分段旅程的里程表读数和使用汽油量:100 20
本段里程的每加仑的英里数为:5.00,总的MPG为:5.00。
请输入当前分段旅程的里程表读数和使用汽油量:150 40
本段里程的每加仑的英里数为:3.75,总的MPG为:4.29。
请输入当前分段旅程的里程表读数和使用汽油量:200 45
本段里程的每加仑的英里数为:4.44,总的MPG为:4.35。
请输入当前分段旅程的里程表读数和使用汽油量:
进程已结束,退出代码0
- 10.修改上一个程序,从文件获取输入。
答案:
def main(): # 计算旅程,英里/加仑
fileName = input("What file are the numbers in? ")
infile = open(fileName, 'r')
initial_odometer = int(infile.readline())
str = infile.readline()
tmile, tgasoline = 0, 0
while str != '':
current_odometer = float(str.split(' ')[0])
gasoline = float(str.split(' ')[1])
mile = current_odometer - initial_odometer
mile_gasoline = mile / gasoline
tmile = tmile + mile
tgasoline = tgasoline + gasoline
mpg = tmile / tgasoline
print('本段里程的每加仑的英里数为:{0:0.2f},总的MPG为:{1:0.2f}。'.format(mile_gasoline, mpg))
str = infile.readline()
main()
输入文件内容如下:
输出结果如下:
What file are the numbers in? mile.txt
本段里程的每加仑的英里数为:5.00,总的MPG为:5.00。
本段里程的每加仑的英里数为:4.50,总的MPG为:4.78。
本段里程的每加仑的英里数为:2.51,总的MPG为:3.28。
本段里程的每加仑的英里数为:4.17,总的MPG为:3.56。
进程已结束,退出代码0
- 11.加热和制冷的“度天”是公用事业公司估计在此处键入公式。能源需求的测量指标。如果某天的平均温度低于60摄氏度,则在加热度天数中加入低于60摄氏度的度数。如果温度高于80摄氏度,则在制冷度天数中加入超过80摄氏度的度数。编程接受每日平均温度的序列,并计算制冷和加热度天数的不断增长的总和,所有的数据处理完成后,程序应该打印这两个总和。
答案:
def main():
refrigeration = 0
heating = 0
str = input('请输入每日平均温度的序列:')
while str != '':
list = str.split(' ')
for i in range(len(list)):
if float(list[i]) < 60:
refrigeration = refrigeration + (60 - float(list[i]))
elif float(list[i]) > 80:
heating = heating + (float(list[i]) - 80)
print('制冷度天数的总和为:{0:0.2f},制热度天数的总和为:{1:0.2f}。'.format(refrigeration, heating))
break
main()
输出如下:
请输入每日平均温度的序列:58 82 99 102 55 15 78 99 130
制冷度天数的总和为:52.00,制热度天数的总和为:112.00。
进程已结束,退出代码0
- 12.修改上一个程序,从文件获取输入。
答案:
def main():
refrigeration = 0
heating = 0
fileName = input("What file are the temperature in? ")
infile = open(fileName, 'r')
str = infile.readline()
while str != '':
list = str.split(' ')
for i in range(len(list)):
if float(list[i]) < 60:
refrigeration = refrigeration + (60 - float(list[i]))
elif float(list[i]) > 80:
heating = heating + (float(list[i]) - 80)
str = infile.readline()
print('制冷度天数的总和为:{0:0.2f},制热度天数的总和为:{1:0.2f}。'.format(refrigeration, heating))
main()
输入文件内容如图:
输出结果如下:
What file are the temperature in? temperature.txt
制冷度天数的总和为:188.00,制热度天数的总和为:187.00。
- 13.编写一个程序,以图形方式绘制回归线,即通过一个点集的最佳曲线。首先要求用户在图形窗口中点击,指定数据点。为了表示输入结束,将一个标有“Done”的小矩形放在窗口的左下角。当用户在该矩形内点击时,程序将停止收集数据点。
回归线是满足以下公式的线:
y = y ˉ + m ( x − x ˉ ) y= \bar{y} +m(x- \bar{x}) y=yˉ+m(x−xˉ)
其中
m = ∑ x i y i − n x ˉ y ˉ ∑ x i 2 − n x ˉ 2 m = \frac {\sum x_iy_i - n\bar{x}\bar{y} }{\sum x_i^2 - n\bar{x}^2} m=∑xi2−nxˉ2∑xiyi−nxˉyˉ
x ˉ \bar{x} xˉ是 x x x的平均值, y ˉ \bar{y} yˉ是 y y y的平均值, n n n是点数。
当用户点击数据点时,程序应将它绘制在图形窗口中,并记录输入值的计数,以及x,y, x 2 x^2 x2和xy值的不断增长的总和。当用户单击“Done”矩形内部时,程序随后计算窗口左边缘和右边缘的x值对应的y值(用上面的公式),以计算穿越窗口的回归线的端点。线绘制后,程序将暂停并待另一次鼠标点击,然后关闭窗口并退出。
答案:
def main(): # 计算线性回归线
win = GraphWin('回归线', 800, 600)
win.setBackground('white')
win.setCoords(0, 0, 100, 100)
r = Rectangle(Point(80, 15), Point(90, 20)) # 绘制灰色提示框
r.setFill('gray')
r.draw(win)
t = Text(Point(85, 17.5), 'Done') # 绘制提示词“Done”
t.setFill('black')
t.draw(win)
n, xm, ym, xym, xs = 0, 0, 0, 0, 0
xl, xr = 100, 0
while True:
pt = win.checkMouse()
if pt and 80 < pt.getX() < 90 and 15 < pt.getY() < 20: # 判断有点且点的位置是否在“Done”区域内
break
elif pt:
n = n + 1
pt.draw(win)
x = pt.getX()
y = pt.getY()
if x < xl: # 记录点的x坐标的最小值
xl = x
if x > xr: # 记录点的x坐标的最大值
xr = x
xy = x * y # 点坐标的乘积
xm = xm + x # 点X坐标的求和
ym = ym + y # 点Y坐标的求和
xym = xym + xy # 点X,Y坐标的乘积的求和
xs = xs + x ** 2 # 点X坐标的平方的求和
m = (xym - n * (xm / n) * (ym / n)) / (xs - n * ((xm / n) ** 2)) # 根据给定公式计算m值
yl = (ym / n) + m * (xl - (xm / n)) # 根据给定公式计算线段左端点的y值
yr = (ym / n) + m * (xr - (xm / n)) # 根据给定公式计算线段右端点的y值
line = Polygon(Point(xl, yl), Point(xr, yr))
line.draw(win)
win.getMouse()
win.close()
main()
输出结果如下:
- 14.编写一个将色彩图像转换为灰度的程序。用户提供包含GIF和PPM图像文件的名称,程序加载图像并显示文件。再单击鼠标时,程序将图像转换为灰度。然后提示用户输入文件名,保存灰度图像。
你可能要回去复习一下graphics库中的Image对象。转换图像的基本思想是遍历它的每个像素,将颜色转换为合适的灰度。设置红绿蓝的比值,让他具有相同的亮度,从二创创建灰色像素。所以color_rgb(0,0,0)是黑色,color_rgb(255,255,255)是白色,color_rgb(127,127,127)是50度灰。你应该使用原始RGB值的加权平均值来确定灰度的亮度。下面是灰度算法的伪代码:
for each row in the image:
for each column in the image:
r, g, b = get piexl information for current row and column
brightness = int ( round (0.299r + 0.587g + 0.114b)
set pixel to color_rgb(brightness, brightness, brightness)
update the image # to see progess row by row
注意:Image类中的像素操作相当慢,因此要使用较小的图像(不是1200万像素)来测试你的程序。
答案:
def main(): # 图像变灰
win = GraphWin('灰度图像', 400, 300)
win.setBackground('white')
win.setCoords(0, 0, 100, 100)
win.getMouse()
fileName = input("What file is the picture? ")
picture = Image(Point(50, 50), fileName)
picture.draw(win)
win.getMouse()
pw = picture.getWidth()
ph = picture.getHeight()
for i in range(0, pw):
for j in range(0, ph):
r, g, b =picture.getPixel(i, j)
brightness = int(round(0.299*r + 0.587*g + 0.114*b))
picture.setPixel(i, j, color_rgb(brightness, brightness, brightness))
NewfileName = input("Enter a name to save the new file:")
picture.save(NewfileName)
win.getMouse()
win.close()
main()
输出过程如下:首先在窗口中显示彩色人物照片,
更改像素变为灰色:
运行交互时输入要打开的图像名称和要保存的文件名称:
What file is the picture? xiaoyan.png
Enter a name to save the new file:xiaoyan2.png
进程已结束,退出代码0
- 15.编写程序将图像转换成其他补色。程序的一般形式将于上一个问题类似。通过从255减去每个颜色值来得到像素的补值。因此,新像素的颜色是color_rgb(255-r,255-g,255-b)。
答案:
def main(): # 图像变为补色像素展示
win = GraphWin('灰度图像', 400, 300)
win.setBackground('white')
win.setCoords(0, 0, 100, 100)
win.getMouse()
fileName = input("What file is the picture? ")
picture = Image(Point(50, 50), fileName)
picture.draw(win)
win.getMouse()
pw = picture.getWidth()
ph = picture.getHeight()
for i in range(0, pw):
for j in range(0, ph):
r, g, b = picture.getPixel(i, j)
picture.setPixel(i, j, color_rgb(255 - r, 255 - g, 255 - b))
NewfileName = input("Enter a name to save the new file:")
picture.save(NewfileName)
win.getMouse()
win.close()
main()
输出过程如下:首先在窗口中显示彩色人物照片,
更改像素变为原像素的补值后图像如图所示:
运行交互时输入要打开的图像名称和要保存的文件名称:
What file is the picture? xiaoyan.png
Enter a name to save the new file:xiaoyan3.png
进程已结束,退出代码0
- 16.修改event_loop3程序,以使用书中所述的键。用户在Entry框中输入时,按键应该导致消失,并丢弃在框中输入的所有文本。
答案:
def handleKey(k, win):
if k == "r":
win.setBackground("pink")
elif k == "w":
win.setBackground("white")
elif k == "g":
win.setBackground("lightgray")
elif k == "b":
win.setBackground("lightblue")
def handleClick(pt, win):
entry = Entry(pt, 10)
entry.draw(win)
while True:
key = win.getKey()
if key == "Return":
entry.undraw()
Text(pt, entry.getText()).draw(win)
break
if key == "Escape": # loop exit
entry.undraw()
break
win.checkMouse()
def main():
win = GraphWin("Click and Type", 500, 500)
while True:
key = win.checkKey()
if key == "q":
break
if key:
handleKey(key, win)
pt = win.checkMouse()
if pt:
handleClick(pt, win)
win.close()
main()
输出窗口中:按下Esc键,Entry框消失,文本丢失;按下Enter键,Entry框消失,文本显示在图像中。
(如有错误,请读者批评指正!)