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

转载 2016年05月30日 11:00:21
一、下面的题目你能全做对吗?
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的值由编译器选取。需要注意的是,本公式只是除法优化中的一个典型代表,编译器会根据除数对公式进行调整,但基本形式与原理是类似的。


警惕C++中整数除法计算的精度损失

很偶然发现了一个精度损失的问题,简单来说: 有表达式: l = i/30 + j/40 + k/25, 求当{i,j,k} = {50,85,27}时l的值,很简单,用计算器马上可以算出答案为4...
  • ghevinn
  • ghevinn
  • 2014年06月17日 18:00
  • 7348

C++除法

分两种情况,一是操作数都是整型,那么运算结果也是整型,会舍去小数部分,相当于取(整型)商.二是有一个操作数为浮点数,运算结果就会保留小数部分,此时才算真正的除法. 例如,要计算2个double类...
  • ZK_J1994
  • ZK_J1994
  • 2017年05月21日 22:04
  • 545

C/C++整数除法以及保留小数位的问题

题目描述 Given two postive integers A and B,  please calculate the maximum integer C that C*B≤A, and t...
  • Lv_Victor
  • Lv_Victor
  • 2015年11月28日 22:11
  • 12487

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

http://blog.csdn.net/sonydvd123/article/details/8245057 一、下面的题目你能全做对吗? 1.7/4=? 2.7/(-4)=? 3....
  • littlestream9527
  • littlestream9527
  • 2013年06月28日 11:32
  • 2900

C语言:正负数之间取模运算

如果 % 两边的操作数都为正数,则结果为正数或零;如果 % 两边的操作数都是负数,则结果为负数或零。C99 以前,并没有规定如果操作数中有一方为负数,模除的结果会是什么。C99 规定,如果 % 左边的...
  • ProgBelief
  • ProgBelief
  • 2010年12月01日 20:48
  • 4399

c笔试面试 之 不用除法操作实现两个正整数的除法

正整数X,Y来表示 本题有两种解法: ①用减法实现: 大致思想是, while(X >Y) { count++; X = X - Y; } ②移动操作 位运算知识: 一、常用等式  -n = ~n...
  • yezifayale
  • yezifayale
  • 2014年03月19日 20:58
  • 1128

超大整数出除法的C语言实现

  • 2007年12月16日 02:28
  • 468KB
  • 下载

负数的除法和取模运算(Python 2.7和C的比较)

一、除法: 除法的取整分为三类:向上取整、向下取整、向零取整。  1.向上取整:向+∞方向取最接近精确值的整数。在这种取整方式下,5 / 3 = 2, -5 / -3 = 2, -5 / 3 = ...
  • u010388829
  • u010388829
  • 2015年06月18日 17:24
  • 602

详解负数取模运算

有人如果在python上使用%运算,肯定会遇到这样的问题,就是它在负数上的结果和我们之前在C或JAVA上的结果不一样。比如: -6 % 5这个运算,在python中的结果是4,但是在C/JAVA上的结...
  • hk2291976
  • hk2291976
  • 2016年10月10日 10:29
  • 2323

负数取模运算

最经在学习运算符时,遇到了负数取模(求余数)的问题。对于正数取模很简单,单复数取模不同的计算却有不同的答案。在网上看了一篇文档感觉总结的很详尽和大家共享 源地址:https://ceeji.net/b...
  • ao_xiaoqiang
  • ao_xiaoqiang
  • 2013年12月16日 20:40
  • 4595
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C/C++除法实现方式及负数取模详解
举报原因:
原因补充:

(最多只允许输入30个字)