C/C++除法实现方式及负数取模详解

一、下面的题目你能全做对吗?

1.7/4=?

2.7/(-4)=?

3.7%4=?

4.7%(-4)=?

5.(-7)/4=?

6.(-7)%4=?

7.(-7)/(unsigned)4=?

答案:

1

-1

3

3

-1

-3

1073741822

如过你全部答对,你可以无视后面的内容……

二、除法的取整分类

除法的取整分为三类:向上取整、向下取整、向零取整。

1.向上取整:向+∞方向取最接近精确值的整数。在这种取整方式下,7/4=2,7/(-4)=-1,6/3=2,6/(-3)=-2

2.向下取整:向-∞方向取最接近精确值的整数。在这种取整方式下,7/4=1,7/(-4)=-2,6/3=2,6/(-3)=-2

3.向零取整:向0方向取最接近精确值的整数,换言之就是舍去小数部分,因此又称截断取整。在这种取整方式下,7/4=1,7/(-4)=-1,6/3=2,6/(-3)=-2

通过观察可以发现,无论是向上取整还是向下取整,(-a)/b==-(a/b)都不一定成立。这给程序设计者带来了极大的麻烦。而对于向零取整,(-a)/b==-(a/b)是成立的,以此,C/C++采用这种取整方式。

三、负数取模

回想小学的公式:被除数÷除数=商……余数。

由此可知,余数=被除数-商×除数 (*)

对C/C++而言,(*)式依然成立。并且,该式是解决负数取模问题的关键。

例一:7%(-4)=?

解:由C/C++向零取整的整除方式可知,7/(-4)=-1;由(*)式知,余数=7-(-4)*(-1)=3.所以,7%(-4)=3

例二:(-7)%4=?

解:由C/C++向零取整的整除方式可知,(-7)/4=-1;由(*)式知,余数=(-7)-4*(-1)=-3.所以,(-7)%4=-3

例三:(-7)%(-4)=?

解:由C/C++向零取整的整除方式可知,(-7)/(-4)=1;由(*)式知,余数=(-7)-(-4)*1=-3.所以,(-7)%(-4)=-3

四、相关知识的拓展

1.对于有符号整数与无符号整数间的除法,C/C++会将有符号整数转换为无符号整数,需要特别注意的是,符号位并没有丢失,而是变成了数据位参与运算。这就是(-7)/(unsigned)4不等于-1,而等于1073741822的原因。

此处原创:这里为啥呢。两个不同符号位的数进行运算,需要转换成同一个符号位的数,有个规则,如果无符号的数大于等于有符号的数,那么将有符号位的数转换成无符号的,如果无符号的数小于有符号的数,那就要看编译器了。假设int是32位,那么可以表示的最大就是4294967296,这时候,用-7对这个数取模,得到4294967289,这就是转换后得到的无符号位的数,然后再用这个数除4,就是1073741822,余数是1

2.编译器对除法的优化

①在“无优化”条件下,编译器会在不影响正常调试的前提下,对除法进行简单的优化。

A.“常量/常量”型除法:编译器会直接计算出结果。

B.“变量/变量”型除法:无优化。

C.“变量/常量”型除法:若常量≠2^n,无优化;否则,除法将被转换为右移运算。由于由右移运算实现的整除实质上是向下取整,所以编译器会通过一些附加的指令在不产生分支结构的情况下将向下取整转换为向零取整。

以【变量/2^3】为例,反汇编代码如下:

mov eax,被除数

cdq ;若eax<0,则edx=0xFFFFFFFF;否则edx=0

and edx,7 ;若eax<0,则edx=7;否则edx=0

add eax,edx ;若eax<0,【(eax+7)/(2^3)】向下取整的值 与 【eax/(2^3)】向零取整的值相等,从而实现向零取整

sar eax,3 ;右移,完成除法

