热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

c/c++开发分享定点数和浮点数加减乘除运算详解【计算机组成原理】—真的建议收藏啊!!!

前言:      你知道计算机内部是如何进行加减运算的吗?可能你知道,那你知道计算机内部是如何进行乘除法运算的呢?肯定和我们十进制运算是不一

前言:

     你知道计算机内部是如何进行加减运算的吗?可能你知道,那你知道计算机内部是如何进行乘除法运算的呢?肯定和我们十进制运算是不一样的。当我查找资料的时候,发现除了书本很少有这样的知识点。所以我想和大家一起分享定点数和浮点数加减乘除运算的方法,一起在二进制的世界里面遨游吧~

     温馨小贴士,以下内容仅仅包含计算方法(手算和计算机内部表达部分均有),不含运算器数电知识哦。文章以下方思维导图来展开:

定点数和浮点数加减乘除运算详解【计算机组成原理】---真的建议收藏啊!!!


预备知识:

     在开始之前,我们要知道定点数移位运算的知识点,在我们日常生活中总是有移位的例子。例如1500cm转换成15m,这就是一个移位,在计算机内部,也是有移位的,但是计算机的位数是不变的,所以我们在进行移位操作的时候就要将空缺高位或者低位的数字用0或1补齐,而我们接下来介绍的运算也和移位是分不开的,所以这里就列出定点数的移位运算,至于为什么没有给出浮点数的移位运算,那是因为浮点数的移位运算是和阶码相挂钩的(并且伴随精度丢失),至于尾数部分和定点数的规则一致。

数的表达形式 码制 填补代码 备注
正数 原码、补码 0 不管是左移还是右移,填0即可
负数 原码 0 符号位不变,空位添加0即可
负数 补码

左移添0;

右移添1

 

     另外有符号数的移位称为算术移位无符号数的移位称为逻辑移位。逻辑移位的规则是:逻辑左移时,高位移出,低位添0;逻辑右移时,低位移出,高位添0。


一、定点加减法运算

(一)加法运算

1、有符号数的加法运算:

     补码加法运算的特点就是符号位要一起作为数的一部分参与运算,其次要在模2^(n+1)的意义下相加,超过2^(n+1)的进位要丢掉,也就是说符号位的进位要丢掉。例如:

定点数和浮点数加减乘除运算详解【计算机组成原理】---真的建议收藏啊!!!

     而对于单符号位的数和双符号位的数来说,加法法则依旧是一致的(符号位进位舍去)。它们的不同点在于:溢出判断不一样。

  • 单符号数溢出检测判断一:负负得正,正正得负,那么绝对溢出了呀!
  • 单符号数溢出检测判断方法二:最高位和符号位有且仅由一个进位时溢出,即当最高位有进位,而符号位无进位时,产生正溢;当最高位无进位,而符号位有进位时,产生负溢。
  • 双符号位溢出判断:两个符号位相异时,表示溢出;相同时,表示未溢出。

     至于无符号数的加法,和上面是一致的,所有的位数都参与运算。它的溢出判断逻辑也及其简单。从表面上看就是如果加法变大,减法变小才符合逻辑,如果不符合这个逻辑,那肯定是不对的。那么我们还有UOF = Sub 异或 Cout(这里Sub代表减法,如果是减运算,那么Sub = 1,如果是加运算,那么Sub = 0。Cout代表最高位进位),所以它的判断逻辑就是如果是加法的话,最高位有进位,那么溢出;减法的话,最高位没有进位,那么溢出。

 

(二)有符号数的减法运算

     减法无非就是加上这个数的补码的形式,即X补-Y补 = X补 + [-Y]补,其余的运算就和加法一致了。它的溢出判断和上面也是一致的。


二、定点乘除法运算

(一)乘法运算

1、手算乘法

     我觉得第一步至少要会手算乘法,所以我们一起来看看一个例子:

A = -0.1101  B = 0.1011,我们需要计算A*B的值,首先符号位单独处理,这里就知道是负数,数值部分就如图所示(例子来源网上,太懒不想画图了,哈哈哈):

