浮点数的加法与乘法

移位运算

        在计算机中并没有存放小数点的位置,小数点是在我们约定的位置存在的。所以我们在说到移位操作的时候,就不能说将小数点左移和右移(因为在数学中我们常常这样表达),而是说将尾数左移还是右移。我之前就是一直有一个理解障碍,我就认为小数点是一个分隔符,就是不能进位到小数点上面的。其实这个想法是错误的。因为我们实现补码的运算中,符号位就是要参与运算的。电脑并不知道你的数据最高位就是符号位,它一律看成数据,并且实现同样的规则加法运算。最后如果进位到超过了符号位,就会发生溢出。也正是溢出的原因,减法就可以使用补码的加法来做。

        无论是正数还是负数,其符号位均不能变化,这个是算术移位的特点。正数情况下,无论左移还是右移,都是补0。在负数的时候,原码还是补0,但是反码补1,补码在左移的时候补0,右移补1。至于为什么这样做,唐老师的《计算机组成原理》上解释的很清楚了。

        其实在C语言中的带符号右移和不带符号的右移指的的都是补码的运算。因为在原码中,不管带不带符号的左移还是右移,否是统一补0。但是对于补码来说,负数右移补1,左移补0。

浮点数规格化数据

        下面的都是以2为基址来讲的。不同的基址,也有所区别。后面会稍微提一下。
        非IEEE754标准的规格化数据:
当S>0时:

  • 真值的规格化数据:0.1xxxxxx
  • 原码的规格化数据:0.1xxxxxx
  • 反码的规格化数据:0.1xxxxxx
  • 补码的规格化数据:0.1xxxxxx

当S<0时:

  • 真值的规格化数据:-0.1xxxxxx
  • 原码的规格化数据:1.1xxxxxx
  • 反码的规格化数据:1.0xxxxxx
  • 补码的规格化数据:1.0xxxxxx

        因为原码和补码使用的比较多。总结以下就是:对于原码来说:“不管是正数还是负数,统一保证小数点后面的第一个是1就可以了。”对于补码来说:“要保证符号位和小数点第一位不一样就行。”

        我觉得使用这个非IEEE754的标准的规格化的数据,就是为了提升数据的表示精度。因为你看,在以2为基址的定义下,就是1/2<=|S|<1的就是规格化数据(如果以4为基址就是1/4<=|S|<1)。例如S=0.00011111112^0。假设只有8位来存放这个浮点数的话,那么尾数的最后一个1就无法存放。但是阶码那里却没有利用起来。所以将其左归,就可的得到这样的0.111111002 ^-11。这样子就能保证精度了。

注意,[-1/2]补不是一个规格化的数据,[-1]补是一个规格化数据。所以来说,判断一个机器码的表现形式是不是规格化数据,一般没有按照定义来(定义就是1/2<=|S|<1),而是直接看机器码的符号位和符号位的下一位的情况。

        按照我做题目的经验来看,如果题目没有要求,那么在浮点数的四则运算中,所有的规格化指的的都是非IEEE754的规格化数据。但是,还是得注意一点的就是:你要看看你自己使用的是原码还是补码在计算(尤其在乘法中可以使用原码来计算),因为原码和补码的规格化的格式是不一样的。

        IEEE754标准的规格化数据:就是和书本上定义的一样。保证尾数是1.M的形式。而1却是掩藏起来的,不会存贮。但是最后在转化成为实际的数据的时候,还是要加上去。我觉得这个的标准就是为了能充分的利用存储字长。因为有一个1掩藏不存放,那么就可以多出一位来存放别的数据了。

舍入规则

        这里只有右归和对阶的时候需要进行舍入处理,左归的时候是不要舍入处理的。因为左归处理的时候,会将数据的变化的很大,因为最高有效位都丢失了。所以我们仅仅只对右规的数据进行舍入处理。因为右规的时候,才会出现精度的损失。这个也是为什么要使用小阶向大阶看齐的原因。

  • 浮点加法和减法的舍入规则
            书本上介绍了两个方法,一个是“0舍1入法”,还有一个就是“恒置1法。”但是实际用的比较多的就是“0舍1入法。”

  • 浮点乘法和除法的舍入规则
            这里就是主要看你使用的什么方法来计算的。如果是原码来计算的话,其舍入规则和浮点加减法是一样的。但是如果你是补码来计算的话,就有点区别(我觉得这里之所以有区别的原因就在于你要保证使用原码计算和补码计算的得到的结果是一样的。)

