电脑故障

位置:IT落伍者 >> 电脑故障 >> 浏览文章

浮点运算结果出现误差原因分析及解决方案


发布日期:2020/11/21
 

如下C#代码

float a = f;

float b = f;

float c = a b;

此时c为多少?

?错误!

此时c为

为什么?

其根本原因是计算机所使用二进制代码无法准确表示某些带小数位的十进制数据

下面我们来分析下

我们知道将一个十进制数值转换为二进制数值需要通过下面的计算方法

整数部分连续用该整数除以取余数然后商再除以直到商等于为止然后把得到的各个余数按相反的顺序排列简称取余法

小数部分十进制小数转换为二进制小数采用取整顺序排列乘以十进制小数将得到的整数部分取出再用乘余下的小数部分然后再将积的整数部分取出如此进行直到积中的小数部分为或者达到所要求的精度为止然后把取出的整数部分按顺序排列起来即先取出的整数部分作为二进制小数的高位后取出的整数部分作为低位有效位简称取整法

含有小数的十进制数转换成二进制整数小数部分分别进行转换然后相加

例如将十进制数值转换为二进制数值步骤如下

(整数部分)

/=

/=

/=

/=

/=

() =()

(小数部分)

*=

*=

() =()

() =() +() =()

按照上述方法我们将转换为二进制代码

() = ()

() = ()

后面的省略号表示已经算不完了后面在无限重复 这段二进制数值

文章开始部分我们用的float类型下面我们来看看float类型是否能存储上面转换出的二进制代码

目前计算机上存储浮点数值是按照IEEE(电气和电子工程师协会)浮点存储格式标准来存储的

IEEE单精度浮点格式共包含三个构成字段位小数f位偏置指数e位符号s将这些字段连续存放在一个位字里并对其进行编码其中:位包含位的小数f :位包含位指数e位包含符号s如下图所示

也就是说上面将转换出的二进制代码我们只能存储即使数据类型为double也只能存储这样大家便能看出问题出现的原因了

截取的二进制代码已无法正确表示根据这个二进制代码肯定无法正确得到结果

如何解决这个问题?知道其根本原因后我们知道是无法从根本上解决这个问题的但我们可以有一些曲线救国的方法下面列举几个

因为二进制数值可以准确表示整数(可以使用整数转换为二进制方法验证下)所以可以将小数乘以等变成整数然后做运算最后再通过除以等获得结果

通过截取结果的有效小数位数等来取得最好的近似结果然后在做处理

对于可以用有限长度的二进制数值表示的十进制数值可以使用存储位数大于其长度的数据类型

解决方案正在补充中……若各位有什么好的方法也可以提出来!

以上解决方案需要按照使用的实际情况来决定使用哪种方法

上一篇:编程中如何选择Class, Abstract Class and&n

下一篇:ckeditor+代码高亮