- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
- 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
- 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们。
- 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
- 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
浮点数精确运算
1.01 + 2.01 = 3.02
2.01 * 2.01 = 4 0401
不知你注意没有,这个很寻常的等式,你如果将它放在C++中,Java中,Basic中,它居然是不成立的。计算机在开玩笑吗?噢,对了,隐约记得这好象是浮点数的问题,似乎很多很多年前,老师说过。还有某位姓林的先生在某本书里提过=0的判断。嗯,如果你不遇到此问题,那你完全可以把它抛到火星上去,可惜,偶不好彩,这样的问题,被俺遇到了。唉!
why?how?
没办法,硬着头皮,从头开始。
一:为何不成立?Why?
这得从浮点数的在计算机内的存储开始说起,我这里闲话少说。我们只谈双精度double数(至于float,基本上是五十步和一百步的区别)。
双精度数在计算机内的表示方式是:(三部分组成)
符号(正或负) 阶码(2的N次幂) 尾数(大于等于1小于2的数)
比如: -(符号) 1.01(尾数) * 2~1(N = 1) = - 2.02
具体到计算机的存储单元:双精度数共占8字节(64bit)
符号位(占1个bit) 阶码(11个bit) 尾数(52个bit)
解释一下:
符号位:0表示正 1表示负
阶码:是一个偏移量,1023的偏移量,它的1023相当于0,小于1023时为负,
大于1023时为正,如:10000000001表示指数为1025 - 1023 = 2,表示真值为2^2。
好了,知道了原理,我们开始分析上述等式为何为不等。
(相应数的存储值,可以简单用C语言的指针方式取出)
1.01 表示为:
0 0111111 1111 0000111101011000111100101001
2.01 表示为;
0 1000000 0000 0000011110100100011100010100
3.02 表示为:
0 1000000 0000 1000111101011000111100101001
2.01+1.01 在编程语言中的计算结果 表示为:
0 1000000 0000 1000111101011000111100101000
好了,我们可以比较一下3.02和计算结果,果然有所不同,只不过最后一个bit不同嘿。
为了验证一下,可以用手工计算一下2.01+1.01:
先把1.01的幂次变为1(与2.01的阶码相同),于是,将尾数右移一位。得到:
10000111101001000111000101001
加上2.01的尾数。
0000011110100100011100010100
得到:
1000111101011000111100101000
嗯,与计算机的计算结果相同,我们的运算思路是正确的。
因此,结论出来了,因为浮点数在计算机内的存储存在偏差,导致运算时,与实际期望的结果不同。很多时候,你可以不理它,但是,可以肯定负责任的说,发射卫星的运算时,你需要知道,否则,卫星一转眼就不见了。
二:不成立的的原因找到了,那怎么解决这个问题呢,How?
一个简单的解决办法是:
不要用浮点数来存储浮点,对于VC,Java,Basic,最好的办法是用Decimal来保存它。
下面是分别的实现:(以加法为例,其它四则运算处理相同)
VC中:
double doublAdd(double dbl1, double dbl2)
{
double dblResult;
DECIMAL dec1,dec2,decResult;
::VarDecFromR8(dbl1,dec1);
::VarDecFromR8(dbl2,dec2);
::VarDecAdd(dec1,dec2,decResult);
::VarR8FromDec(decResult,dblResult);
return dblResult;
}
VB中:
Private Function doubleAdd(ByVal dbl1 As Double, ByVal dbl2 As Double) As Double
doubleAdd = CDec(dbl1) + CDec(dbl2)
End Fu
文档评论(0)