目录
1.十进制小数转换二进制问题
22.8125转二进制
整数和小数分别转换。
整数除以2,商继续除以2,得到0为止,将余数逆序排列。
22 / 2 11 余0
11/2 5 余 1
5 /2 2 余 1
2 /2 1 余 0
1 /2 0 余 1
所以22的二进制是10110
小数乘以2,取整,小数部分继续乘以2,取整,得到小数部分0为止,将整数顺序排列。
0.8125x2=1.625 取整1,小数部分是0.625
0.625x2=1.25 取整1,小数部分是0.25
0.25x2=0.5 取整0,小数部分是0.5
0.5x2=1.0 取整1,小数部分是0,结束
所以0.8125的二进制是0.1101
十进制22.8125等于二进制10110.1101
2.浮点数在计算机中的存储方式
科学技数法的形式,即用一个尾数(Mantissa ),一个基数(Base),一个指数(Exponent)以及一个表示正负的符号来表达实数。比如 123.456 用十进制科学计数法可以表达为 1.23456 × 10^2 ,其中 1.23456 为尾数,10 为基数,2 为指数。
采用IEEE标准
假设是float类型的4字节(32bit)的单精度小数,在内存中是分三部分存储的:
符号位S(1位):0代表正数,1代表负数
指数位E(8位):用于存储科学计数法中的指数数据
尾数部分M(23位):采用位移存储尾数部分
8.25 用二进制表示为:1000.01
而用二进制的科学计数法表示 1000.1,可以表示为1.00001 * 2^3
二进制中任何一个数的科学计数法表示都为1. xxx * 2^n,尾数部分就可以表示为xxxx,由于第一位都是1嘛,干嘛还要表示呀?所以将小数点前面的1省略。
指数位E=指数+127
而对于指数部分,因为指数可正可负(占1位),所以8位的指数位能表示的指数范围就只能用7位,范围是:-127至128。所以指数部分的存储采用移位存储,存储的数据为元数据 +127。
注意:
元数据+127:大概是指“指数”从00000000开始(表示-127)至11111111(表示+128)
所以,10000000表示指数1 (127 + 1 = 128 --> 10000000 ) ;
指数为 3,则为 127 + 3 = 130,表示为 01111111 + 11 = 10000010 ;
按照上述规则
符号位为:0,正
指数位为:3+127=130,10000010;
尾数部分为:00001(缺位的补0)
所以8.25存储方式为0 10000010 00001000000000000000000
0 10000010 00001000000000000000000的反推过程 :
10000010(二进制) ==> 130
1.00001*2^(130-127=3)=1000.01,转换成十进制为8.25
几个特殊的情形:
指数E全为0时,
指数E全为1时,这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s);
如果有效数字M不全为0,表示这个数不是一个数(NaN)
参考:http://www.cnblogs.com/wuyuan2011woaini/p/4105765.html浮点数在计算机中的存储方式
http://blog.csdn.net/jjj19891128/article/details/22945441小数在计算机中的存储形式
3.十进制小数0.1无法被二进制小数准确表示
来源知乎 慕容小匹夫 陈嘉栋https://www.zhihu.com/question/32304267
我们先来看一看一个十进制的小数0.1为何不能被二进制浮点数准确的表示出来吧。
如同在十进制中,1/3是无法被准确表示的,如果我们要将1/3转换成十进制小数的形式则是:
1/3 = 0.3333333....(3循环)
同理,十进制小数0.1也是无法被二进制小数准确表示,如果我们要将十进制的0.1转换为二进制小数则是:
0.1 = 0.00011001100....(1100循环)
我们可以看到,如果要将十进制的0.1转换为二进制小数,则会出现1100循环的状况。因此根据我在上一篇文章中提到过的IEEE 754标准以及在上一篇文章中最后所举的一个例子,我们首先将0.00011001100....进行逻辑移位,使之小数点左边第一位是1。那么结果是 1.10011001100...,共移动了4位,因此指数相应的应该是-4。所以,表示十进制0.1的float二进制浮点数的结果如下:
符号位:0(表示正数)
指数部分:01111011(01111011换算成十进制是123,因为要减去-127故结果为-4)
尾数部分:10011001100110011001101(即通过移位之后,舍掉小数点左侧的1,留下的小数部分,保留23位)
那么这个用来“表示”十进制小数0.1的float二进制浮点数如果换算成十进制数到底是多少呢?它和0.1到底有多大的误差呢?下面我们就来换算一下:
指数部分:2^(-4) = 1/16
尾数部分:1 + 1/2 + 1/16 + 1/32 + 1/256 + 1/512 + 1/4096 + 1/8192 + 1/65536 + 1/131072 + 1/1048576 + 1/2097152 + 1/8388608 = 1.60000002384185791015625 (在换算成float时会把小数点左侧的1省略,这里需要再次加回来)
那么,换算之后实际的十进制数便是:1.60000002384185791015625 * 1/16 = 0.100000001490116119384765625
所以我们可以看到,二进制浮点数并不能准确的表示0.1这个十进制小数,它使用了0.100000001490116119384765625来代替0.1。
这便是直接使用二进制来表示小数的方式,很有可能会产生误差。
4.C语言中浮点数的范围和精度
指数全为1, 若尾数全为0,表示正负无穷大
若尾数不全为0,表示 NaN not a number
指数全为0,若尾数全为0,表示0
若尾数不全为0,表示是非规格化的值,接近0的值
最大值,+,尾数23位全为1,指数位全是1,为255
1.11111111111111111111111*2^(255-127=128)
对于单精度浮点数(float)来说,符号位一位,指数位8位,尾数23位。指数能够表示的指数范围为-128~127。尾数为23位。
其中负指数决定了浮点数所能表达的绝对值最小的非零数;而正指数决定了浮点数所能表达的绝对值最大的数,也即决定了浮点数的取值范围。float的范围为-2^128 ~ +2^128,也即-3.40E+38 ~ +3.40E+38;
以float为例,如下表
符号 | 尾数 | 指数 |
1 | 23 | 8 |
数符(+-) | 小数部分(决定精度) | -127~128 指数(决定范围) |
例如:
+1.1111111111111111111111*2^127(小数点后面23个1,由于尾数的范围1~2,其最高位总为1,故只需存取小数部分,所以小数为是23位1),约等于2*2^127=3.4*10^38。为3.4*10^38负数亦然。
参考:http://blog.sina.com.cn/s/blog_6ebd49350101gdgo.htmlC语言中关于float、double、long double精度及数值范围理解
5.浮点数的比较
C语言用"=="来比较两个浮点数,返回值完全是不确定的。
因此只能定义一个精度来确定是否相等
#define EPSILON 0.000001//根据精度需要
if(fabs(a-b) < EPSILON)
{
//a b 近似相等
}
参考:https://blog.csdn.net/jk110333/article/details/8902707 比较两个浮点数是否相等的方法
https://blog.csdn.net/slience_646898/article/details/80954464 浮点数比较问题
6.浮点数计算中存在的误差
相关文章:
http://www.cnblogs.com/zhangziqiu/archive/2011/03/30/ComputerCode.html原码, 反码, 补码 详解
http://www.cnblogs.com/kevinq/p/4480563.html定点数与浮点数
https://www.zhihu.com/question/21711083IEEE 754格式是什么?
http://justjavac.com/codepuzzle/2012/11/02/codepuzzle-float-from-surprised-to-ponder.html
http://justjavac.com/codepuzzle/2012/11/11/codepuzzle-float-who-stole-your-accuracy.html代码之谜(五)- 浮点数(谁偷了你的精度?)
知乎 https://www.zhihu.com/question/32304267
http://www.cnblogs.com/fczjuever/archive/2013/04/16/3023868.html
http://bbs.chinaunix.net/thread-3746530-1-1.html
http://blog.csdn.net/dreamer2020/article/details/24158303
http://blog.163.com/qimo601@126/blog/static/1582209320135101823454/
http://blog.csdn.net/cppptr/article/details/573372
http://blog.csdn.net/hyforthy/article/details/19649969
http://blog.csdn.net/u010296036/article/details/70766904
http://blog.csdn.net/lin200753/article/details/27952897 C中double到int的转换、四舍五入
http://blog.sina.com.cn/s/blog_63d1de3d0100gmcz.html C++中的数据类型转换(使用sstream头文件)