差分机の分析
写在前面的:
本文含有大量公式,不一定能成功渲染,请见谅。
Top Image来自这里有空再补图
差分机是啥?(极简)
差分机简易版本大致如下:
给定一些寄存器,可以看作类似数组a[N] (下标从1开始),这里假设N = 8,有八个寄存器a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]。
对于第i个寄存器,每次操作使得a[i]加上上次操作后a[i-1]的值。特别的,我们认为a[0] = 0 ,所以第一个寄存器a[1]的值永远不变。
下列表格中,第一列编号表示操作次数,操作0次即为初始状态。我们取a[1]=1 ,a[5] = 3,a[6] = 2 , a[7] = 1加以演示
a[1] | a[2] | a[3] | a[4] | a[5] | a[6] | a[7] | a[8] | |
---|---|---|---|---|---|---|---|---|
0. | 1 | 0 | 0 | 0 | 3 | 2 | 1 | 0 |
1. | 1 | 1 | 0 | 0 | 3 | 5 | 3 | 1 |
2. | 1 | 2 | 1 | 0 | 3 | 8 | 8 | 4 |
附:一个简单的差分机网站 from SJTU (点我传送)
差分机有啥用?
差分机原理十分简单,而它最大的作用就是用来快速多项式求出值。
考虑一个简单的函数 $ f(x) = x^2 $。
定义差分函数 :
$ f0(x) = f(x) $ 且 $ f_n(x) = f{n-1}(x+1) - f_{n-1}(x)$
我们对其二次差分 $f_1(x) = f(x+1) - f(x) = 2x+1$,而 $f_2(x) = f_1(x+1) - f_1(x) = 2$。可以发现,其二次差分的结果变为了常数,如果再进行更多次的差分,其得到的$ f_n(x)$必定为0。
那这和我们的差分机有啥关系呢?
我们把$f_0(0),f_1(0),f_2(0)$的值作为a[8],a[7],a[6]的初始值,然后进行运算,然后我们会发现,第n次操作后,a[8],a[7],a[6]的值便变成了$f_0(n),f_1(n),f_2(n)$的值。
a[5] | a[6] | a[7] | a[8] | |
---|---|---|---|---|
0. | 0 | 2 | 1 | 0 |
1. | 0 | 2 | 3 | 1 |
2. | 0 | 2 | 5 | 4 |
3. | 0 | 2 | 7 | 9 |
4. | 0 | 2 | 9 | 16 |
5. | 0 | 2 | 11 | 25 |
事实上,任意的多项式都可以进行类似的差分操作。对一个最高n次的多项式,我们每次差分会让其最高次减一,因此在经过n次差分操作后,其n次差分函数只有0次,即为一个常数,所以其更高次的差分函数均为0函数。
因此,我们只需知道函数/数列 $f(n)$ 的所有次差分函数在0处的值,即可求出 $f(n)$ 的值。
一些计算相关的问题
一些小技巧与正确性证明
定义 $ a_k = f_k(0) $
性质0
$ fk(n) = \sum{i = 0}^{n}(a_{i+k}*{n\choose i}) $
proof: 显然,对于不同的 $k$,$ fk(n) $ 的形式应当一致,仅仅是求和中初始下标不同。所以我们只需对 $ k = 0 $的情况进行数学归纳即可。( 此时由定义,$f_0(n) = f(n)$ )
对于 $ n = 0 $,显然,$ f(n) = a_0$ 成立
假设对 $ n = m $ 成立,
此时,对于 $ n = m + 1 $,由定义有 $ f(m+1) = f(m) + f_1(m) $。
代入 $ f_k(n) = \sum{i = 0}^{n}(a_{i+k}*{n\choose i}) $ ,
—————其中 $ {n\choose -1} = {n\choose n+1} = 0$。—————
因为 $ {n+1\choose i} = {n\choose i} + {n\choose i-1} $
因此,$ f(m + 1) = \sum_{i = 0}^{m+1} (a_i*{m+1\choose i}) $ ,即假设对 n = m + 1也成立。
由数学归纳法,对 $\forall n \in Z^{+}{\cup}{0}$,假设都成立
因此,性质0成立,
性质1
$ ak = \sum{i = 0}^k ( f(i) \ast ( -1)^{k-i} \ast {k\choose i} ) $
proof: 类似的,假如将0替换为n,我们只需简单地把求和中的 $f(i)$ 替换为 $f(i+n)$ 即可
假设对 $k = m$ 已经成立,则对 $k = m + 1$
则
同理0,我们可以将后两个组合数合并。
因此,假设对 $ k = m + 1 $ 也成立。
由数学归纳法,对 $\forall n \in Z^{+}{\cup}{0}$,假设都成立
因此,性质1成立。
性质0,1の运用
将性质0结合计算器/计算机,可以很快地由原函数 $ f(n) $ 求出差分机中对应寄存器的初始值。即使你可能并不知道 $ f(n) $ 的解析式,你仍然可以接这个差分机来大致预测其之后的走向。
而有时计算题里面如果给定了每个寄存器的值,你也可以通过性质1快速求出一定精度下的 $ f(n) $ 的解析式。
说白了就是为了应付题目,挣分数的事,不寒掺。
差分机二号
附注:更准确的原理请点击跳转
目前的差分器看似已经十分高效了的,但其原型是用纯机械实现的。
我们考虑一次差分机操作,即将寄存器的值加到下一个寄存器,可以用C++代码表示:
1 | int re[9]; //re[i]为第i个寄存器的值 |
然而,机械结构的加法并不是这么简单。其具体实现是靠齿轮的啮合,齿轮转过的齿数为齿轮的值。
设相邻的 齿轮a 和 齿轮b 的齿数分别为 x 和 y,因为ab啮合,所以a 和 b 转过的总齿数相同。
通过把 齿轮a 转动到0,即可实现齿轮b的值变为 x+y ,进而实现加法。
注意到在这个过程中,齿轮a的值丢失,所以睿智的巴贝奇先生又在两个寄存器间添加了中间齿轮,在齿轮转动的过程中和 齿轮b 保持同样的旋转,这样在 齿轮b 变为 x+y 后,该中间齿轮也会转过 x 齿。在完成加法后,我们只需让中间齿轮和已经被清0的齿轮a啮合,把中间齿轮转回 0 ,即可实现一次加法操作。
可以看出,在每次的加法操作中,需要同时占用相邻的两个齿轮(寄存器),因此一次差分机操作其实需要7步操作,每步操作使相邻的两个寄存器进行加法,这样效率比较低。
因此,我们可以考虑并行计算,注意到加法只会占用相邻的两个寄存器,我们可以在第一步让寄存器 2n-1 加到 2n 同时操作,第二步让寄存器 2n 加到 2n+1 同时操作,这样就可以只用两步就完成了加法。
相比第一种做法,并行计算提升了寄存器的平均占用率(原先操作每步骤占用率为 2/8,而后面的操作占用率第一步为8/8 第二步为6/8),加法操作的总数不变,但一步可以同时进行更多次加法,这样的效率提升是十分显著的,尤其对于机械结构。
具体实现可以看如下的表格:
我们先预处理成如下的阶梯阵
a[1] | a[2] | a[3] | a[4] | a[5] | a[6] | a[7] | a[8] | |
---|---|---|---|---|---|---|---|---|
0. | 0 | 0 | 1 | 0 | 1 | 0 | 2 | 0 |
1. | 1 | 1 | 1 | 1 | 2 | 2 | ||
2. | 2 | 2 | 3 | 4 | ||||
3. | 4 | 7 |
第一步后:
a[1] | a[2] | a[3] | a[4] | a[5] | a[6] | a[7] | a[8] | |
---|---|---|---|---|---|---|---|---|
0. | 0 | 0 | 1 | 0 | 1 | 0 | 2 | 0 |
1. | 0 | 1 | 1 | 1 | 1 | 2 | 2 | |
2. | 2 | 2 | 2 | 3 | 4 | |||
3. | 4 | 5 | 7 | |||||
4. | 12 |
第二步后:
a[1] | a[2] | a[3] | a[4] | a[5] | a[6] | a[7] | a[8] | |
---|---|---|---|---|---|---|---|---|
0. | 0 | 0 | 1 | 0 | 1 | 0 | 2 | 0 |
1. | 0 | 0 | 1 | 1 | 1 | 1 | 2 | 2 |
2. | 1 | 2 | 2 | 2 | 3 | 4 | ||
3. | 4 | 4 | 5 | 7 | ||||
4. | 9 | 12 |
可以看出,该计算方式的确可以加速机械结构的运算过程。
End
差分机简易版入门级介绍到此结束。可以看出,差分机的确是一个非常巧妙的机器,其诞生于19世纪早期,不仅巧妙借助齿轮实现了加法的计算,而且还利用了差分函数的性质来快速求出多项式函数的值。甚至对于某些非多项式函数,借助公式我们也能大致模拟其之后的走向。其在加法过程中还运用到了并行计算的思想,而这在计算机的雏形以及思想尚不存在的时代无疑是十分超前的。