定点数和浮点数加减乘除运算详解【计算机组成原理】---真的建议收藏啊!!!

     上面的手算我们可以观察出,被乘数A每次进行运算之后都是要左移的,当然你也可以看成是乘数B右移,然后它们得到的数相加就得到了乘法的结果。

 

2、原码计算

     手算%ignore_a_1%就会了吧,原码的话其实也就是符号位的话单独运算(即直接异或得出),数值部分就是如上的运算即可(当然你可能看到过竖式的计算,其实都是一样的,也很好理解)。例如:我们计算X = -0.1110和Y = 0.1101的原码乘积的时候,把符号位丢到一边计算,异或就为1,为负数。然后取绝对值,即X = 0.1110,Y = 0.1101,然后开始按照第一步的手算一般运算,就得到了-0.10110110,然后把我们的符号位加上就有1.10110110,这就是最后的答案。

 

3、补码计算

补码一位乘运算规则:

     有被乘数X和乘数Y,那么

  • 被乘数任意,乘数为正,和原码相乘是一致的。
  • 被乘数任意,乘数为负,乘数[Y]补去掉符号位和X补运算,操作和第一个相同,最后加上[-X]补校正即可。

     这里我们直接以例子的形式来看看,例如X = +0.0011 Y = -0.1011,求[X*Y]补(一看就是乘数为负的形式)。那么其实也是一样的,首先我们转换为补码形式,并且被乘数X以双符号位表示,乘数Y以单符号位表示(还要计算被乘数X的负数形式的补码)。那么[X]补 = 00.0011,[-X]补 = 11.1101,[Y]补 = 1.0101。之后也就是:让[X]补和[Y]补(注意,这里是去符号位的0.0101)相乘得到00.00001111,然后加上[-X]补,就得到了结果11.11011111。

     至于溢出的判断逻辑如下:

  • 有符号数乘积的高n位全0或全1就不溢出
  • 无符号数乘积的高n位全0则不溢出

 

(二)除法运算

(约定:小数定点除法,被除数绝对值小于除数;整数定点除法,被除数大于除数;除数不能为0,被除数不能为0)

1、手算除法

     对于手算除法来说,也是和我们小学所学的一致,但我们有几个约定的规则:首先商的符号单独计算,余数不动低位补0减去右移一位的除数。例如X = -0.1011, Y = 0.1101。求X / Y有:

定点数和浮点数加减乘除运算详解【计算机组成原理】---真的建议收藏啊!!!

     

2、原码除法

     原码相除时,商的符号位由两个符号位相加求得,商的数值位由两数的数值部分相除得到,也就是和上面的手算除法是一至的算法(当然,数值部分的计算用上面的手算是可以的,也可以用下面提到的恢复余数法和不恢复余数法,也就是计算机内部的计算)。

     这里用不恢复余数法做一个例子(算子在下面可以查看):

定点数和浮点数加减乘除运算详解【计算机组成原理】---真的建议收藏啊!!!

(这里不要奇怪哦,有些地方是余数左移然后再和除数进行计算,而我这里是用余数与右移的除数进行运算,其实本质都是一致的哦,我这里将除数右移计算,这样得到的余数就不需要矫正了)。

 

3、补码除法

     我们采用心算(计算机内部则是进行移位操作)的时候总是可以判断够不够减,不够就商0,够减商一再做处理。但是计算机内部是不能这么做的。前辈们想到了恢复余数法:机器先做减法,若余数为正,才知道够减;若余数为负,才知道不够减。不够减时必须恢复到原来的余数,以便继续往下运算,这就是恢复余数法。但恢复余数使除法过程困难,不容易控制。我们就采用不恢复余数法,也叫加减交替法。特点就是运算过程中如出现不够减,不必恢复余数,根据余数符号,可以继续往下运算。

恢复余数法规则(若有X除以Y,Ri为余数,Y*代表Y的绝对值)
 余数Ri>0,商1,2Ri-Y*
余数Ri<0,商0,Ri+Y*   恢复余数
不恢复余数运算规则
上商1  2Ri-Y*
上商0  2Ri+Y*

     因为恢复余数法缓慢复杂,所以大都采用不恢复余数法。在下面例子中一起来看看补码除法需要注意什么呢?

