1. 数学规则:
对于任意两个正整数 X, Y,假设Y>=X, 总是存在两个整数 q /*Quotient缩写*/, r /*Remainder缩写*/ 使得
等式 Y = q*X + r 成立, 要求 0 <= r < X, 则q(商), r(余数) 是唯一确定的。
商: q = [Y/X] /*[]:取整函数*/
余数: r = Y - q*X 推倒出 r = Y - [Y/X]*X.
2. 自定义规则:
定义一种Y的取值规则,要求让Y是能整除X,且是最接近X的整数
2.1 地板法:
若 0 =< r < X, 取 Y = q*X,
c语言为我们提供整形除法,所以地板法容易实现: q = Y/X /*取商*/, r = Y%X /*取余数*/
必杀技巧:如果X值恰巧是2^n,那么直接左移n位 q = Y >> n , r = Y&(X-1);
2.2 天花板法:
若 0 < r <= X, 取 Y = (q+1)*X.
3. 现在我们问题是,如何利用C语言实现这个天花板法?
Y X x/y x%y 地板 天花板
0 -> 5 -> 0 -> 0 -> 0 -> 5
1 -> 5 -> 0 -> 1 -> 0 -> 5
2 -> 5 -> 0 -> 2 -> 0 -> 5
3 -> 5 -> 0 -> 3 -> 0 -> 5
4 -> 5 -> 0 -> 4 -> 0 -> 5
5 -> 5 -> 1 -> 0 -> 5 -> 5
6 -> 5 -> 1 -> 1 -> 5 -> 10
7 -> 5 -> 1 -> 2 -> 5 -> 10
8 -> 5 -> 1 -> 3 -> 5 -> 10
9 -> 5 -> 1 -> 4 -> 5 -> 10
10 -> 5 -> 2 -> 0 -> 10 -> 10
11 -> 5 -> 2 -> 1 -> 10 -> 15
12 -> 5 -> 2 -> 2 -> 10 -> 15
13 -> 5 -> 2 -> 3 -> 10 -> 15
14 -> 5 -> 2 -> 4 -> 10 -> 15
15 -> 5 -> 3 -> 0 -> 15 -> 15
16 -> 5 -> 3 -> 1 -> 15 -> 20
17 -> 5 -> 3 -> 2 -> 15 -> 20
18 -> 5 -> 3 -> 3 -> 15 -> 20
19 -> 5 -> 3 -> 4 -> 15 -> 20
20 -> 5 -> 4 -> 0 -> 20 -> 20
21 -> 5 -> 4 -> 1 -> 20 -> 25
直接让商Q = Y/X + 1行不行?
地板法:
Y = {0,1,2,3,4} => q = 0 则 Q = 1
Y = 5 => q = 1 则 Q = 2
很明显不是我们想要的结果,我们希望Y = 5,Q = 1
所以
商Q = (Y-1)/X + 1
Y=Q*X=((Y-1)/X + 1)*X = (Y+X-1)/X*X
4.证明过程:
ceiling的除法运算是只要余数不为0,商要进1,对于整型的Y/X而言只需Y+其最大的余数即可既ceiling = (Y+最大的余数)/X
4.1 证明方法1:
首先按照地板除Y/X,我们只能得到地板值,然后余数是r(从0到X-1),
现在我们要求用地板除规则实现天花板除,那么势必要给Y值的基础上加上X,再地板除(Y+X)/X,这样商能多加1,注意此时余数不发生改变,仍为(0,1,2...X-1)
但是天花板除法又规定,就是(Y+X)/X整除时,商不进位,那么我们让Y+X再减去1,即(Y+X-1)/X,则余数为(-1,0,1,2...X-2),原来余数为1的位置对应的数,现在整除了.也就是按照地板除规则,余数位(0,1,2...X-2),所对应的商都为0,至于-1对应的数,也就是原来能整除的数,已经去到上一轮了.
当Y=nX时,(Y+X-1)/X=>(nX+X-1)/X不进位,
当Y=nX+1时,(Y+X-1)/X=>(nX+1+X-1)/X=>n+1
...
当Y=nX+X-1时 (Y+X-1)/X=>(nX+X-1+X-1)/X=>n+1
当Y=nX+X时 (Y+X-1)/X=>(nX+X+X-1)/X=>n+1
4.2 证明方法2:
这也相当于把 Y 表示为:
Y = q'*X + r', 其中 -X < r' <=0 //最大非正剩余
q'*X 是我们所求。
关键是如何用 c 语言计算它。由于我们能处理标准的带余除法,所以可以把这个式子转换成一个标准的带余除法,然后加以处理:
已知 Y = q'*X + r', 其中 -X < r' <=0
则 Y+X = q'*X + (X+r'),其中 0 < X+r' <= X //最asx大正剩余
则 Y+X-1 = q'*X + (X+r'-1), 其中 0 <= X+r'-1
其中 q' = [(Y+X-1)/X] 推倒出 q' = [(Y-1)/X] +1
5.用C语言计算(Y+X-1)/X*X
若 X 是 2 的方幂, 比如 2^m,则除为右移 m 位,乘为左移 m 位。
所以
(Y+X-1)/X : 相当于右移 m 位
(Y+X-1)/X*X : 相当于将上面的值再左移m位,也等价于将最低 m 个二进制位清0
上面两句等价于
(Y+X-1) & (~(X-1))
假设X = 8 = 0b1000,则 X-1 = 0b0111,~(X-1) = 0b111...11000
这样再与原来的值相与就清零了.
6.这种算法主要可以用到内存对齐上
如果数据总线是32根,那么每次只能取到4个字节的数据,可以使用该法方法,让地址总线每次都指向4的倍数的地址,