【C语言笔记】【宏定义系列】 四舍五入除法

【C语言笔记】【linux宏定义系列】 四舍五入除法 DIV_ROUND_CLOSEST

linux宏定义系列内容。用于记录在linux之中各式各样的宏定义☺。

宏定义说明

用于除法运算,将正或负的被除数除以正的除数,得到的结果会四舍五入到最接近的整数。

例如 4 ÷ 10 = 0 4 \div 10 = 0 4÷10=0 5 ÷ 10 = 1 5 \div 10 = 1 5÷10=1 47 ÷ 5 = 9 47 \div 5 = 9 47÷5=9 47 ÷ 5 = 10 47 \div 5 = 10 47÷5=10

该宏定义来自linux kernel 3.10。

实现代码

#define DIV_ROUND_CLOSEST(x, divisor)(			\
{							\
	typeof(x) __x = x;				\
	typeof(divisor) __d = divisor;			\
	(((typeof(x))-1) > 0 ||				\
	 ((typeof(divisor))-1) > 0 || (__x) > 0) ?	\
		(((__x) + ((__d) / 2)) / (__d)) :	\
		(((__x) - ((__d) / 2)) / (__d));	\
}							\
)

宏定义中:

x表示被除数,被除数可以是正数或者负数。

divisor表示除数,除数只能是正数。

注意:如果被除数是负数,那么除数divisor的变量类型不能是无符号的,否者结果是未定义的。

示例程序

int main(int argc, char* argv[])
{
    int x, y;

    x = 4;
    y = 5;
    printf("x %d y %d result %d\n", x, y, DIV_ROUND_CLOSEST(x, y));
    
    x = 2;
    y = 5;
    printf("x %d y %d result %d\n", x, y, DIV_ROUND_CLOSEST(x, y));
    
    x = -4;
    y = 5;
    printf("x %d y %d result %d\n", x, y, DIV_ROUND_CLOSEST(x, y));
    
    x = -2;
    y = 5;
    printf("x %d y %d result %d\n", x, y, DIV_ROUND_CLOSEST(x, y));
    
    return 0;
}

运行后,结果为

x 4 y 5 result 1
x 2 y 5 result 0
x -4 y 5 result -1
x -2 y 5 result 0

实现过程

  1. typeof(x) __x = x;
    typeof(divisor) __d = divisor;

    使用一个与传入的参数相同数据类型的临时变量来保存参数的值,避免类似于自增或自减带来的影响。

  2. (((typeof(x))-1) > 0 || \ ((typeof(divisor))-1) > 0 || (__x) > 0)

    这个里面有三个部分

    1. ((typeof(x))-1) > 0用来判断被除数的类型。

      x为有符号数时,将-1强制转换成typeof(x)类型,这个值还是负数,不会大于0,((typeof(x))-1) > 0的结果为假,也就是为0;

      x为无符号数时,将-1强制转换成typeof(x)类型,这个值会变成正数,值会大于0,((typeof(x))-1) > 0的结果为真,也就是为1;

    2. ((typeof(divisor))-1) > 0用来判断除数的类型。

      方式同上。当divisor为有符号数时,结果为假;当divisor为无符号数时,结果为真。

    3. (__x) > 0)用来判断被除数的值是否大于0。

    上面三种情况,任意一种大于0,就执行(((__x) + ((__d) / 2)) / (__d)),否者就执行(((__x) - ((__d) / 2)) / (__d))

  3. (((__x) + ((__d) / 2)) / (__d))
    (((__x) - ((__d) / 2)) / (__d))

    x的类型为无符号数,或者当divisor的类型为无符号数,再或者被除数__x的值大于0时,执行(((__x) + ((__d) / 2)) / (__d))。能运行这句,就表示被除数与除数都是正数。这里__x先加上(__d) / 2,再除以__d,这样结果就会四舍五入到最接近的整数。这与正常的除法区别就是被除数要先加上除数的一半。为什么要先加上除数的一半,这是因为,如果需要向下舍入的数,加上除数的一半,除法的结果还是一样的,比如正常除法运算4 / 10 = 0,如果加上除数的一半,变为(4 + 10/2) / 10 = (4 + 5) / 10 = 9 / 10 = 0,结果不变;而需要向上取整的数,加上除数的一半,除法的结果会加1,比如正常除法运算5 / 10 = 0,如果加上除数的一半,变为(5 + 10/2) / 10 = (5 + 5) / 10 = 10 / 10 = 1,实现向上取整。

    x的类型为有符号数,并且divisor的类型为有符号数,同时被除数__x的值小于等于0时,执行(((__x) - ((__d) / 2)) / (__d))。能运行这句,就表示被除数为负数,而除数是正数。这里__x先减去(__d) / 2,再除以__d,这样结果就会四舍五入到最接近的整数。原因与上面相同,但是由于被除数为负数,所以加上(__d) / 2变为了减去(__d) / 2

[参考资料]

linux kernel 3.10

/include/linux/kernel.h

【GNU笔记】【C扩展系列】用typeof来引用一个类型 Referring to a Type with typeof


本文链接:https://blog.csdn.net/u012028275/article/details/118864192

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值