一. 关于“取整”
首先谈谈关于数学取整的问题
1. 向0取整
C中的除法和取整规则都是向0取整,即所有小数都向 0 的方向取整:
示例:
#include <stdio.h> int main() { // C中的除法和取整规则都是向0取整 int i = -2.9; int j = 2.9; printf("%d\n", i); // -2 printf("%d\n", j); // 2 return 0; }
补充:C++11中有一个trunc(...)取整函数,作用就是向0取整
2. 向负无穷取整
使用 floor(...)函数,使得所有小数都向负无穷方向取整:
示例:
#include <stdio.h> #include <math.h> //因为使用了floor函数,需要添加该头文件 int main() { //本质是向-∞取整 printf("%f\n", floor(-2.9)); //-3 printf("%f\n", floor(-2.1)); //-3 printf("%f\n", floor(2.9)); //2 printf("%f\n", floor(2.1)); //2 return 0; }
3. 向正无穷取整
使用ceil(...)函数,使得所有小数都向正无穷方向取整:
示例:
#include <stdio.h> #include <math.h> int main() { // 本质是向+∞取整 printf("%f\n", ceil(-2.9)); //-2 printf("%f\n", ceil(-2.1)); //-2 printf("%f\n", ceil(2.9)); //3 printf("%f\n", ceil(2.1)); //3 return 0; }
4. 四舍五入式的取整
使用round(...)函数,可以完成对小数四舍五入式的取整:
#include <stdio.h> #include <math.h> int main() { //本质是四舍五入 printf("%f\n", round(2.1)); // 2 printf("%f\n", round(2.9)); // 3 printf("%f\n", round(-2.1));// -2 printf("%f\n", round(-2.9));// -3 return 0; }
二. 关于“取模”的本质
取模的定义如下:
如果a和d是两个自然数,d非零,可以证明存在两个整数 q 和 r,满足 a = q*d + r ,且0 ≤ |r| < |d|。其中,q 被称为商,r 被称为余数。
下面我们对比不同语言下负数取模的结果:
可以看到,在不同语言中计算同一个表达式,负数“取模”结果是不同的。我们可以分别称之为叫做正余数 和 负余数。
由上面的例子可以看出,具体余数r的大小,本质是取决于商q的。
而商,又取决谁呢?取决于除法计算的时候,取整规则。
Python的取整规则是向负无穷方向取整,所以先计算出来商是 -4,然后才得到余数是2
C语言的取整规则是向0取整,所以先计算出来商是 -3,然后才得到余数是1
三. 取余和取模的区别
经过上面的例子,我们已经知道了取模(余)的本质是要先计算出商是多少,而商的值取决于商的取整规则。
所以区余和取模的区别也体现在 商的取整规则 上:
取余:尽可能让商,进行向0取整
取模:尽可能让商,向-∞方向取整
所以:
C中%,本质其实是取余
Python中%,本质其实是取模
关于取模和取余的一个规律
同符号数据相除,得到的商,一定是正数,即大于0!
所以在对其商进行取整的时候,向0取整和向-∞方向取整的值都一样,这样子的话:取模的值 = 取余的值。