博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
浮点数精度
阅读量:6902 次
发布时间:2019-06-27

本文共 2259 字,大约阅读时间需要 7 分钟。

1、为什么叫浮点数?
   相对于浮点数,就是固点数,小数点固定在最右边,也就是整数。浮点数的小数点,根据指数的取值,左右移动。
2、考虑二进制整数,假设只有2个bit,可以表示00,01,10,11,共四个整数,表示范围是[0,3],可以表示这个范围内的所有整数。
3、考虑二进制小数,假设只有2个bit,可以表示多少个小数?   答案也是四个。假设小数点在最左边,分别为00,01,10,11,表示的值分别为0.0,0.25,0.50,0.75。表示范围[0.0,0.75],特别注意:不同于整数,整数可以表示范围内的每一个整数,如[0,3]。而小数只能表示[0.0, 0.75]范围内的四个小数,我们知道从0.0到0.75有无数个小数,两位二进制只能表示其中的4个。
4、十进制0.0到0.9,有几个可以使用二进制表示?
   只有两个,0.0和0.5。考虑十进制,小数第一位是1/10,小数第二位是1/100,小数第三位是1/1000,那么二进制呢?
   小数第一位是1/2,小数第二位是1/4,小数第三位是1/8,那么0.1 可以使用下面的方式表示吗?
   a1*1/2 + a2*1/4 + a3*1/8 + ....
   存在这样的a1,a2,a3吗?
   答案是不存在。
5、0.1+0.2 为什么不等于0.3?而是0.30000000000000004
   在计算的时候,计算机要把0.1和0.2转化为二进制表示,由上面分析,我们知道计算机无法准确表示0.1和0.2,只能是无限接近地表示,那么无限接近0.1和0.2的两个值相加,当然不能保证是0.3,但是可以保证的是,结果无限接近0.3。
6、那么怎么解释 0.2+03 会等于0.5呢?
举个例子,计算 1.6+1.8,现在假设不能准确表示1.6和1.8,只能准确表示整数,先转化为最接近的整数,也就是2+2=4,这与1.6+1.8=3.4,再转化为最接近的3,相差为1。那么是不是,所有的计算结果都不准确呢?
不是这样,考虑1.2+1.8 =3,转化为处理是 1+2 =3,计算的结果是准确的。
也就是说,转化过程中精度缺失,如果两个加数都多了一点,其和多了一点加一点。如果一个加数多了一点,一个加数少了一点,刚好相互抵消,其和刚好非常准确,一点不差。
7、二进制与十进制的转化,
   二进制整数转为十进制整数,二进制小数转为十进制小数都简单。
   十进制整数转为二进制小数,除2取余,倒序排列。
   十进制小数转为二进制小数,乘2取整,顺序排列。用这种方法,可以知道0.1永远不能得到0
8、思考一下,十进制小数0.1不能用二进制准确表示,那么是不是所有的二进制小数,都可以使用十进制准确表示呢?
可以。二进制小数,转为十进制,就是a1/2+a2/4+a3/8....,a1,a2,a3取值为0或者1,那问题就转化为,1除2的n次方,是不是都能除尽。类推一下,0.5,0.25,0.125,每次末位都是5,除2结尾是25,永远都能除尽。

9、从数学的角度分析,对于小数,2进制只能表示1/2,  3进制只能表示1/3, 2/3, 3进制没法表示1/2, 也就是一半,你会说1.5/3 就是一半呀,这就是一个递归的问题,那1.5怎么用3进制表示?没法表示。那么10进制,只能表示1/10, ...9/10,  而恰巧5/10就是1/2, 因此10进制能够表示2进制的任何小数。 

10、如果我想让0.1+0.2 等于0.3,怎么办?
从上面分析知道,二进制可以表示可表示范围内的任意一个整数。我们把0.1和0.2根据小数点分成两部分,同时记住小数点的位置。,分别变成整数相加,再合并进位,在字符串中添加小数点的位置即可。需要注意的是:小数点左边右对齐,小数点右边左对齐。比如:12.46+5.5400,分别为12+5,4600+5400。
代码如下:
string NzbUtils::GetRightDouble(string a, string b)
{
vector<string> aVec;
StringSplit(a,".",aVec,true);
vector<string> bVec;
StringSplit(b,".",bVec,true);
int c1 =  atoi(aVec[0].c_str()) + atoi(bVec[0].c_str());
int maxLen = aVec[1].size() > bVec[1].size() ? aVec[1].size():bVec[1].size();
if(maxLen > aVec[1].size())
{
while(maxLen > aVec[1].size())
{
aVec[1]+="0";
}
}
if(maxLen > bVec[1].size())
{
while(maxLen > bVec[1].size())
{
bVec[1]+="0";
}
}
int c2 =  atoi(aVec[1].c_str()) + atoi(bVec[1].c_str());
char ch[64] = {0};
sprintf(ch,"%d",c2);
if(strlen(ch) > aVec[1].size())
{
c2 = atoi(ch+1);
c1 = c1+1;
}
char ret[64] = {0};
sprintf(ret,"%d.%d",c1,c2);
return ret;
}

转载地址:http://gcpdl.baihongyu.com/

你可能感兴趣的文章
uGUI知识点剖析之AutoLayout
查看>>
Eclipse调试DEBUG时快速查看某个变量的值的快捷键
查看>>
C#的Compiler Error CS1660
查看>>
记录未预编译文件“*.aspx”,因此不能请求该文件的几种处理办法
查看>>
《大话设计模式》读书笔记-第15章 抽象工厂模式
查看>>
一个朋友
查看>>
转:汉字转拼音 - 输入汉字获取其拼音
查看>>
webservice(pers)
查看>>
hbase源码系列(十五)终结篇&Scan续集-->如何查询出来下一个KeyValue
查看>>
Linux学习总结(4)——Centos6.5使用yum安装mysql——快速上手必备
查看>>
Spring Boot学习总结(1)——Spring Boot入门
查看>>
C/C++ 宏带来的奇技淫巧 转载
查看>>
CocoaPods requires your terminal to be using UTF-8 encoding
查看>>
CSS3 圆角(border-radius)
查看>>
最大子数组
查看>>
用telnet命令,POP3接收邮件
查看>>
Nginx 关于 location 的匹配规则详解
查看>>
OutputStream、InputStream 、FileOutputStream、FileInputStream,字节流API
查看>>
10. Python面向对象
查看>>
python3与 python2 urllib模块区别
查看>>