浮点数双精度,单精度以及半精度知识总结

本文深入介绍了浮点数的不同精度表示,包括单精度、双精度和半精度浮点数的结构和计算方法。重点讨论了半精度浮点数,包括其在存储和计算中的优势与限制,以及与单精度Bfloat16的对比。同时,提供了C语言中16位和32位浮点数之间的转换代码示例。
摘要由CSDN通过智能技术生成

最近工作中遇到一个16位半精度浮点数的问题,纠结了很久,特此研究了一下,总结在此:

1.单精度(32位)浮点数的结构:

 名称  长度 比特 位置

符号位 Sign(S):  1bit     (b31)

指数部分Exponent(E): 8bit    (b30-b23)

尾数部分Mantissa(M):  23bit    (b22-b0)

其中的指数部分(E)采用的偏置码(biased)的形式来表示正负指数,若E<127则为负的指数,否则为非负的指数。

注意:%f输出float类型,输出6位小数,有效位数一般为7位;

2. 双精度(64位)浮点数的结构

名称 长度 比特位置

符号位 Sign (S) : 1bit (b63)
指数部分Exponent (E) : 11bit (b62-b52)
尾数部分Mantissa (M) : 52bit (b51-b0)

双精度的指数部分(E)采用的偏置码为1023

求值方法:(-1)S*(1.M)*2(E-1023) (公式2)

注意:双精度数也可用%f格式输出,它的有效位一般为16位,给出小数6位。(这一点在计算金额的时候尤为重要,超过有效位的数字是无意义的,一般会出错。

3. 半精度(16位)浮点数结构

名称 长度 比特位置

符号位 Sign (S) : 1bit (b15)
指数部分Exponent (E) : 5bit (b14-b10)
尾数部分Mantissa (M) : 10bit (b9-b0)

最近还诞生了一种Bfloat16的计数方式,使用和半精度相同的位数,实现了保持和单精度一样的指数位也就是8位指数位,可以表示和单精度相同的数字范围,但是牺牲了小数位也就是精度。

半精度浮点数是一种计算机使用的二进制浮点数数据类型。半精度浮点数使用2字节(16位)存储。在IEEE 754-2008中,它被称作binary16。这种类型只适合用来存储那些对精度要求不高的数字,而不适合用来计算。
半精度浮点数是一种相对较新的浮点类型。 英伟达在2002年初发布的Cg语言中将它定义为 half 数据类型,并且首次在2002年末发布的GeForce FX中实现。ILM当时正在寻找一种能够有高动态范围,并且不需要过多消耗硬盘以及内存,而且能像单精度浮点数和双精度浮点数那样被用来进行浮点计算的图像格式。由SGI的John Airey领导的硬件加速可编程着色小组在1997年发明了作为’bali’设计工作的一部分的s10e5数据类型。这曾在SIGGRAPH2000年的论文中介绍过。(见章节 4.3)并且在美国专利7518615中被进一步记录。
半精度浮点数可以在包括OpenEXR,JPEG XR,OpenGL,Cg语言和D3DX等数种计算机图形环境中使用。与8位或16位整数的相比,它的优点是可以提升动态范围,从而使高对比度图片中更多细节得以保留。与单精度浮点数相比,它的优点是只需要一半的存储空间和带宽(但是会以精度和数值范围为代价)

半精度浮点数详解:

IEEE754-2008包含一种“半精度”格式,只有16位宽。故它又被称之为binary16,这种类型的浮点数只适合用于存储那些对精度要求不高的数字,不适合用于进行计算。与单精度浮点数相比,它的优点是只需要一半的存储空间和带宽,但是缺点是精度较低。

半精度的格式与单精度的格式类似,最左边的一位仍是符号位,指数有5位宽且以余-16(excess-16)的形式存储,尾数有10位宽,但具有隐含1。

如图所示,sign为符号位,0表示这个浮点数为正,1表示这个浮点数为负

先介绍尾数,再说指数,fraction为尾数,有10位长,但是有隐含1,尾数可以理解为是一个浮点数小数点后的数,如1.11,尾数就为1100000000(1),最后的隐含1主要用于计算时,隐含1可能存在可以进位的情况。

exponent为指数位,有5位长,具体表示的值有以下几种情况:

当指数位全为0 ,尾数位也全为0的时,表示的就是0
当指数位全为0,尾数位不全为0时,表示为subnormal value,非规格化浮点数,是一个非常小的数
当指数位全为1,尾数位全为0时,表示的是无穷大,此时如果符号位为0,表示正无穷,符号位为1,表示负无穷
当指数位全为1,尾数位不全为0时,表示的不是一个数
其余情况下,指数位的值减去15就是其表示的指数,如11110表示的就是30-15=15
所以我们可以得到,半精度浮点数的值得计算方式为(-1)^sign×2^(指数位的值)×(1+0.尾数位) 

备注:这里0.尾数位,表示如尾数位为0001110001,则0.尾数位为0.0001110001

举几个例子:

半精度可以表示的最大值:0 11110 1111111111 计算方法为:(-1)^0×2^(30-15)×1.1111111111 = 1.1111111111×2^15,即十进制的65504
半精度可以表示的最小值(除了subnormal  value):0 00001 0000000000 计算方法为:(-1)^(-1)×2(1-15)=2^(-14),约等于十进制的6.104×10^(-5)
再举一个平常的数,这次反过来,如-1.5625×10^(-1) ,即-0.15625 = -0.00101(十进制转二进制)=  -1.01×2^(-3),所以符号位为1,指数为-3+15=12,所以指数位为01100,尾数位为0100000000。所以-1.5625×10^(-1)用半精度浮点数表示就为1 01100 0100000000

代码实测:

Float16ToFloat32:

可以把16位的float IEEE754规范的int值转成32位的float

float Float16ToFloat( short fltInt16 )
{
    int fltInt32    =  ((fltInt16 & 0x8000) << 16);
    fltInt32        |= ((fltInt16 & 0x7fff) << 13) + 0x38000000;

    float fRet;
    memcpy( &fRet, &fltInt32, sizeof( float ) );
    return fRet;
 }

Float32ToFloat16:

可以把32的float IEEE754规范转化为16位int值

short FloatToFloat16( float value )
{
    short   fltInt16;
    int     fltInt32;
    memcpy( &fltInt32, &value, sizeof( float ) );
    fltInt16    =  ((fltInt32 & 0x7fffffff) >> 13) - (0x38000000 >> 13);
    fltInt16    |= ((fltInt32 & 0x80000000) >> 16);

    return fltInt16;
}

参考链接:

半浮点数详解

浮点数单精度32b与半精度16b转换C语言IEEE 754浮点数单精度32b与半精度16b转换C语言IEEE 754

半精度浮点数和单精度浮点数的转换(不考虑特殊情况)

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ppipp1109

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值