向上取整再分析

先看两个简单的数学问题:

  1. 一个青蛙跳跃一次的长度为3,现在它垂直于马路方向要跳跃整条马路。假定马路的宽为x长? 问:它最少需要跳跃几次能够完全跳过这条马路?

  2. 一个房间可以住6个人,现在来了一群人,人数为x,问最少需要多少个房间才能让这x个人都可以住下? 假设一个房间住满的情况下,才安排另外一个房间。

问题分析:

假设马路的长度是10,青蛙一次跳3,跳3次的距离是9 ,4次的距离是12,为了能完全跳过马路,需要跳跃4次

10/3 + 1 = 4

如果马路的长度是12,为了能完全跳过马路,需要跳跃4次:

12/3 = 4

如果马路的长度是13,需要5次才能完全过去:

13/3 + 1 = 5 

所以,这两个题目, 都是同样的道理,不难得出结论:

result = (x%n == 0) ? (x/n) : (x/n + 1)

三目运算可以解决此类问题,但针对此类问题有一个较为巧妙的算法公式, 分子是总量加上步长减去1 ,运算后的结果再去除以步长:

result =(x+n-1/ n

计算机中的整数运算是向下取整的,也就是如果能整除,没有余数,那结果正好;如果不能整除,有余数,就将余数舍弃,保留相除后的整数部分。但此时正好和我们想要的结果(向上取整)相差一,正确的结果需要加上这个一。

下面是对这个公式的分析:

  • 因为x/n的余数(计为z)总小于n,这样就能保证,余数(z + n-1) < 2n,所以z + (n-1)/n的值不是0就是1,如果z == 0z + (n-1)/n = 0 ,如果z > 0z + (n-1)/n = 1

  • 所以:result =(x+n-1)/ n,就能保证:如果x+n-1的余数等于n-1x/n刚好能够整除余数z0,向上取整不需要加1,如果x+n-1的余数大于n-1,那么x/n不能整除,有余数(z),向上取整就需要x/n + 1,这里的1就是(z+n-1)/n = 1

所以在C语言中,ceil函数可以使用以下公式:

int ceil(int x, int y) {
    return (x + y - 1) / y;
}

这个公式的原理和上面提到的一样,当x除以y时,如果x不能被y整除,那么向上取整后的结果应该是x除以y的商加上 1。

结合移位运算-实例分析

假设收到比特流157位,利用位运算如何得出占据多少个字节。

157 + 7 >> 3得到20字节:

// 157 +7 >> 3的二进制过程为:(用8位表示)10011101+      111
--------------
  10100000
       >>3
--------------
  00010100=20

对157/8向上取整的做法:157除以8,如果有余数就对结果+1。

这里位运算的思想是:除以8,在位运算中就是右移3位,丢掉最后的3位。因为是向上取整,所以如果最后3位中只要有一个1,就不能单纯地丢掉这3位。都需要将第四位+1,表现出来的形式就是+7。

看一下7的二进制表示就很明显了,7的二进制是0b111,如果某个数的最后3位只要有一个1,再加上7,那么最终都会进位导致这个数的最后第四位+1,实现了向上取整的效果。然后再右移3位,实现了除法的效果。


参考

向上取整

你可能感兴趣的:(算法)