0
点赞
收藏
分享

微信扫一扫

【Python编程导论】第三章- 一些简单的数值程序

基本概念

1. 穷举法

穷举法​:是猜测与检验算法的一个变种。我们枚举所有可能性,直至得到正确答案或者尝试完所有值。

  1. ​#寻找完全立方数的立方根​
  2. ​x = int(input('Enter an integer: '))​
  3. ​ans = 0​
  4. ​while ans**3 < abs(x):​
  5. ​    ans = ans + 1​
  6. ​if ans**3 != abs(x):​
  7. ​    print(x, 'is not a perfect cube')​
  8. ​else:​
  9. ​    if x < 0:​
  10. ​        ans = -ans​
  11. ​    print('Cube root of', x,'is', ans)​

那么,对于何种x值,程序能正常结束呢?答案是“所有整数”。 ​​:

1.表达式ans**3的值从0开始,并随着每次循环逐渐变大; 2.当这个值达到或超过abs(x)时,循环结束; 3.因为abs(x)的值总为正,所以循环结束前进行的迭代次数必然是有限的。编写循环时,应该使用一个合适的递减函数。这个函数具有如下属性:

  1. 它可以将一组程序变量映射为一个整数;
  2. 进入循环时,它的值是非负的;
  3. 当它的值≤0时,循环结束;
  4. 每次循环它的值都会减小。

2. for循环

for循环中常用到 ​range()函数​,因此先对它进行介绍:

  1. range函数接受3个整数参数:start、stop和step。生成一个数列:start、start + step、start + 2*step,等等。
  2. 如果step是正数,最后一个元素就是小于stop的最大整数start + i * step。如果step是负数,最后一个元素就是大于stop的最小整数start + i * step。
  3. 数列中的数值是以“按需产生”的原则生成的,所以即使range(1000000)这样的表达式也只占用很少内存。
  4. ​#寻找完全立方数的立方根​
  5. ​x = int(input('Enter an integer: '))​
  6. ​for ans in range(0, abs(x)+1):​
  7. ​    if ans**3 >= abs(x):​
  8. ​        break​
  9. ​if ans**3 != abs(x):​
  10. ​    print(x, 'is not a perfect cube')​
  11. ​else:​
  12. ​    if x < 0:​
  13. ​        ans = -ans​
  14. ​    print('Cube root of', x,'is', ans)​

3. 近似解和二分查找

穷举法​是一种查找技术,只在被查找集合中包含答案时才有效

  1. ​#使用穷举法求近似平方根​
  2. ​x = 25​
  3. ​epsilon = 0.01​
  4. ​step = epsilon**2​
  5. ​numGuesses = 0​
  6. ​ans = 0.0​
  7. ​while abs(ans**2 - x) >= epsilon and ans <= x:​
  8. ​    ans += step​
  9. ​    numGuesses += 1​
  10. ​print('numGuesses =', numGuesses)​

  11. ​if abs(ans**2 - x) >= epsilon:​
  12. ​    print('Failed on square root of', x)​
  13. ​else:​
  14. ​    print(ans, 'is close to square root of', x)​

二分查找法​,可以提升查询效率

  1. ​x = 25​
  2. ​epsilon = 0.01​
  3. ​numGuesses = 0​
  4. ​low = 0.0​
  5. ​high = max(1.0, x)​
  6. ​ans = (high + low)/2.0​
  7. ​while abs(ans**2 - x) >= epsilon:​
  8. ​    print('low =', low, 'high =', high, 'ans =', ans)​
  9. ​    numGuesses += 1​
  10. ​    if ans**2 < x:​
  11. ​        low = ans​
  12. ​    else:​
  13. ​        high = ans​
  14. ​    ans = (high + low)/2.0​
  15. ​print('numGuesses =', numGuesses)​
  16. ​print(ans, 'is close to square root of', x)​

4. 关于浮点数

很多时候, ​float类型​的数值是实数的一个非常好的 ​近似​。但“很多时候”并不代表所有情况,这个功能失效时会引起不可思议的后果。例如,试着运行以下代码:

  1. ​x = 0.0​
  2. ​for i in range(10):​
  3. ​    x = x + 0.1​
  4. ​if x == 1.0:​
  5. ​    print(x, '= 1.0')​
  6. ​else:​
  7. ​    print(x, 'is not 1.0')​
  8. ​# 结果​
  9. ​0.9999999999999999 is not 1.0​

