关于C语言的取模运算,也许你只了解正数取模,而从未接触过负数取模,本文就来分享一波C语言取整、取模和取余的个人学习经验与心得,希望对你有所帮助。

笔者水平有限,难免存在纰漏,欢迎指正交流。

关于取整

你真的了解取整么?那你知道有几种取整方式吗?

除了最常见的向0取整以外其实是是有很多的取整方式的。

向0取整

C语言中整数除法就是遵循这一取整方式。下面代码中浮点数字面量拷贝赋值时发生了隐式类型转换,向0取整。

#include<stdio.h>
int main()
{int i = -2.9;int j = 2.9;printf("%d\n", i); //结果是-2printf("%d\n", j); //结果是2return 0;
}

有一个trunc取整函数(C99),同作用。

​比如:

#include<math.h>
#include<stdio.h>
int main()
{int i = -2.9;int j = 2.9;printf("%f\n", trunc(i)); //结果是-2printf("%f\n", trunc(j)); //结果是2return 0;
}

floor取整

本质是向-∞取整,注意输出格式要不然看不到结果,比如:

#include <stdio.h>
#include <math.h> //因为使用了floor函数,需要添加该头文件
int main()
{printf("%.1f\n", floor(-2.9)); //结果是-3printf("%.1f\n", floor(-2.1)); //结果是-3printf("%.1f\n", floor(2.9)); //结果是2printf("%.1f\n", floor(2.1)); //结果是2return 0;
}

ceil取整

本质是向+∞取整,注意输出格式要不然看不到结果,比如:

#include <stdio.h>
#include <math.h>
int main()
{printf("%.1f\n", ceil(-2.9)); //结果是-2printf("%.1f\n", ceil(-2.1)); //结果是-2printf("%.1f\n", ceil(2.9)); //结果是3printf("%.1f\n", ceil(2.1)); //结果是3return 0;
}

round取整

本质是四舍五入取整,比如:

#include <stdio.h>
#include <math.h>
int main()
{printf("%.1f\n", round(2.1));//结果是2printf("%.1f\n", round(2.9));//结果是3printf("%.1f\n", round(-2.1));//结果是-2printf("%.1f\n", round(-2.9));//结果是-3return 0;
}

汇总例子

#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;
}

​接下来深度理解取余/取模运算。

C/C++Linux服务器开发高级架构师/C++后台开发架构师​免费学习地址

另外还整理一些C++后台开发架构师 相关学习资料,面试题,教学视频,以及学习路线图,免费分享有需要的可以自行添加:Q群:720209036 点击加入~ 群文件共享

关于取余和取模

你知道2/(-2),2%(-2)的值分别是多少吗?我们一点点来看。

取模运算的定义与引例

给出一个定义: 如果a和d是两个自然数,d非零,可以证明存在两个唯一的整数 q 和 r,满足 a = q*d + r 且0 ≤ r < d。其中,q被称为商,r 被称为余数,取模运算求取的就是这个余数r。 举个例子:

int main()
{int a = 10;int b = 3;printf("%d\n", a % b);//a = q*d + r => 10 = 3*3 + 1return 0;
}

结果显而易见会是1,那如果改成下面这样结果又会如何?

int main()
{int a = -10;//改成负数了int b = 3;printf("%d\n", a % b);return 0;
}

​而在python中结果却是完全不一样的:

>>> print(-10%3)
2
>>>

分析

很显然,前面关于取模运算的定义并不能较好地满足这两门语言上的取模运算。

因为在C语言中,-10%3出现了负数,而根据定义是应该满足 a = q*d + r 且0 ≤ r < d的,这就说明C语言中取模运算得到的余数,是不满足我们所谓的取模定义的——出现了r<0的情况。

故有了一个修订版的定义:

如果a和d是两个自然数,d非零,可以证明存在两个唯一的整数 q 和 r,满足 a = q*d + r , q 为整数,且0 ≤ |r|< |d|。其中,q 被称为商,r 被称为余数,取模运算求取的就是这个余数r。 有了这个新的定义,那么C或者Python中的取模运算,就都能解释了。

解释C: -10 = (-3) * 3 + (-1)

解释Python:-10 = (?)* 3 + 2,其中,可以推导出来(?)必须是-4,即-10 = (-4)* 3 + 2,才能满足定义,这也和下面-10//3的结果吻合。