有如下算子:

定点数和浮点数加减乘除运算详解【计算机组成原理】---真的建议收藏啊!!!

定点数和浮点数加减乘除运算详解【计算机组成原理】---真的建议收藏啊!!!

    按照上面的步骤来说商符是自动形成的。接下来我们在例子中看看怎么计算(这里我使用单符号位,上面算子中说采用双符号位那是因为方便计算,但这里单符号位即可):

定点数和浮点数加减乘除运算详解【计算机组成原理】---真的建议收藏啊!!!

     你可能会很奇怪,为什么我只算到了第n步,而没有进行到n+1步计算,最后一位直接说“末位恒置1”就结束了。那是因为如果我们进行n+1次计算,到时候除不尽还需要对商值进行校正,而根据经验我们是知道末位恒置为1,所以这里就这样减少了计算和检验步骤了。


三、浮点加减法运算

     浮点数加减法运算其实很简单,总共就5步:对阶、尾数运算、规格化、舍入、溢出判断。

 1.运算步骤

    假设浮点数的阶码和尾数均用补码表示,在浮点加减运算时,为便于浮点数尾数的规格化处理和浮点数的溢出判断,阶码和尾数均采用双符号位表示。

    ①对阶,小阶向大阶对齐

    两个浮点数进行加减运算时,首先要使两个数的阶码相同,即小数点的位置对齐。若两个数的阶码相同,表示小数点的位置是对齐的,就可以对尾数进行加减运算。反之,若两个数的阶码不相同,表示小数点的位置没有对齐,此时必须使两个数的阶码相同,这个过程称为对阶。

    要对阶,首先应求出两个浮点数的阶码之差,即

    ΔE=[Ex]补-[Ey]补=[Ex]补+[-Ey]补

    若ΔE=0,表示两个浮点数的阶码相等,即[Ex]补=[Ey]补;若ΔE>0,表示 [Ex]补>[Ey]补;若ΔE<0,表示[Ex]补<[Ey]补。

    当ΔE≠0时,要通过浮点数尾数的算术左移或算术右移来改变阶码,使两个浮点数的阶码相等。理论上讲,既可以通过移位[Mx]补以改变[Ex]补来达到[Ex]补=[Ey]补,也可以通过移位[My]补以改变[Ey]补来达到[Ex]补=[Ey]补。但是,由于浮点数的尾数在算术左移的过程会改变尾数的符号位,同时,尾数在算术左移的过程中还会使尾数的高位数据丢失,造成运算结果错误。因此,在对阶时规定使小阶向大阶看齐,通过小阶的尾数算术右移以改变阶码来达到[Ex]补=[Ey]补,尾数每右移一位,阶码加1,其数值保持不变,直到两个浮点数的阶码相等,右移的次数等于ΔE的绝对值。

    ②尾数进行加法或减法运算

    对阶结束后,即可对浮点数的尾数进行加法或减法运算。不论是加法运算还是减法运算,都按加法进行操作,其方法与定点加减运算完全一样。

    ③结果规格化并进行舍入处理

    根据规格化浮点数的定义,当尾数用二进制补码表示时,规格化浮点数的尾数形式为00.1××…××11.0××…××。若浮点数的尾数不是这两种形式,则称之为非规格化浮点数,需进行浮点数的规格化。

    若浮点数的尾数形式为00.0××…××或11.1××…××,应利用向左规格化使其变为规格化浮点数,尾数每算术左移1位,阶码减1,直到浮点数的尾数变成规格化形式。

    若浮点数的尾数形式为01.××…××或10.××…××,表示尾数求和的结果发生溢出,应利用向右规格化使其变为规格化浮点数,尾数算术右移1位,阶码加1,此时浮点数的尾数就变成了规格化形式。

    在对阶或向右规格化时,尾数都要进行算术右移操作,为了保证运算结果的精度,运算过程中需保留右移中移出的若干位数据,称为保护位。在运算结果进行规格化后再按照某种规则进行舍入处理以去除这些数据。舍入处理就是消除保护位数据并按照某种规则调整剩下的部分,舍入处理总要影响到数据的精度。舍入处理的方法通常选用“0舍1入”法。

    ④判断溢出

    浮点数尾数的溢出可通过规格化进行处理,而浮点数运算结果的溢出则根据运算结果中浮点数的阶码来确定。若阶码未发生溢出,则表示运算结果未发生溢出;若阶码溢出,则需进行溢出处理。

    若阶码用双符号位补码表示,判断溢出的方法为:若阶码的双符号位相同,表示结果未发生溢出;若阶码的双符号位不相同,表示结果发生溢出。

 

    [例1]设两浮点数x=2001×(0.1101),y=2011×(-0.1010),在浮点数的表示格式中阶码占3位,尾数占4位(都不包括符号位)。阶码和尾数均采用含双符号位的补码表示,运算结果的尾数取单字长(含符号位共5位),舍入规则用“0舍1入”法,用浮点运算方法计算x+y、x-y。

    解:[x]浮=00001,00.1101  [y]浮=00011,11.0110

    ①对阶,小阶向大阶对齐

    ΔE=[Ex]补-[Ey]补=[Ex]补+[-Ey]补=00001+11101=11110

    x的尾数[Mx]补右移2位,阶码[Ex]补加2

    [x]浮=00011,00.0011(01)

    其中(01)表示[Mx]补右移2位后移出的最低两位数。

    ②尾数进行加法、减法运算

 

    即[x+y]浮=00011,11.1001(01)

      [x-y]浮=00011,00.1101(01)

    ③结果规格化并进行舍入处理

    和的尾数左移1位,阶码减1,采用“0舍1入”法进行舍入处理后,得

      [x+y]浮=00010,11.0011

    差已为规格化浮点数,采用“0舍1入”法进行舍入处理后,得

      [x-y]浮=00011,00.1101

    ④判断溢出

    和、差的阶码的双符号位均相同,故和、差均无溢出。

    所以x+y=2010×(-0.1101)

        x-y=2011×(0.1101)

 

