float原理与使用详解

一、概况float 32位数据,8位用于存储指数,24位存储尾数。


基本参数从cfloat,climits(float.h)中查看:

#define FLT_DIG 6

#define FLT_MANT_DIG 24

#define FLT_MAX_10_EXP  +38

#define FLT_MIN_10_EXP -38

分别表示,有效数字位数,尾数位数,指数最大,最小值。


二 、将一个float型转化为内存存储格式的步骤为:      

   (1)先将这个实数的绝对值化为二进制格式。  

   (2)将这个二进制格式实数的小数点左移或右移n位,直到小数点移动到第一个有效数字的右边。  

   (3)从小数点右边第一位开始数出二十三位数字放入第22到第0位。       

   (4)如果实数是正的,则在第31位放入“0”,否则放入“1”。      

   (5)如果n 是左移得到的,说明指数是正的,第30位放入“1”。如果n是右移得到的或n=0,则第30位放入“0”。  

   (6)如果n是左移得到的,则将n减去1后化为二进制,并在左边加“0”补足七位,放入第29到第23位。如果n是右移得到的或n=0,则将n化为二进制后在左边加“0”补足七位,再各位求反,再放入第29到第23位。


三、将一个内存存储的float二进制格式转化为十进制的步骤:  

(1)将第22位到第0位的二进制数写出来,在最左边补一位“1”,得到二十四位有效数字。将小数点点在最左边那个“1”的右边。  

(2)取出第29到第23位所表示的值n。当30位是“0”时将n各位求反。当30位是“1”时将n增1。  

(3)将小数点左移n位(当30位是“0”时)或右移n位(当30位是“1”时),得到一个二进制表示的实数。  

(4)将这个二进制实数化为十进制,并根据第31位是“0”还是“1”加上正号或负号即可。

float存储如下所示:          1位S ,8位E,23位F

其中F= 1.f(22)....f(0)

        E= e - Bias(127)

        X = F*2^E


四、代码与详细说明:

1. 其中S位占1bit,为bit31看,S位为0代表浮点数是正数,S位为1代表浮点数是负数。

2. E位占8bits,为bit23~bit30。E位代表2的N次方,但需要减去127(移位存储,后面再解释),比如说E位为87,那么E位的值为2(87-127)=9.094947017729282379150390625e-13。

3. F位占23bits,为bit0~bit22。F位是小数点后面的位数,其中bit22是2^-1=0.5,bit21是2^-2=0.25,以此类推,bit0为2^-23=0.00000011920928955078125。但F位里隐藏了一个1,也就是说F位所表示的值是1+(F位bit22~bit0所表示的数值),比如说F位是(0b)10100000000000000000001,只有bit22、bit20和bit0为1,那么F位的值为1+(2^-1+2^-20+2^-22),为1.5000011920928955。

代码与分析:

#include <iostream>
using namespace std;
int main()
{
	float a = 100;
	cout<<a<<endl;
	unsigned char *b;
	b = (unsigned char *)&a;
	for(unsigned int i=0;i<4;++i){
		cout<<hex<<static_cast<int>(b[i])<<endl;// 检测转换保证安全
	}
	cin.get();
}

100 ->float   S = 0, e = 0x85 ,f = (计算需补1)100100(100 = 0x64 = 1100100 = 1.100100*2^6) 

E = e - Bias = e - 2^7 +1=  6,F = 1.f = 0xC800

E*2^F = 100;

五、浮点数的精度

首先考虑float中的定义 FLT_EPSILON,意思为 “正float的0跨度值”,即满足 x+0.0 != 0.0 的最小正整数。

在32位系统中,该值等于 2^-23 约等于1.1920928955078125e-07 < 1.0e-6

该值计算可以通过:指数= 0 ,尾数取最小值来获得,即2^-23(f0取1其他取0)

由此,引申而来对float非0的判断或两数字相等判断,if(abs( a- b) < FLT_EPSILON)


六、指数取得38的原理

指数7位有效数字,指数原本-2^7-1 ~ 2^7由于bias的存储方式使得其存储内容为,-2^7~2^7 +1

然后2^7 + 1 相当于128,然后2^128,对应可以取得3.4*10^38,对应于S位的正负,因此float 的一个最大范围就是-3.4e+38~3.4e+38

而对应的最接近0,的非0数应该是,让指数取最负值,即-127,然后尾数取f=0,这个值大概为5.8e-39.


七、为何偏置非规范化值

1. 提供一种表示0值的方法,使用规格化M>=1而无法表示1,实际+0.0表示全0,M=f=0.符号位为1时,其他域为0,得到-0.0,偏置后使得只有一个0.

2. 那些非常接近0.0的数,提供了一种属性,逐渐溢出(gradual underflow),可能的数值分布均匀的接近0.0


八、特殊值

重要:指数全为1。

小数域全0,得到无穷,s=0,+无穷,s=1,-无穷。两大数相乘,或者除0,无穷可表示溢出结果。

小数域非0,NaN,一些运算的结果不能是实数或无穷,就会返回这样的NaN值,比如计算根号-1时候。(判断可以f!=f,或者isnan())

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值