取整取余(模)知多少?

本文介绍几种常见的整除取整方式,以及 % 运算问题。

一. 取整方式

以C语言为例,相信大多数同学都知道以下事实:

int a = 5, b = 2;
a / b;    // 答案为2,不是2.5

当 a, b都是整形变量时,相除的结果必定也是整形,所以 a / b 不会是 2.5,那么为什么结果是2,而不是3呢?

int a = 5, b = -2;
a / b;    // 答案为-2,不是-2.5

同样的,为什么答案是 -2 ,而不是 -3 呢?
要解决这个问题,我们首先要了解一下常见的几种取整方式。

1. 0向取整

int main()
{
	//本质是向0取整
	int i = -2.9;
	int j = 2.9;
	printf("%d\n", i); //结果是:-2
	printf("%d\n", j); //结果是:2
	return 0;
}

这种取整方式是C语言在整除或者整形截断的时候默认采取的取整方式,它的做法是将取整后的结果尽可能的靠近 0 。
向0取整
如 -2.9 取整后变成 -2 而非 -3 是因为 -2 比 -3 更加靠近 0。
从数值上看,这种取整方式就是直接抹去浮点数的小数位。
再次强调,向0取整是C语言默认的取整方式

2.向 -∞ 取整

#include <stdio.h>
#include <math.h>

int main()
{
	printf("%.1f\n", floor(-2.9));  //-3.0
	printf("%.1f\n", floor(-2.1)); //-3.0
	printf("%.1f\n", floor(2.9));  //2.0
	printf("%.1f\n", floor(2.1));  //2.0

	return 0;
}

这种取整方式就是让取整后的结果尽可能的小,又叫地板取整,C语言math库中 floor() 函数可以实现这种取整方式。
向负无穷取整

3.向 +∞ 取整

#include <stdio.h>
#include <math.h>

int main()
{
	printf("%.1f\n", ceil(-2.9)); //-2.0
	printf("%.1f\n", ceil(-2.1)); //-2.0
	printf("%.1f\n", ceil(2.9));  //3.0
	printf("%.1f\n", ceil(2.1));  //3.0
	return 0;
}

这种取整方式就是让取整后的结果尽可能的大,即靠近正无穷,C语言math库中 ceil() 函数可以实现这种取整方式。
向正无穷取整

4. 四舍五入取整

#include <stdio.h>
#include <math.h>

int main()
{
	printf("%.1f\n", round(2.1));   //2.0
	printf("%.1f\n", round(2.9));   //3.0
	printf("%.1f\n", round(-2.1));  //-2.0
	printf("%.1f\n", round(-2.9));  //-3.0
	return 0;
}

这种就是最为常见的四舍五入,同样的,math 库中的 round()函数可以实现。

下面给出一个汇总例子,可以帮助大家理解:

#include <stdio.h>
#include <math.h>

int main()
{
	const char * format = "%.1f \t%.1f \t%.1f \t%.1f \t%.1f\n";
	printf("value\tround\tfloor\tceil\ttrunc\n");
	printf("-----\t-----\t-----\t----\t-----\n");
	printf(format, 2.3, round(2.3), floor(2.3), ceil(2.3), trunc(2.3));
	printf(format, 3.8, round(3.8), floor(3.8), ceil(3.8), trunc(3.8));
	printf(format, 5.5, round(5.5), floor(5.5), ceil(5.5), trunc(5.5));
	printf(format, -2.3, round(-2.3), floor(-2.3), ceil(-2.3), trunc(-2.3));
	printf(format, -3.8, round(-3.8), floor(-3.8), ceil(-3.8), trunc(-3.8));
	printf(format, -5.5, round(-5.5), floor(-5.5), ceil(-5.5), trunc(-5.5));
	return 0;
}

结果
注:trunc()函数也可实现向0取整。

二. % 运算

1.概念

如果a和d是两个自然数,d非零,可以证明存在两个唯一的整数 q 和 r,满足 a = q*d + r , q 为整数,且0 ≤ |r| < |d|。其中,q 被称为商,r 被称为余数。
此概念非常重要,一些特殊的取模/余情况都要依据此概念才能得到合理的解释。
看例子
(1) 10 % 3 == 1
解释:10 = 3 * 3 + 1,故 3 是商,1 是余数。

(2) -10 % 3
C语言:-1
解释:-10 = 3 * (-3) + (-1) 故 -3 是商,-1是余数。
Python: 2
解释:-10 = 3 * (-4) + 2 故-4是商,2是余数。
Python测试
对于这个例子,我们可以看到,C和Python的解释都符合我们的定义,那么到底是什么形成了这种差异呢?

2.取模和取余的差别

取模和取余大多数情况下是一样的,可是在某些特殊的情况下还是有些差别的。
本质:
取余:尽可能让商,进行向0取整。
取模:尽可能让商,向-∞方向取整。

本质差别就是,商的取整方式不同!!
由上述 -10 % 3 例子,我们可以看到 C 默认取整方式是向0取整,而Python默认向负无穷取整,而根据定义,才导致 -10 % 3在C和Python中结果不同。
我们也可以这么说:
C中 % ,本质其实是取余。
Python中 % ,本质其实是取模。
请注意,无论是C的向0取整,还是Python的向负无穷取整,在除数和被除数符号相同(即商是正数)的情况下都是一样的,即此时,取模等价于取余!,所以我们平时使用并未感觉到差异,因为除数和被除数符号不同的情况的确很少见。

3.总结

上面讲了这么多,那么假如我们遇到了一些特殊情况,如何计算 % 的结果呢?
1.求出商(小数)
第一步,我们首先不考虑取整的情况,直接先计算出,如 10 / (-3) == -3.333333
2.考虑如何取整
第二步,根据语言特性对所得商进行取整,如在C语言中采用向0取整,即 -3.333333取整后为-3。
注:如果不清楚语言取整方式,可以进行一下简单的测试。
3.根据公式 a = q*d + r 计算出 % 的结果
第三步,套公式。如10%(-3),我们在第二步已经得出 q = 10 / (-3) = -3。
由 10 = (-3)*(-3) + r 得出 r = 1,故 C语言中 10 % (-3) == 1。大家可依照此方法自行退到一下Pyhton中 10 % (-3) 的值。

其实说了这么多,总的来说就是一句话,对于模除余运算,取整方式绝对一切! ,一般语言的默认取整方式基本上都是向0取整或向负无穷取整。只要我们将该语言默认取整方式搞清楚,在根据公式,我们就可以轻易得出 % 运算的结果。

笔者水平有限,若有大佬指出错误或不足之处,笔者感激不尽!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值