为什么会出现这样的结果呢?

  1. 其实这和二进制与十进制表示方式有关(python中二进制表示的0.1并不是真的等于十进制中0.1)。
  2. 那Python中写作0.1的十进制分数1/10呢?若使用4位有效数字,最好的表示方式是(0011,-101),等于3/32,也就是0.09375。如果有5位有效的二进制数字,可以将0.1表示成(11001, -1000),等于25/256,也就是0.09765625。那么,需要多少位有效数字才能使用浮点数准确表示0.1呢?需要无穷位!不存在两个整数sig和exp,使sig × 2-exp = 0.1。所以无论Python(或任何一种语言)使用多少位有效数字表示浮点数,都只能表示0.1的一个近似值。
  3. 所以将0.1相加10次真的不等于10乘以0.1的值

5. 牛顿-拉弗森法

牛顿-拉弗森法​可以用于求单变量多项式的值,那么什么是单变量多项式?

单变量多项式或者是0,或者是一个有限数目的非零单项式的和。每一项都由一个常数(项的系数)乘以变量的非负整数次方(这里为2次方)组成。

牛顿-拉弗森法的原理​:

逐次逼近;牛顿证明了一个定理:如果存在一个值guess是多项式p的根的近似值,那么guess -p(guess)/p'(guess)就是一个更好的近似值,其中p'是p的一次导数。

  1. ​#利用牛顿.拉弗森法寻找平方根​
  2. ​#寻找x,满足x**2-24在epsilon和0之间​
  3. ​epsilon = 0.01​
  4. ​k = 24.0​
  5. ​guess = k/2.0​
  6. ​while abs(guess*guess - k) >= epsilon:​
  7. ​    guess = guess - (((guess**2) - k)/(2*guess))​
  8. ​print('Square root of', k, 'is about', guess)​

编程练习

1.编写一个程序,要求用户输入一个整数,然后输出两个整数root和pwr,满足 ​0<pwr<6​,并且 ​root**pwr​等于用户输入的整数。如果不存在这样一对整数,则输出一条消息进行说明。

  1. ​# 解法1​
  2. ​r = int(input('input an integer'))​
  3. ​root = 0​
  4. ​i = 0​
  5. ​for pwr in range(1, 7):​
  6. ​    result = -1​
  7. ​    while result < abs(r):​
  8. ​        root += 1​
  9. ​        result = root**pwr​
  10. ​    if result == abs(r):​
  11. ​        if r < 0:​
  12. ​            root = -root​
  13. ​        print('root:{},pwr:{}'.format(root, pwr))​
  14. ​        i += 1​
  15. ​    root = 0​
  16. ​print('总共有{}种输出结果'.format(i))​
  17. ​# 解法2​
  18. ​x=int(input('Enter an integer: '))​
  19. ​root=1​
  20. ​pwr=1​
  21. ​w=root**pwr​
  22. ​i=0​
  23. ​while w<abs(x) or root<=abs(x): ​
  24. ​    if pwr<6: ​
  25. ​        w=root**pwr​
  26. ​        if w==abs(x) and x<0:​
  27. ​            i+=1​
  28. ​            print('root','=',-root,'pwr','=',pwr)​
  29. ​        elif w==abs(x):​
  30. ​            i+=1​
  31. ​            print('root','=',root,'pwr','=',pwr)​
  32. ​        pwr+=1​
  33. ​    else:​
  34. ​        pwr=1​
  35. ​        root+=1​
  36. ​        w=root**pwr​
  37. ​print('符合条件的整数对共有{}种'.format(i))​

2.假设s是包含多个小数的字符串,由逗号隔开,如 ​s='1.23, 2.4, 3.123'​。编写一个程序,输出s中所有数值的和。

  1. ​# 解法1​
  2. ​s = '1.23, 2.4, 3.123'​
  3. ​sum = 0.0​
  4. ​for i in map(lambda i: float(i), s.split(',')):​
  5. ​    sum += i​
  6. ​print(sum)​
  7. ​# 解法2​
  8. ​s = '1.23, 2.4, 3.123'​
  9. ​a=s.split(',')​
  10. ​t=0​
  11. ​for i in a:​
  12. ​    t=t+float(i)​
  13. ​print(t)​

