第0章 基础知识


本章主要内容:

  • 初等微积分和函数求值的一些基本思想
  • 现代计算机运行机器算术的细节
  • 有效数字
  • 二进制数制系统,浮点的表达
  • 舍入的通用法则和误差影响

0.1 多项式求值


对于多项式: $$P(x)=2x^4+3x^3-3x^2+5x-1 \notag$$ 当$x=\frac{1}{2}$时,如何才是计算上面表达式结果的最优方式?

【方法1】,直接把$x=\frac{1}{2}$代入上面的表达式,可以计算出结果。如下面的python程序,这个方法要计算10次乘法,4次加法。


In [7]:
import sympy as sy
x=sy.symbols("x")
p=2*x**4+3*x**3-3*x*x+5*x-1
print(p.subs(x,1/2))
print(p.subs(x,sy.S.One*1/2)) #sy.S.One可以确保最后结果保持分数的形式


1.25000000000000
5/4

【方法2】,可以先算当$x=\frac{1}{2}$时,$a=x\cdot x, b=x^3=x^2\cdot x=ax, c=x^4=bx$,最后原来的多项式可以看作: $$ P(x,a,b,c)=2c+3b-3a+5x-1 \notag$$ 这样,所需要的乘法是7次,加法4次,相比方法1减少了3次乘法,当数据量大的时候,可以得到更快的结果。

【方法3】,把原多项式改写为: $$P(x)=-1+x\cdot(5+x\cdot(-3+x\cdot(3+x\cdot 2))) \tag{0.2}$$ 这样就只有4次乘法,4次加法。这种方法称为:嵌套乘法或者霍纳方法。一般的,$d$阶多项式可以通过$d$次乘法和$d$次加法来求值。

例如,对于标准形式下的多项式:$c_1+c_2x+c_3x^2+c_4x^3+c_5x^4$ 可以写为嵌套的形式: $$c_1+x(c_2+x(c_3+x(c_4+xc_5))) \tag{0.4}$$

而更加一般的是下面考虑到基点$r_1,r_2,...$得到的形式: $$c_1+(x-r_1)(c_2+(x-r_2)(c_3+(x-r_3)(c_4+(x-r_4)c_5))) \tag{0.5}$$ 下面是用numpy来实现的采用嵌套乘法计算的函数。


In [8]:
import numpy as np

'''
程序:嵌套乘法求多项式的值
参数: n: integer, 多项式的阶
      c: list, 多项式每一项的系数数组,第一个是常数项,长度为n+1个
      x: double, x的值
      r: double, 基点数组, 长度为n个
'''
def nest(n,c,x,r):
    y=c[-1]
    for i in range(1,n+1,1):
       y=y*(x-r[n-i])+c[n-i]
    return y

print(nest(4,[-1,5,-3,3,2],1/2,[0,0,0,0]))


1.25

0.2 二进制数字

0.2.1 将十进制转换为二进制

  1. 整数部分:除2取余数法,比如:

53 ➗ 2 = 26 余 1
26 ➗ 2 = 13 余 0
13 ➗ 2 = 6 余 1
6 ➗ 2 = 3 余 0
3 ➗ 2 = 1 余 1
1 ➗ 2 = 0 余 1
因此$(53)_{10} = (110101)_2$

  1. 小数部分:在小数部分乘2,保留小数部分,记录整数的值,比如:

0.7 ✖ 2 = 0.4 --> 1
0.4 ✖ 2 = 0.8 --> 0
0.8 ✖ 2 = 0.6 --> 1
0.6 ✖ 2 = 0.2 --> 1
0.2 ✖ 2 = 0.4 --> 0
0.4 ✖ 2 = 0.8 --> 0
0.8 ✖ 2 = 0.6 --> 1
...

最后会形成重复的位,表示为:$(0.7)_{10} = (0.101100110...)_2=(0.1\overline{0110})_2$