[例2]设两浮点数x=2-011×(0.100101),y=2-010×(-0.011110),在浮点数的表示格式中阶码占3位,尾数占6位(都不包括符号位)。阶码和尾数均采用含双符号位的补码表示,运算结果的尾数取单字长(含符号位共7位),舍入规则用“0舍1入”法,用浮点运算方法计算x+y、x-y。

    解:[x]浮=11101,00.100101  [y]浮=11110,11.100010

    ①对阶,小阶向大阶对齐

    ΔE=[Exx]补-[Ey]补=[Ex]补+[-Ey]补=11101+00010=11111

    x的尾数[Mx]补右移1位,阶码[Ex]补加1

    [x]浮=11110,00.010010(1)

    其中(1)表示[Mx]补右移1位后移出的最低一位数。

    ②尾数进行加法、减法运算

 

    即[x+y]浮=11110,11.110100(1)

      [x-y]浮=11110,00.110000(1)

    ③结果规格化并进行舍入处理

    和的尾数左移2位,阶码减2,得

    [x+y]浮=11100,11.010010

    差已为规格化浮点数,采用“0舍1入”法进行舍入处理后,得

    [x-y]浮=11110,00.110001

    ④判断溢出

    和、差阶码的双符号位均相同,故和、差均无溢出。

    所以x+y=2-100×(-0.101110)

        x-y=2-010×(0.110001)