②在“O2优化”条件下,“变量/常量”型除法中,常量若≠2^n,也可以优化。此时,除法将被转换为乘法与右移的结合形式。例如,a/b=a*(1/b)=a*((2^n)/b)*(1/(2^n)),其中,((2^n)/b为MagicNumber,由编译器在编译过程中算出。这样a/b就变成了(a*MagicNumber)>>n,n的值由编译器选取。需要注意的是,本公式只是除法优化中的一个典型代表,编译器会根据除数对公式进行调整,但基本形式与原理是类似的。

原文地址:https://www.cnblogs.com/wxmwanggood/p/9323238.html

时间: 2024-08-04 16:13:11

C/C++除法实现方式及负数取模详解的相关文章

【转】C/C++除法实现方式及负数取模详解

原帖:http://blog.csdn.net/sonydvd123/article/details/8245057 一.下面的题目你能全做对吗?1.7/4=? 2.7/(-4)=? 3.7%4=? 4.7%(-4)=? 5.(-7)/4=? 6.(-7)%4=? 7.(-7)/(unsigned)4=? 答案: 1 -1 3 3 -1 -3 1073741822 如过你全部答对,你可以无视后面的内容-- 二.除法的取整分类除法的取整分为三类:向上取整.向下取整.向零取整. 1.向上取整:向+∞

C++负数取模

预习: r=余数 a=被除数 b=除数 c=商 a/b=c........r r=a-(a/b)*b 一.下面的题目你能全做对吗?1.7/4=?2.7/(-4)=?3.7%4=?4.7%(-4)=?5.(-7)/4=?6.(-7)%4=?7.(-7)/(unsigned)4=?答案:1-133-1-31073741822如过你全部答对,你可以无视后面的内容…… 二.除法的取整分类除法的取整分为三类:向上取整.向下取整.向零取整.1.向上取整:向+∞方向取最接近精确值的整数. 在这种取整方式下,7

CodeForces 450B (矩阵快速幂模板题+负数取模)

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=51919 题目大意:斐波那契数列推导.给定前f1,f2,推出指定第N项.注意负数取模的方式:-1%(10^9+7)=10^9+6. 解题思路: 首先解出快速幂矩阵.以f3为例. [f2]  * [1 -1] = [f2-f1]=[f3]  (幂1次) [f1]  * [1  0]     [f2]      [f2] 于是fn=[f2] *[1 -1]^(n-2)

负数取模

本文转载于:http://blog.sina.com.cn/s/blog_6f5c63ff0100tucb.html 我们知道,在不同的语言中,对负数执行取模运算,结果有可能会是不同的.例如,(-11)%5在python中计算的结果是4,而在C(C99)中计算的结果则是-1. truncate除法 && floor除法 在大多数编程语言中,如果整数a不是整数b的整数倍数的话,那么a.b做除法产生的实际结果的小数部分将会被截除,这个过程称为截尾(truncation).如果除法的结果是正数的

python中的负数取模问题(一个大坑)

先来看一段代码 这是什么情况?为什么会出现这种结果.我们再来看看其它语言的执行结果 我们用golang.js.c分别算了一下,结果得到的结果都是一致的,但是python为啥不一样呢? 其实之所以这么做是python有意而为之,因为python对于正负号不同的两个值的除法处理方式和其它流行语言不一样.这就要考虑到机器是如何计算商和余数的,以10 % 3为例,先算10 / 3 = 3.333,然后取整得到3,也就是商,然后10 - 3 * 3=1,因此对于两个正数相除是没有疑问的,一样的结果. 但是

信息安全-3:负数取模[转]

背景 最近在一道 Java 习题中,看到这样的一道题: What is the output when this statement executed:System.out.printf(-7 % 3); 正整数的取余运算大家都很熟悉,但是对于负数.实数的取余运算,确实给人很新鲜的感觉.于是我对此进行了一些探索.我发现,这里面还是颇有一点可以探索的东西的. 探究 首先,看看自然数的取模运算(定义1): 如果a和d是两个自然数,d非零,可以证明存在两个唯一的整数 q 和 r,满足 a = qd +

(转)Altium Designer PCB网络连接方式Port和Net Label详解

1.图纸结构      图纸包括两种结构关系: 一种是层次式图纸,该连接关系是纵向的,也就是某一层次的图纸只能和相邻的上级或下级有关系:另一种是扁平式图纸,该连接关系是横向的,任何两张图纸之间都可以建立信号连接. 2.网络连接方式      Altium Designer提供了6类网络标识:Net Label(网络标号),Port(端口),Sheet Entry(图纸入口),Power Port(电源端口),Hidden Pin(隐匿引脚).Off-sheet Connector(图纸外连接符)

【转】Android 定时器实现的几种方式和removeCallbacks失效问题详解--不错

原文网址:http://blog.csdn.net/xiaanming/article/details/9011193 实现定时器有很多种方式,在这里我简单的介绍几种方式 (1)使用Handler + Runnable的方式 [java] view plaincopy Handler handler = new Handler(); Runnable runnable = new Runnable() { @Override public void run() { //你要做的事 //.....

Apache中3种MPM工作方式的区别及配置详解

MPM是Multi-Processing Modules,表示Apache中的多路处理模块,目前在Linux上的Apache2.2/2.4中包括三种模式:prefork.worker和event模式.apache或httpd的命令参数"-l"即可列出当前apache中已经编译了的模块,由于MPM只能在编译时指定其中一种,所以列出的静态模块中MPM只有1个,如下所示: # httpd -l Compiled in modules: core.c prefork.c    #说明使用的是p