0.2.2 将二进制转换为十进制

  1. 整数部分:以2为基建立多项式,比如$(10101)_2$可以转为: $$1\times 2^4+0\times 2^3+1\times 2^2+0\times 2^1+1\times 2^0=(21)_{10} \notag $$

  2. 小数部分:以$\frac{1}{2}$为基建立多项式,比如$(0.1011)_2$转为: $$ 1\times\left(\frac{1}{2}\right)^1+0\times\left(\frac{1}{2}\right)^2+1\times\left(\frac{1}{2}\right)^3+1\times\left(\frac{1}{2}\right)^4 = \left(\frac{11}{16}\right)_{10} $$

注意当小数为重复出现的循环小数时,可以利用2乘的平移性质的技巧:

当小数部分全是循环小数时,比如 $x=(0.\overline{1011})_2$ ,由于小数后有4位小数循环,所以把 $x\cdot 2^4$,得到: $$ \begin{align*} 2^4x &=1011.\overline{1011} \\ x &=0000.\overline{1011} \end{align*} \notag $$,上下相减得到:$(2^4-1)x=(1011)_2=(11)_{10}$,求解出$x$,转换为十进制,得到:$x=(0.\overline{1011})_2=\left(\frac{11}{15}\right)_{10}$

当小数部分有部分是循环小数时,比如 $x=(0.10\overline{101})_2$ ,把 $x\cdot 2^2$,得到 $y=2^2x=(10.\overline{101})_2 $, 取$y$的分数部分,记为$z=0.\overline{101}$,按前面所述进行计算: $$ \begin{align*} 2^3z &=101.\overline{101} \\ z &=000.\overline{101} \end{align*} \notag $$,上下相减得到:$(2^3-1)z=(101)_2=(5)_{10}$,求解出$7z=5, y=2+z=2+\frac{5}{7}, x=\frac{y}{2^2}=\frac{19}{28}$

0.2.3 二进制、八进制和十六进制互相转换

二进制 八进制 二进制 十六进制
000 0 0000 0
001 1 0001 1
010 2 0010 2
011 3 0011 3
100 4 0100 4
101 5 0101 5
110 6 0110 6
111 7 0111 7
- - 1000 8
- - 1001 9
- - 1010 A
- - 1011 B
- - 1100 C
- - 1101 D
- - 1110 E
- - 1111 F

二进制转八进制的例子: $ \underline{101}\:\underline{011}\:\underline{110} \Leftrightarrow 536$

二进制转十六进制的例子: $ \underline{1101}\:\underline{0011}\:\underline{1100} \Leftrightarrow D3C$

0.3 实数的浮点表示

采用的是IEEE 754浮点标准。注意,简单算法,诸如高斯消去或者微分方程的求解方法,能够把极微小的误差放大到极大的规模

0.3.1 浮点格式

精度(总位数) 符号($\pm$)位 指数位 尾数位(有效二进制数位)
单精度(32bit) 1 8 23
双精度(64bit) 1 11 52
长双精度(80bit) 1 15 64

浮点数的表示:$\pm 1.bbb...b\times 2^p$,其中$N$个$b$是$0$或者$1$,$p$是一个$M$位的二进制数表示指数,最左边的一位必须是$1$,意味着每个保存的浮点数必须转换为二进制的小数,只保留一位的小数点左边的$1$,转换为指数的形式。

比如:十进制的 $92.6$ ,转换为小数的二进制表示: $\underline{101}\:\underline{1100}.\overline{1001} \to +1.\underline{01}\:\underline{1100}\:\underline{1001}...\times 2^6 \to +1.\underline{01}\:\underline{1100}\:\underline{1001}...\times 2^{\underline{110}}$,对于单精度的类型,实际存储的内容如下:

指数位(8位)尾数位(23位)
$\underline{0}$ $\underline{0000}\:\underline{0110}$ $\underline{01}\:\underline{1100}\:\underline{1001}\:\underline{1001}\:\underline{1001}\:\underline{1001}\:\underline{1}$

0.4 有效数字的缺失

0.5 微积分回顾