四、浮点乘除法运算

     浮点乘除法其实很简单,浮点数乘法:阶码相加、尾数相乘、结果规格化;浮点数除法:尾数调整、阶码求差、尾数相除

    1.运算步骤

    在浮点乘除运算时,为便于浮点数判断溢出和尾数进行阵列乘除运算运算,假设浮点数的阶码采用双符号位补码表示,尾数采用单符号补码或原码表示。

    浮点乘法、除法运算步骤如下:

    ①阶码相加减

    按照定点整数的加减法运算方法对两个浮点数的阶码进行加减运算。

    ②尾数相乘或相除

    按照定点小数的阵列乘除法运算方法对两个浮点数的尾数进行乘除运算。为了保证尾数相除时商的正确性,必须保证被除数尾数的绝对值一定小于除数尾数的绝对值。若被除数尾数的绝对值大于除数尾数的绝对值,需对被除数进行调整,即被除数的尾数每右移1位,阶码加1,直到被除数尾数的绝对值小于除数尾数的绝对值。

    ③结果规格化并进行舍入处理

    浮点数乘除运算结果的规格化和舍入处理与浮点数加减运算结果的规格化和舍入处理方法相同。并且在浮点数乘除运算的结果中,由于乘积和商的绝对值一定小于1,因此在浮点乘除运算结果进行规格化处理时只存在向左规格化,不可能出现向右规格化。

    ④判断溢出

    浮点数乘除运算结果的尾数不可能发生溢出,而浮点数运算结果的溢出则根据运算结果中浮点数的阶码来确定,溢出的判定和处理方法与浮点加减运算完全相同。

 

    [例1]设两浮点数x=2-001×(-0.100010),y=2-100×(0.010110),在浮点数的表示格式中阶码占3位,尾数占6位(都不包括符号位),阶码采用双符号位的补码表示,尾数用单符号位的补码表示。要求用直接补码阵列乘法完成尾数乘法运算,运算结果的尾数取单字长(含符号位共7位),舍入规则用“0舍1入”法,用浮点运算方法计算x×y。

    解:[x]浮=11111,1.011110  [y]浮=11100,0.010110

    ①阶码相加

    [Ex+Ey]补=[Ex]补+[Ey]补=11111+11100=11011

    ②尾数作直接补码阵列乘法运算

 

    [Mx]补×[My]补=1.110100010100

    ③结果规格化并进行舍入处理

    积的尾数左移2位,阶码减2,采用“0舍1入”法进行舍入处理后,得

    [x×y]浮=11001,1.010001

    ④判断溢出

    乘积的阶码的双符号位相同,故乘积无溢出。

    所以x×y=2-111×(-0.101111)

 

    [例2]设两浮点数x=2-010×(0.011010),y=2011×(-0.111100),在浮点数的表示格式中阶码占3位,尾数占6位(都不包括符号位),阶码采用双符号位的补码表示,尾数用单符号位的原码表示。要求用原码阵列除法完成尾数除法运算,运算结果的尾数取单字长(含符号位共7位),舍入规则用“0舍1入”法,用浮点运算方法计算x÷y。

    解:[x]浮=11110,0.011010  [y]浮=00011,1.111100

    ①阶码相减

    [Exx-Ey]补=[Ex]补+[-Ey]补=11110+11101=11011

    ②尾数作原码阵列除法运算

    [Mx]原=0.011010  [My]原=1.111100

    商的符号位为:Mxf⊕Myf=0⊕1=1

    令Mx’=011010000000,My’=111100,其中Mx’和My’分别为[Mx]原和[My]原的数值部分,且Mx’为双字长

    [Mx’]补=0011010000000,[My’]补=0111100,[-My’]补=1000100

 

    故得商q=0011011

    所以[Mx÷My]原=1.011011

    因此[x÷y]浮=11011,1.011011

    ③尾数规格化

    商的尾数左移1位,阶码减1。

    [x÷y]浮=11010,1.110110

    ④判断溢出

    商的阶码的双符号位相同,故商无溢出。

    所以x÷y=2-110×(-0.110110)


后记:

     额,写到这里我快没了,哈哈哈。其实掌握了定点数部分,到浮点数部分只要按照具体的步骤来,就水到渠成。而且你也会发现,加减法简单,乘法还好,除法就特别难了,计算机内部还要进行很多判断和移位操作,所以各位写代码的,尽量少用除法呀!!!

 

参考资料:

https://blog.csdn.net/xingqingly/article/details/18981671?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param,后半部分浮点数运算均来源于此,特做说明,因为写的很好了,就不需要自己再去写了,谢谢大佬的资料。

c/c++开发分享定点数和浮点数加减乘除运算详解【计算机组成原理】—真的建议收藏啊!!!地址:https://blog.csdn.net/qq_43919400/article/details/108954732