>>>print(-10//3)
-4
>>>

所以,在不同语言,同一个计算表达式,负数取模运算结果是不同的。我们可以分别叫做正余数和负余数。

由上面的例子可以看出,具体余数r的大小,本质是取决于商q的。

而商,又取决于谁呢?取决于除法计算的时候的取整规则。

比如:在C中,10/(-3)的值向0取整,所以得到-3;而在python中,10/(-3)的值向-∞取整,所以得到-4

​取余和取模一样吗

注意我前面说的是取模运算,接下来才是取余和取模。

并不是完全严格等价的,虽然大部分情况下差不多(用的都是正数)。

取余或者取模,都应该要算出商,然后才能得出余数。

我们这里主要发掘一下二者的区别。

本质 1 取整

取余:尽可能让商进行向0取整。

取模:尽可能让商进行向-∞取整。

结合上面讲的例子,可知:

C中%,本质其实是取余。

Python中%,本质其实是取模。

操作数是正还是负是有差别的:

对任何一个大于0的数,对其进行向0取整和向-∞取整,取整方向是一致的,故此时取模等价于取余。

对任何一个小于0的数,对其进行向0取整和向-∞取整,取整方向是相反的,故此时取模不等价于取余。

​本质 2 符号

参与取模运算的两个数据,如果同符号,取模等价于取余。

因为同符号数据相除,得到的商,一定是正数,即大于0!故在对其商进行取整的时候,取模等价于取余。

那如果参与运算的数据符号不同呢?比如:

int main()
{printf("%d\n", -10 / 3); //结果:-3printf("%d\n\n", -10 % 3); //结果:-1  因为-10=(-3)*3+(-1)printf("%d\n", 10 / -3); //结果:-3printf("%d\n\n", 10 % -3); //结果:1  因为10=(-3)*(-3)+1return 0;
}

所以可以看出:如果两数符号不同,余数的求法参考之前定义,而余数符号与被除数相同。此时取余不等价于取模,因为符号不同的数据相除得到的商一定是负数,对商取整时取模和取余提供的方向相反。

但是,在python中却是这样:

>>> print(-10//3)
-4
>>> print(10//-3)
-4
>>> print(-10%3)
2
>>> print(10%-3)
-2
>>>

我们发现在这里余数符号与被除数的相反,why?

还记得前面讲过的规律吗?

具体余数r的大小,本质是取决于商q的。

而商,又取决于谁呢?取决于除法计算的时候的取整规则。

我们来看一个不怎么严谨的数学推导,理解一下即可:

重新看看定义:

如果a和d是两个自然数,d非零,可以证明存在两个唯一的整数 q 和 r,满足 a = q*d + r , q 为整数,且0 ≤ |r|< |d|。其中,q 被称为商,r 被称为余数。

a = q*d + r 变换成 r = a - q*d 变换成 r = a + (-q*d),我们重点讨论的是r的符号问题。

对于:x = y + z,这样的表达式,x的符号与|y|、|z|中更大的那一个数的符号一致,若是y和z互为相反数则x为0。

而r = a + (-q*d)中,|a|和|-q*d|谁大,取决于商q的取整方式(a和d固定 )。

C语言中是向0取整的,也就是q本身的绝对值是减小的。 如:

-10/3=-3.33... 向0取整 -3,a=-10 对应绝对值为|10|, -q*d=-(-3)*3=9 对应绝对值为|9|

10/-3=-3.33... 向0取整 -3,a=10 对应绝对值为|10|,-q*d=-(-3)*(-3)=-9 对应绝对值为|9|

所以-q*d的绝对值变小了,而且往往比a的绝对值要小,因此r的符号就取决于a的符号。

而python是向-∞取整的,也就是q本身的绝对值是增大的。 如:

-10/3=-3.33... 向-∞取整 -4,a=-10 对应绝对值为|10|, -q*d=-(-4)*3=12 对应绝对值为|12|

10/-3=-3.33... 向-∞取整 -4, a=10 对应绝对值为|10|, -q*d=-(-4)*(-3)=-12 对应绝对值为|12|

所以-q*d的绝对值都变大了,而且往往比a的绝对值要大,因此r的符号就取决于-q*d的符号,又因为我们这里一直在讨论的是不同符号的数据取余/取模,所以除数d的符号与被除数a的相反,并且得到的商q一定是负数,-q正好把负号抵消掉了,-q*d的符号就取决于d了,也就是说最终r的符号取决于d的符号,同时与a的符号相反。

结论:如果参与取余的两个数据符号不同,在C语言中(或者其他采用向0取整的语言如:C++,Java),余数符号与被除数的符号相同,而在python语言中(或者其他采用-∞取整的语言),余数符号与被除数的符号相反。

最后我们再看回最开始提到的问题:2/(-2),2%(-2)的值分别是多少?

int main()
{printf("%d\n", 2 / (-2)); //-1printf("%d\n", 2 % (-2)); //2=(-1)*(-2)+r,r就是0return 0;
}

参考资料

编辑切换为居中

添加图片注释,不超过 140 字(可选)

推荐一个零声教育C/C++后台开发的免费公开课程,个人觉得老师讲得不错,分享给大家:C/C++后台开发高级架构师,内容包括Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,立即学习

原文地址:[深入浅出C语言]理解取整、取余和取模 - 掘金

[深入浅出C语言]理解取整、取余和取模相关推荐

  1. 向上取整、向下取整与四舍五入(易理解版)

    关于取整.四舍五入 取整 向上取整 向下取整 四舍五入 关于向上取整和向下取整,一直有点晕晕的 特写一篇文章总结一下: 取整 分向下取整.向上取整 如上图所示,可以这么理解:数值处于两个整数之间, 向 ...

  2. python取整求余

    python取整求余 / 表示除法 // 表示除后取整 % 表示除后求余 i = 15 a = i/2 b = i//2 c = i%2 print(a,b,c) 输出: 7.5 7 1

  3. python中取整求余的计算步骤

    预备知识:取整分为向上取整.向下取整.向零取整. 首先必须知道 x%y等价于x-(( x//y ) * y )  ,这就是一个公式!!  这个x//y意思是x对y取整 比如python中(是向下取整, ...

  4. c 语言浮点数向上取整,(转)C/C++ 取整函数ceil(),floor(),向上取整,向下取整...

    #include  double floor(doublex); float floorf(floatx); long double floorl(long doublex); double floo ...

  5. 向上取整和向下取整(ceil、round)

    Floor and ceiling functions - Wikipedia Useful Properties of the Floor and Ceil Functions 0. 基础 向上取整 ...

  6. 向下取整数学符号_向上取整与向下取整

    向上向下取整函数数只会对小数点后面的数字不为零的数进行操作,要是给它一个整数 它就返回整数本身. 对小数不为零的数操作: 向上取整 不管四舍五入的规则 只要后面有小数前面的整数就加1 向下取整 不管四 ...

  7. 截断 四舍五入 进位php,PHP取整,四舍五入取整、向上取整、向下取整、小数截取 四舍五入是什么意思 四舍五入就是一个亿 excel数值四舍五...

    PHP取整数函数常用的四种方法: 1.直接取整,舍弃小数,保留整数:intval(): 2.四舍五入取整:round(): 3.向上取整,有小数就加1:ceil(): 4.向下取整:floor(). ...

  8. Oracle四舍五入,向上取整,向下取整

    用oracle sql对数字进行操作: 取上取整.向下取整.保留N位小数.四舍五入.数字格式化取整(向下取整): select floor(5.534) from dual; select trunc ...

  9. #python计算结果百位500向下取整,(0-499取000,500-999取500)

    !/usr/bin/env python coding:utf-8 计算结果百位500向下取整,(0-499取000,500-999取500) import math calc_Amount = fl ...

最新文章

  1. Python怎么利用多核cpu
  2. MySQL导入导出数据和结构
  3. SURF 特征检测及匹配
  4. EDIUS新建项目工程设置
  5. android text字体居中显示,Android Canvas的drawText()和文字居中方案
  6. 文巾解题 981. 基于时间的键值存储
  7. leetcode350. 两个数组的交集 II(hashmap)
  8. 数据科学 python_如何使用Python为数据科学建立肌肉记忆
  9. linux必备工具,Linux装机必备工具
  10. eclipse中的JSP项目连接mysql报错,找不到jdbc驱动,java项目却没问题
  11. MSP430程序库二UART异步串口
  12. 通俗易懂!视觉slam第七部分——四元数
  13. iOS开发过程中常见错误问题及解决方案
  14. 计算机国三网络技术,计算机国三网络技术.doc
  15. Git来回切换版本的时候,pom文件变黄,每次都需要重新添加到maven以及修改后文件不生效的解决方法
  16. 使用DX查看系统配置
  17. cppcheck 自定义规则_Cppcheck 用法-编码规范
  18. 通过Linux+SNMP+zabbix的实验理解SNMP协议
  19. hdmi接口有什么用_显示器有哪些接口?DP、HDMI、VGA、DVI有什么区别?
  20. ASP.NET MVC5 使用NPOI导出ExceL 返回浏览器下载

热门文章

  1. 分销商城小程序开发解决方案
  2. NAT(地址转换模式)
  3. 国产DSP,32位双核CPU,pin2pin替代TMS320F280049C,高频400MHz
  4. 怎么利用计算机教学,浅谈在课堂教学中如何应用信息技术
  5. 【游戏程序设计】三维游戏示例-战术竞技游戏Demo(二)
  6. 安卓IOS客户端调试webview页面的方法,支持实时预览
  7. 基层服务项目服务器一般几年,基层事业单位有5年服务期,期间可以提拔或调动吗?看完知道了!...
  8. 截图工具FastStone Capture 10.0官方简体中文版
  9. 金立手机android怎么关闭,金立手机软件卸不掉怎么办 金立手机软件卸不掉如何解决...
  10. 编码算法(URL编码和Base64编码)