实现位数超过32bit的整数的加减乘除运算_简单加减运算为何还会出bug?

最近输入法有用户反馈一个bug:v模式中数学运算结果不准确,7250.11-7249.68无法得到正确结果0.43

5ab237f3d168fdc7fab4a37e17c49a4b.png

为了分析bug的由来,小编调研了浮点数在计算机中的存储和运算过程,接下来为大家分享7250.11-7249.68详细运算处理过程,解析结果0.429999999999的由来。

浮点数的存储

29914827f9f5ddfa854c1087a408e999.gif

浮点数,顾名思义就是小数点位置可以浮动的数据,科学的规定浮点数常用公示表示:

2517c29538f19e18ed884c57e148039f.png

其中N为浮点数,M为尾数,E为阶码(指数),R为阶的基数(计算机中R一般为2)。

类比十进制的科学计数法:12300 = 1.23 * 10^4,10为基数,4为指数,二进制中1.25 = 1.01 * 2^0,2为基数,0为指数,1.01为尾数。

基于以上基础,国际制定了IEEE 754标准规范完整定义了浮点数在计算机底层的存储方式。根据国际标准IEEEE 754,任意一个二进制浮点数N可以如下表示:

f022a27bc7abd9021d4835da7dd0a14b.png

(1)S表示符号位,当S=0时,N为正数;当S=1时,N为负数;

(2)M表示尾数(二进制),值大于等于1且小于2;

(3)E表示指数。

单精度浮点数float类型数值在计算机中使用32bit存储,存储方式如下:

dee3f007abef25ce169cc237132105c1.png

双精度浮点数double类型数值在计算机中使用64bit存储,存储方式如下:

e37e5623e03c7fb935bd323c3beef849.png

在计算机内部存储尾数M时,M的范围总是[1,2),默认这个数的第一位总是1,可以被舍去,因此为了最大化利用这个空间,IEEE 754规定尾数部分只保存小数部分,所以float类型的尾数可以表示24位二进制,double类型的尾数可以表示53位二进制数。

根据IEEE 754标准,E指数部分是无符号整型数据,因此float类型E的取值范围为0~255,double类型的E的取值范围为0~2047。另外,在实际小数的二进制表示中,指数部分可能为负数,为了表示负数,IEEE 754规定,计算机中E部分实际存储的值为实际值加上中位值(float类型中位数为127,double类型中位数为1023)。

所以,float类型的数据,E用126表示-1,128表示1;double类型的数据,E用1021表示-2,1025表示2。

以上便是浮点数在计算机底层的存储过程。

浮点数转二进制

29914827f9f5ddfa854c1087a408e999.gif

如何将一个浮点数转为符合IEEE 754标准的数据?

以float类型数3.22为例:

整数部分3:符号位为0,大小为11

小数部分0.22:

0.22 * 2 = 0.44 (0)

0.44 * 2 = 0.88 (0)

0.88 * 2 = 1.76 (1)

0.76 * 2 = 1.52 (1)

0.52 * 2 = 1.04 (1)

0.04 * 2 = 0.08 (0)

0.08 * 2 = 0.16 (0)

0.16 * 2 = 0.32 (0)

0.32 * 2 = 0.64 (0)

0.64 * 2 = 1.28 (1)

……

二进制表示为11.0011100001……,左移一位为1.10011100001……符合尾数部分规范

所以23位尾数10011100001010001111010

指数位:1 + 127 = 128(10000000)

最终二进制表示为01000000010011100001010001111010

计算机处理数学运算

29914827f9f5ddfa854c1087a408e999.gif

以bug中的7250.11-7249.68运算为例,输入法中7250.11和7249.68使用的是双精度double类型存储,本文中以32bit存储为例说明:

7f405a1af4a330a67f1dfc4ce53ef8d3.png

(1)将7250.11和7249.68存储符合IEEE 754标准的二进制存储,分别为:7250.11(01000101111000101001000011100001)、7259.68(01000101111000101000110101110000)

(2)处理数据的指数位,保证运算数据的指数位相等,原则上指数低的数向指数高的数转换,本文中7250.11和7249.68的指数位相等,不需要转换。

(3)将尾数M相减,即1110 0010 1001 0000 1110 0001-1110 0010 1000 1101 0111 0000=000 0000 0000 0011 0111 0001,隐藏的24位为0。

(4)将结果转为符合IEEE 754标准的二进制数据,尾数左移14位,指数值-14,结果为0(S) 01111101(E) 10111000100000000000000(M),转换为10进制为0.43017578125

总结

在本次运算过程中共有两次精度损失:第一次是计算机存储浮点数时,第二次是标准化时,因此最终的结果并不完全准确。如果能够尽量降低精度损失,最终结果也会越接近真实数值,比如使用double类型存储运算7250.11-7249.68的结果为0.429999999999,更接近真实结果0.43。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值