#include
int main() {
int a = 2.9;
int b = -2.9;
printf("%d\n", a);
printf("%d\n", b);
return 0;
}
结果是2和-2,大家应该是知道的,但是大家了解原理吗?看下面的图
C语言采取的就是上图所述的向0取整
取整函数trunc
采用的也是向0取整规则
#include
#include
int main() {
printf("%.1f\n", trunc(-2.1));
printf("%.1f\n", trunc(-2.9));
printf("%.1f\n", trunc(2.1));
printf("%.1f\n", trunc(2.9));
return 0;
}
#include
#include
int main() {
printf("%.1f\n", ceil(-2.1));
printf("%.1f\n", ceil(-2.9));
printf("%.1f\n", ceil(2.1));
printf("%.1f\n", ceil(2.9));
return 0;
}
结果好像都变大了
那是因为ceil
函数取整采用的规则是向+∞取整
#include
#include
int main() {
printf("%.1f\n", floor(-2.1));
printf("%.1f\n", floor(-2.9));
printf("%.1f\n", floor(2.1));
printf("%.1f\n", floor(2.9));
return 0;
}
结果又全都变小了
因为floor
函数取整采取的是向-∞取整
#include
#include
int main() {
printf("%.1f\n", round(-2.1));
printf("%.1f\n", round(-2.9));
printf("%.1f\n", round(2.1));
printf("%.1f\n", round(2.9));
return 0;
}
这结果有点像四舍五入
没错,round
函数取整采取的是四舍五入取整
浮点数(整数/整数),其实是有很多种取整方式的(四种),而C语言采取的是向0取整
先看一下取模的定义:
如果a和d是两个自然数,d非零,可以证明存在两个唯一的整数q和r,满足a = q * d + r 且0 <= r < d。其中q被称为商,r被称为余数。
看下面代码:
#include
int main()
{
int a = 10;
int b = 3;
printf("%d\n", a / b);
printf("%d\n", a % b);
return 0;
}
可以看到结果分别是3和1,此时还没有任何的问题。
#include
int main()
{
int a = -10;
int b = 3;
printf("%d\n", a / b);
printf("%d\n", a % b);
return 0;
}
再看结果,分别是-3和-1,这里有一点不对劲儿了,-3还好理解,但是-1好像跟定义不太符合,再继续往下看
在python中,正数的“取模”是1非常正确,但是负数的“取模”竟然是2,这好像太不对劲儿了吧,但是这个2是符合定义的。
从这里可以得出一点结论:关于取模的定义,并不能满足语言上的取模运算
因为在C语言中,余数出现了负数,这显然是不符合定义的,所以现在这里有了一个修订版的定义:
如果a和d是两个自然数,d非零,可以证明存在两个唯一的整数q和r,满足a = q * d + r 且0 <= |r| < |d|。其中q被称为商,r被称为余数。
有了这个新的定义,那么C中和python中的“取模”,就都能解释了。
解释C:-10 = (-3) * 3 + (-1)
解释python:-10 = (-4) * 3 + 2
我们一定要知道一点,余数一定是根据商来求得的,余数的变化随商的变化而变化。
那么上面C和python余数的不同肯定是由于商的不同而造成的,上图中也可以看出,C中负数的商是-3而python负数的商却是-4,那么这是为什么呢?
因为C和python遵守的取整规则不同,C遵守的是向0取整,而python遵守的是向-∞取整。
取余和取模并不能严格等价(虽然大部分情况差不多)
先看取整
取余:尽可能让商进行向0取整
取模:尽可能让商进行向-∞取整
所以
C中%,本质是取余
python中%,本质才是取模
理解链:
对任何一个大于0的数,对其进行向0取整或者-∞取整,取整方向是一致的。故取模等价于取余
对任何一个小于0的数,对其进行向0取整或者-∞取整,取整方向是相反的。故取模不等价于取余
而同符号数据得到的商一定是正数,所以此时取模也等价于取余。
通过对比实验,更加验证了,参与取余的两个数据,如果同符号,取模等价于取余。
#include
int main()
{
printf("%d\n", -10 / 3);
printf("%d\n", 10 / -3);
printf("%d\n", -10 % 3);
printf("%d\n", 10 % -3);
return 0;
}
通过结论可以看到:如果不同符号,参考之前的定义,余数的符号是和被除数的符号相同的。
然而真的是这样吗?
?????
这是怎么回事?
上面讲过了C语言中的求整规则是向0取整,而python中的取整规则是向负∞取整。
其实导致上图的二者之间的余数的符号的区别,也是由于C语言和python采取的取整规则不同。
-10 // 3 = -4 ,而-4*3=-12,所以余数是-10 - (-12) = 2,
10 // -3 = -4 ,而-4*-3=12,所以余数是10 - 12 = -2
结论:如果参与取余的两个数的符号不同,在采取向0取整的语言中(C语言、C++、Java),余数符号和被除数相同;而在采取向负∞取整的语言中(python),余数符号相对是无规则的,具体符号可根据公式倒退出来。