浮点数溢出规则

        这点和定点的运算时不一样的。在浮点的运算中,尾数是否溢出,看的是阶码来决定的。因为尾数是10.xxxxxx和01.xxxxxx的时候,并没有表示溢出。因为此时还是仅仅只有一位来表示符号,此时的情况只能说是两数相加之后,绝对值大于1。所以此时不满足规格化(非IEEE754标准)数据的定义,所以实现右规(因为左归会让尾数更加变大)。注意,我上面的例子是以补码的形式来讲解的,所以说,此时实现的是补码的右移运算。对于10.xxxxxx右移时,最高位补1,因为第一位是符号位,代表的是负数,负数的补码右移最高位补1。01.xxxxxx代表的是正数,右移时最高位补0。

        所以说,当10.xxxxxx和01.xxxxxx出现之后,先右规,然后为了保证数据的大小不变,阶码必须增大。如果此时阶码的双符号位出现了01,证明就是出现了上溢。在左规的时候,阶码要减小,容易出现下溢。

阶码[j]补=01,xxxxxx为上溢,机器停止运算,做中断处理
阶码[j]补=10,xxxxxx为下溢,按机器0处理

一般来说,就是阶码比较大或者比较小的时候容易因为阶码溢出。

浮点数加法

浮点数加法规则

        给我一个感觉就是补码的规格化采用的就是包括符号位都要参与移位。这一点在右归的时候表现的十分明显。其实在补码左规的时候,也是可以这样理解。

        最主要是教材上面都有这样的一句话:“在浮点运算中,01.xxxx和10.xxxx都不算溢出。它表明尾数求和的结果的绝对值大于1。”我个人认为就是这句话,导致此时在左规和右规的时候实现的尾数的移位运算和补码定义的移位运算的步骤不一样。尤其是右规时,对于01这样的情况,为什么最高位补0,而不是补1。因为这个其实还是一个正数。也就是说,在浮点计算的时候,10xxx和01xxx中的第二高位都不是代表的符号,都是真实的数据。这个也是为什么书本上说的“10xxx,01xxx”都不是代表溢出。那么01xxx其实右规的时候,就是一个正数在向右移动,所以最高位补0。而10xxx就是一个负数,所以在右归的时候,最高位补1。

浮点数乘法

浮点数乘法规则

        在实现乘法的规则的中,因为数据我们采用的是IEEE754的标准来存贮的,所以,我们的尾数采用的都是小数来计算的。所以我们在计算尾数的乘法中,在规格化尾数的时候,仅仅只有左规。(但是其实我觉得题目出的都有些问题。因为计算机实际存放的浮点数是IEEE754的标准,那么数据的尾数部分决定不是一个纯小数。那么,我就觉得上面的说法是不是有问题。)

        因为乘法的计算既可以采用原码计算,也可以采用补码计算。所以,针对于不同的题目的要求,也要采用不同的策略。在白中英老师的书本上,主要讲述的是原码计算乘法,而唐朔飞老师的书本上,主要讲述的就是补码计算乘法。

        补码和真值的左移和右移方式是不一样的。因为补码是带上符号的数据,所以左移,右移的时候要注意符号的问题。那么,在浮点的乘法运算中,可能就会因为采用原码计算和补码计算的时候,舍入方式的处理导致计算的结果不一样。那么为了使原码和补码舍入处理后的结果是相同的,人们就推出了一个规则来决定负数的补码如何舍入(因为正数的原码和正数的补码的舍入是一样的):

  • 当丢失的各位均为0时,直接丢弃
  • 当丢失的各位数中,最高位为0的时候,且以下各位不全为0的时候,直接丢弃
  • 当丢失的各位数种的最高位为1的时候,且以下均为0的时候,直接丢弃;如果以下各位不全为0的时候,则在保留的尾数最末位加1修正

请注意:我这里谈到了两个位置。第一个是:“要被丢失的各位的最高位”和“被保留的最低位。”

关于IEEE754的标准

        我通过做这个题目发现,就是很多题目并没按照IEEE754的标准来做,尤其是在计算浮点加减法的时候,做题目的时候基本都是采用非IEEE754的标准来计算的。

参考书籍

计算机组成原理(唐朔飞老师)关于这个规则讲的十分详细了

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值