3.如果语句x = 25被替换为x = -25,代码会如何运行?

  1. ​程序会进入无限循环​
  2. ​# 该程序while循环中,x值始终未变。则导致该循环条件(abs(ans**2 - x) >= epsilon)始终成立,程序进入无限循环中。​
  3. ​x = -25​
  4. ​epsilon = 0.01​
  5. ​numGuesses = 0​
  6. ​low = 0.0​
  7. ​high = max(1.0, x)​
  8. ​ans = (high + low)/2.0​
  9. ​while abs(ans**2 - x) >= epsilon: # 这一步永远不会停止​
  10. ​    print('low =', low, 'high =', high, 'ans =', ans)​
  11. ​    numGuesses += 1​
  12. ​    if ans**2 < x:​
  13. ​        low = ans​
  14. ​    else:​
  15. ​        high = ans​
  16. ​    ans = (high + low)/2.0​
  17. ​print('numGuesses =', numGuesses)​
  18. ​print(ans, 'is close to square root of', x)​

4.如何修改图3-4中的代码,才能求出一个数的立方根?这个数既可以是正数,也可以是负数。(提示:修改low保证答案位于待查找区域。)

  1. ​x = -30​
  2. ​epsilon = 0.01​
  3. ​numGuesses = 0​
  4. ​x_abs = abs(x)  # 关键代码​
  5. ​low = 0.0​
  6. ​high = max(1.0, x_abs)​
  7. ​ans = (high + low) / 2.0​
  8. ​while abs(ans**3 - x_abs) >= epsilon:​
  9. ​    numGuesses += 1​
  10. ​    if ans**3 < x_abs:​
  11. ​        low = ans​
  12. ​    else:​
  13. ​        high = ans​
  14. ​    ans = (high + low) / 2.0​
  15. ​print('numGuesses =', numGuesses)​
  16. ​if x < 0:​
  17. ​    print(-ans, 'is close to square root of', x)​
  18. ​else:​
  19. ​    print(ans, 'is close to square root of', x)​

5.二进制数10011等于十进制中的哪个数?

  1. ​19​
  2. ​# 解法1 进制转换​
  3. ​# 解法2 函数求解​
  4. ​int('10011',base=2)​

6.在牛顿.拉弗森法的实现中添加一些代码,跟踪求平方根所用的迭代次数。在这段代码的基础上编写一个程序,比较牛顿.拉弗森法和二分查找法的效率。

  1. ​#利用牛顿.拉弗森法寻找平方根​
  2. ​#寻找x,满足x**2-24在epsilon和0之间​
  3. ​epsilon = 0.01​
  4. ​k = 24.0​
  5. ​guess = k/2.0​
  6. ​a=0​
  7. ​while abs(guess*guess - k) >= epsilon:​
  8. ​    guess = guess - (((guess**2) - k)/(2*guess))​
  9. ​    a+=1​
  10. ​print('Square root of', k, 'is about', guess)​
  11. ​print('牛顿法迭代次数={}'.format(a))​

  12. ​#利用二分查找法寻找平方根​
  13. ​#寻找x,满足x**2-24在epsilon和0之间​
  14. ​x = 24.0​
  15. ​epsilon = 0.01​
  16. ​numGuesses = 0​
  17. ​low = 0.0​
  18. ​high = max(1.0, x)​
  19. ​ans = (high + low)/2.0​
  20. ​b=0​
  21. ​while abs(ans**2 - x) >= epsilon:​
  22. ​    numGuesses += 1​
  23. ​    if ans**2 < x:​
  24. ​        low = ans​
  25. ​    else:​
  26. ​        high = ans​
  27. ​    ans = (high + low)/2.0​
  28. ​print(ans, 'is close to square root of', x)​
  29. ​print('二分法迭代次数 ={}'.format(numGuesses))​
  30. ​Square root of 24.0 is about 4.8989887432139305​
  31. ​牛顿法迭代次数=4​
  32. ​4.8984375 is close to square root of 24.0​
  33. ​二分法迭代次数 =9​


举报

相关推荐

0 条评论