float浮点数理解

79 篇文章 4 订阅
15 篇文章 0 订阅

(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)

总述

随着对float数据格式的进一步认识,对float的看法又有了一些变化,特记录一下:

当前,在c/c++中,32位float的存储:
float是以二进制的科学计数法来存储数据的,形如:
(+/-)1.x * (2y);

符号位,在第1位上,占1个bit
y存在指数位上,在第2到第9位上,占8个bits
x存储小数位上,在后23位上,占23个bits

基于此来看看;符号位暂且不谈;

谈谈指数位:

(+/-)1.x * (2y);

y存在指数位上,8字节,表达数值范围[0, 255];
采用移码-127,表达范围修正到[-127, 128];(去掉特殊表达后是[-126, 127])

指数位存储0x00,此时移码值为-127,y取-127:
1.x *(2-127) 会是一个非常小的数字,约1/(2127),无限接近于0了;
也因此,该指数取值被占用做特殊表达,就来用来表达0,确实也没有比它更合适了,指数为它时,最接近0,符合数学上对它的期待。
所以,在浮点数表达上,就有了+0,-0的表达,从坐标轴上看,一个在右,一个在左,都趋近于0。
取值:(+/-)1.0 * 2-127
0b 0 00000000 00000000000000000000000 (+0)
0b 1 00000000 00000000000000000000000 (-0)

指数位存储0xFF,此时移码值为128,y取128:
1.x * 2128,这个数字远大于uint64的最大值,大于uint64_max * uint64_max,无限接近认知中的无穷大了;
也因此,该指数取值被占用做特殊表达,用来表达无穷大,确实也就很合适了,指数为它时,远离坐标轴原点,接近无穷大,也符合期待。
所以,在浮点数表达上,就有了+infinite, -infinite的表达,从坐标轴上,都远离原点,一个在右,一个在左。
取值:(+/-)1.0 * 2128
0b 0 11111111 00000000000000000000000 (+infinite)
0b 1 11111111 00000000000000000000000 (-infinite)

有了无穷大的定义后,float里面还需要not a number的定义,从哪里取值呢?
not a number,有几个选择,我们人为设定了0的取值,与无穷大的取值;
那么对于比0还接近坐标原点的数应该有吗?
那么比infinite还离坐标原点更远的数应该存在吗?
从推论上讲,都应该是不存在的,所以,not a number就可以在这两个里面来选择定义了;
选则的是比infinite还离原点远的数;
取值:(+/-)(1.0 + 1/223 + …) * 2128

0b x 11111111 x0000000000000000000001 (not a number)
另外,有更多区分需求,取值又还有这么多,不要太浪费,就又区分了quiet not a number(qNan), singaling not a number(sNan).
qNan一般表示未定义的算术运算结果,最常见的莫过于除0运算;
0b x 11111111 10000000000000000000001 (not a number)
sNan一般被用于标记未初始化的值,以此来捕获异常。
0b x 11111111 00000000000000000000001 (not a number)

谈谈小数位:

(+/-)1.x * (2y);

小数位也是很有意思的,1.x,表达x取值,基于二进制的特点,小数之后的值表达为
第1位2-1:1/2=0.5
第2位2-2:1/4=0.25
第3位2-3:1/8=0.125
第4位:2-4 1/16=0.0625
第5位:2-5 1/32=0.03125
第6位2-6: 1/64=0.015625

第22位2-22: 1/4194304 = 0.00000023841857910…
第23位2-23: 1/8388608 = 0.00000011920928955…

x取值范围[0, 1-(2-23)] = [0, 1-1/8388608],[二进制全0,二进制全1],最大精度位2-23
1.x取值范围[1, 2-(2-23)] = [1, 2-1/8388608],[二进制全0,二进制全1],最大精度位2-23

谈谈取值精度与总数量:

所以不同有效指数范围的精度也就出来了:
指数位[-126, 127]
(+/-)1.x * (2y)
0x7F指数y取0时,最大精度位(2-23) * (20) = 2-23
0x80指数y取1时,最大精度位(2-23) * (21) = 2-22
0x81指数y取2时,最大精度位(2-23) * (2^2) = 2-21
0x82指数y取3时,最大精度位(2-23) * (22) = 2-20

指数y取23时,最大精度位(2-23) * (223) = 20 = 1
指数y取24时,最大精度位(2-23) * (224) = 21 = 2
指数y取25时,最大精度位(2-23) * (225) = 22 = 4
指数y取26时,最大精度位(2-23) * (226) = 23 = 8

0xFE指数y取127时,最大精度位(2-23) * (2127) = 2124 (非常大的一个数字,非常远离坐标原点了,此时取值也很远: 1.x*(2127))

指数再向小的方向取值
0x7E指数y取-1时,最大精度位(2-23) * (2-1) = 2-24
0x7D指数y取-2时,最大精度位(2-23) * (2-2) = 2-25
0x7C指数y取-3时,最大精度位(2-23) * (2-2) = 2-26
0x7B指数y取-4时,最大精度位(2-23) * (2-2) = 2-27

0x01指数y取-126时,最大精度位(2-23) * (2-126) = 2-149 (非常小的一个数字,非常趋近于0了,当然此时取值也是非常小的: 1.x*(2-126))

能看的出来,随着指数的变化,取值精度变化也非常大;
对于小数位来说,23位,能表达取值8388608个取值,指数确定了取值范围,小数部分来确定取值精度,确定了表达取值的总数量。
例如
指数取-1时,1.x * (2-1)取值范围[0.5, 1-0.5*(2-23)],取值在0.5和1之间,从0.5开始,到0.5+0.58388607/8388608,取值总共8388608个。
指数取0时,1.x * (20)取值范围[1, 2-1
(2-23)],取值在1和2之间,从1开始,到1+18388607/8388608,取值总共8388608个。
指数取1时,1.x * (21)取值范围[2, 4-2
(2-23)],取值在2和4之间,从2开始,到2+28388607/8388608,取值总共8388608个。
指数取2时,1.x * (22)取值范围[4, 8-4
(2-23)],取值在4和8之间,从4开始,到4+48388607/8388608,取值总共8388608个。

指数取127时,1.x * (2127)取值范围[2127, (2128)-(2127)
(2-23)],取值在2127和2128之间,从2127开始,到2127+(2127)*8388607/8388608,取值总共8388608个。
无论指数值对应的有效范围是多少,能取值的总数量是固定的;

类比走台阶:

相当于无论起止高度多少,台阶数量就这么多;
高度范围大了,梯子每个台阶就比较高;
高度范围小了,梯子每个台阶就比较低;

小数位数-决定了台阶数(例如float-23位-8388608台阶数);
指数位取值-决定了起止高度;
小数位取值-决定走了总台阶数的多少个台阶;

(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

春夜喜雨

稀罕你的喜欢!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值