数据圆整ROUNDUP|DOWN

圆整通常被理解为为满足某种要求而进行的数据修正。按照修正后的数据在数值上是否比原数据大,又可分为向上圆整和向下圆整。它们很像对模拟信号进行采样,对一定范围的数据向一个固定的数据靠拢。Linux内核中定义了面向整除的圆整计算宏。第一个叫做roundup。
#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
roundup类似于一个数学函数,它总是尝试找到大于x并接近x的可以整除y的那个数,也即向上圆整。那么为何内核不同是提供roundown宏定义呢?这是由于对于整型相除而言,所得的结果本身就是向下圆整的了。所以roundown可以很容易定义:
#define roundown(x, y) (((x) / (y)) * (y))
那么如何理解roundup的定义呢?看起来是尝试将(x) + ((y) - 1)的结果对y做向下取整,为何这样就可以实现x对y的向上取整呢?除法的本质在于对量的均分,那么观察下图:

图 133. 向上圆整算法证明

 

对于x = βy + δ来说,β>=0,y>0,并且0<=δ<y。因为y>0且为整数,那么0<=δ<y等价于0<=δ<=y-1。对于圆整运算来说,可以将x中可以整除y的部分βy提取出来,只对剩下的δ部分做圆整运算然后加上βy。同理这里对δ+y-1部分进行圆整,由于0<=δ<=y-1,得到y-1 <= δ + y-1 <= 2y-2。考虑两种情况: 当可以整除时,δ=0,也即取y-1,显然圆整值为0,也即不用向上圆整;而不可整除时,δ>0,所以y-1 < δ + y-1 <= 2y-2,又因为y为整数,所以y <= δ + y-1 <= 2y-2成立,由于y=1时符合第一种情况,所以只需考虑y>=2的情况。y==y并且2y-2在y>=2时>=y且<2y,所以保证δ + y-1的圆整值为1,也即不整除则要始终向上圆整。

一种更易被人理解的定义方式如下,它根据取余的结果计算圆整,由于整除的概率很低,所以这种算法每次都要多计算一次取余,而不能完全避免对除法的运算以消减取余算法的影响,它的效率要低。
#define roundup(x, y) ((x)%(y) ? ((x)/(y) + 1) * (y) : x)
一段如下的测试程序可以看到它的作用:
  int divisor = 0;
  printf("divisor\troundup\trounddown\n");
  for(; divisor < 5; divisor++)
	  printf("%d:\t%d\t%d\n", divisor, roundup(divisor, 2), roundown(divisor, 2));
输出结果如下:
divisor	roundup	rounddown
0:	0	0
1:	2	0
2:	2	2
3:	4	2
4:	4	4
内核提供的另一个宏DIV_ROUND_UP用来对除法的结果进行圆整,也即总是取大于n并接近n的那个数整除d后的结果。DIV_ROUND_UP类似于roundup,只是少了乘的动作,原理也是相同的。
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
DIV_ROUND_UP的处理结果如下:
0, 0
1, 1
2, 1
3, 2
4, 2
圆整可以通过除法实现,另一种实现方式是通过对低比特位进行清0操作,但是它们只适合对对齐到2的幂指数的操作有效。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值