超大浮点数+超小浮点数解析

搜遍全网都是用两个小浮点数加法来解释,且不是按32位总长度来表示,各种原反补码绕来绕去,冗长聒噪,因此决定另辟蹊径讲解:

感性认识:超大浮点数加超小浮点数常常会丢失超小浮点数,也就是加不进去,下面谈下我的理解。

单精度浮点数float有32位,第1位是符号位(0表示此浮点数是正数,1表示此浮点数是负数),接着8位是指数位,范围为0~255,其中0和255是特殊情况:

1、指数为0时,规定其真正指数值大小为1-127即-126,且规定此时尾数开头隐含的那1位值是0,因此尾数范围下限是:

0.0000 0000 0000 0000 0000 000(23位全是0,当然值就是0)

尾数范围的上限是:

0.1111 1111 1111 1111 1111 111(23位全是1,值为1减2的负23次方,即0.99987792964)

综上此时浮点数值非负的范围下限是0,上限是0.99987792964*2^-126可写为[0,1)*2^-126,负数部分范围同理,提示这只是范围,不表示可以取到这个范围中的任何值,只能有选择的表示,能精确表示的是那些可以分解为多个2^n之和的数。

2、指数为255时,又规定了两种情况:当尾数小数部分全为0是,表示±∞;若尾数小数部分不全为0,这表示不是一个数

3、指数为1~254时,规定减去127得到-126~127为实际指数值,而此时尾数范围下限是:

1.0000 0000 0000 0000 0000 000(23位全是0,加上首位1,当然值就是1)

尾数范围的上限是:

1.1111 1111 1111 1111 1111 111(24位全是1,值为2减2的负23次方,即1.99987792964)

综上此时浮点数值非负的范围下限是1*2^-126,此下限刚好连接上指数全为0时的上限0.99987792964*2^-126,上限是1.99987792964*2^127趋近于2*2^127,负数部分范围同理,因此浮点数范围是±2^128,也就是±3.40282367E38

试想指数和尾数为这种情况时:

1.1111 1111 1111 1111 1111 111*2^23值为16777215再加1就是16777216即1.0000 0000 0000 0000 0000 000*2^24,在1~16777216范围分辨率是1,因此这个范围内的整数,浮点数都可以精确表示,在16777217~33554432范围内,也就是1.0000 0000 0000 0000 0000 001*2^24到1.0000 0000 0000 0000 0000 000*2^25这个范围内,尾数在小数点后第23位加1,浮点数值就加2,因此分辨率是2,这个范围中的有些数不能精确表示,如16777217、16777219、16777221……等。因为第8位有大小为1的误差,所以第7位可能有误差,但第6位肯定没有误差,所以浮点数有效位数为6到7位。

重点,浮点数相加时,要先进行对阶,指数小的要变成和指数大的一样大,因此小浮点数的尾数要相应右移,移动位数为大小浮点数指数的差值

下面以超大浮点数8589934592.0即1.0000 0000 0000 0000 0000 000*2^33为例,在8589934592.0~17179869184.0范围内,分辨率为2^(33-23)即1024,而512.0即1.0000 0000 0000 0000 0000 000*2^9

下面当8589934592.0+512.0时有:

1.0000 0000 0000 0000 0000 000*2^33

1.0000 0000 0000 0000 0000 000*2^9

对阶时有:

1.0000 0000 0000 0000 0000 000*2^33

0.0000 0000 0000 0000 0000 0001*2^33

然后相加,相加时要包含移出的位,有:

1.0000 0000 0000 0000 0000 0001*2^33

此时尾数小数部分有24位,多了1位,该位要舍去,但不是简单的舍去:舍去部分的值若超过此时第23位权的一半就在第23加1,否则不加,这里我们第23位的权为2^(33-23)即1024,舍去值为512,未超过1024的一半,因此直接舍去,结果就是8589934592.0+512.0结果还是8589934592.0

思考一下,8589934592.0最少加多少会变成8589935616.0?

由上面的结论可知,只要超过512.0就会加1024.0,那单精度浮点数在512.0之后能精确表示的第一个浮点数是什么?

当然是:

1.0000 0000 0000 0000 0000 001*2^9

即512.00006103516

所以8589934592.0+512.00006103516=8589935616.0

你以为就这样?

由于在大于512.0小于1024.0这个区间,单精度浮点数的分辨率为2^(9-23)=0.00006103516,因此在大于512.0小于512.00006103516范围内的数浮点数都是都无法表示的,这就是表示误差,当向编译器输入值为大于512.0等于512.00003051758时会存储为512.0,而输入大于512.00003051758小于等于512.00006103516时就存储为512.00006103516

因为IEEE754浮点数对于无法精确表示的浮点数默认采用的是向偶舍入,即4舍6入5取偶,但对于浮点数而言,什么是奇?什么是偶呢?规定如下:将浮点数化为IEEE754格式后,其尾数中,小数点右侧第23位,即最后一位为1就是奇,为0就是偶,显然512.00003051758的IEEE754格式为1.0000 0000 0000 0000 0000 0001*2^9,第23位为0是偶,所以第24位直接舍去,整体值为1.0000 0000 0000 0000 0000 000*2^9,也就是512.0;

所以在编译器中对单精度浮点数输入:

8589934592.0+512.00003051759时编译器进行的是:

8589934592.0+512.00006103516

经过舍入得到的是8589934592.0+1024.0=8589935616.0

以上就是我肤浅的理解,如有不当之处,欢迎指正😃

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值