推荐阅读
  • 高效解决应用崩溃问题!友盟新版错误分析工具全面升级
    友盟推出的最新版错误分析工具,专为移动开发者设计,提供强大的Crash收集与分析功能。该工具能够实时监控App运行状态,快速发现并修复错误,显著提升应用的稳定性和用户体验。 ... [详细]
  • 帝国CMS多图上传插件详解及使用指南
    本文介绍了一款用于帝国CMS的多图上传插件,该插件通过Flash技术实现批量图片上传功能,显著提升了多图上传效率。文章详细说明了插件的安装、配置和使用方法。 ... [详细]
  • 2023年京东Android面试真题解析与经验分享
    本文由一位拥有6年Android开发经验的工程师撰写,详细解析了京东面试中常见的技术问题。涵盖引用传递、Handler机制、ListView优化、多线程控制及ANR处理等核心知识点。 ... [详细]
  • 本文深入探讨了 Python 列表切片的基本概念和实际应用,通过具体示例展示了不同切片方式的使用方法及其背后的逻辑。 ... [详细]
  • 本文详细介绍了K-Medoids聚类算法,这是一种基于划分的聚类方法,适用于处理大规模数据集。文章探讨了其优点、缺点以及具体实现步骤,并通过实例进行说明。 ... [详细]
  • 本文探讨如何利用人工智能算法自动区分网页是详情页还是列表页,介绍具体的实现思路和技术细节。 ... [详细]
  • 本文探讨了 C++ 中普通数组和标准库类型 vector 的初始化方法。普通数组具有固定长度,而 vector 是一种可扩展的容器,允许动态调整大小。文章详细介绍了不同初始化方式及其应用场景,并提供了代码示例以加深理解。 ... [详细]
  • 本实验主要探讨了二叉排序树(BST)的基本操作,包括创建、查找和删除节点。通过具体实例和代码实现,详细介绍了如何使用递归和非递归方法进行关键字查找,并展示了删除特定节点后的树结构变化。 ... [详细]
  • MATLAB实现n条线段交点计算
    本文介绍了一种通过逐对比较线段来求解交点的简单算法。此外,还提到了一种基于排序的方法,但该方法较为复杂,尚未完全理解。文中详细描述了如何根据线段端点求交点,并判断交点是否在线段上。 ... [详细]
  • 从零开始构建完整手机站:Vue CLI 3 实战指南(第一部分)
    本系列教程将引导您使用 Vue CLI 3 构建一个功能齐全的移动应用。我们将深入探讨项目中涉及的每一个知识点,并确保这些内容与实际工作中的需求紧密结合。 ... [详细]
  • 解决Windows 10无法正确加载ICA文件的问题:设置Citrix Receiver为默认打开程序
    当在Windows 10系统中遇到无法正确加载ICA文件的情况时,可以通过下载并安装Citrix Receiver,并将其设置为ICA文件的默认打开方式来解决问题。具体操作步骤包括找到ICA文件,选择合适的打开程序路径(通常是C:\Program Files (x86)\Citrix\ICA Client\wfcrun32.exe),并确保该程序被设为始终使用。 ... [详细]
  • 本教程涵盖OpenGL基础操作及直线光栅化技术,包括点的绘制、简单图形绘制、直线绘制以及DDA和中点画线算法。通过逐步实践,帮助读者掌握OpenGL的基本使用方法。 ... [详细]
  • 图数据库中的知识表示与推理机制
    本文探讨了图数据库及其技术生态系统在知识表示和推理问题上的应用。通过理解图数据结构,尤其是属性图的特性,可以为复杂的数据关系提供高效且优雅的解决方案。我们将详细介绍属性图的基本概念、对象建模、概念建模以及自动推理的过程,并结合实际代码示例进行说明。 ... [详细]
  • 获取计算机硬盘序列号的方法与实现
    本文介绍了如何通过编程方法获取计算机硬盘的唯一标识符(序列号),并提供了详细的代码示例和解释。此外,还涵盖了如何使用这些信息进行身份验证或注册保护。 ... [详细]
  • 本文详细介绍了 React 中的两个重要 Hook 函数:useState 和 useEffect。通过具体示例,解释了如何使用它们来管理组件状态和处理副作用。 ... [详细]
author-avatar
零摄氏度玫瑰_460
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有