IEEE 754浮点数构成与转换

IEEE 754 标准是现在主流的浮点数标准,除了常见语言中的 FP32、FP64 之类的类型,还有一些为了量化、加速深度学习的 FP8 类型(E4M3、E5M2)也是使用 IEEE 754 标准来定义无穷等含义。此外,通过了解和学习,在研究其他浮点数格式的时候也会有帮助,比如机器学习使用的 BFLOAT16。

如果你是为了考试,那么本文可能不太适合你,因为教材上使用的 IEEE 754 和 2008 往后版本的区别不少。

下图是 FP32、FP16、BF16 三种浮点格式对比(图自BFloat16: The secret to high performance on Cloud TPUs - Google Cloud
改编自 2018 年 TensorFlow 开发者峰会上展示的培训性能幻灯片

本文主要以 IEEE 754 的 FP32 为例,展示结构和如何得到浮点数。

数据结构

IEEE 754 中,浮点数的结构为:

结构:	|符号|阶码|尾数|
FP32:	|1位|8位|23位|
FP64:	|1位|11位|52位|

举个例子, − 12.2 5 3 -12.25^3 12.253,基数(基值)为 2(也就是使用二进制表示):

  • 符号为-,也就是1
  • 尾数为12.25,也就是1100.01

IEEE 中没有记录小数点位置的地方,也就是可以节约这些空间。如何做到这点的呢?这就是规格化。

也就是强制小数点在第一个1后面。于是可以得到 1.10001 1.10001 1.10001x 2 3 2^{3} 23

  • 阶码就是上面这个数中的指数部分+偏移量。FP32 偏移量为 127,3+127=130的二进制为1000 0010

这时候得到 − 12.2 5 3 -12.25^3 12.253的二进制表达为:
− 1.10001 ∗ 2 10000010 -1.10001*2^{1000 0010} 1.10001210000010

在机器中存放的时候,需要忽略尾数的最高的1,因为规格化要求小数点必须在第一个1后面。也就是说小数点前面肯定有个1,可以省下来一位,提高精度:

|  符号1位	|    阶码8位		|		       尾数23位				|
	  1			1000 0010		1000 1000 0000 0000 0000 0000

偏移量

这时候你可能好奇计算阶码的时候偏移量是什么,127是哪来的?

来看看文档(这个表格非常不错,如果你能理解每一个单元的含义,相信你也就真的懂了 IEEE 754。从中你也可以看到所谓的“阶码”、“尾数”的含义,我是没想到“尾数”居然是从英文翻译过来的):
请添加图片描述

会发现偏移(bias)就是“emax, maximum exponent e”,也就是最大指数e,计算方法其实是:

2 总位数 − 尾数 − 1 2^{总位数-尾数-1} 2总位数尾数1

为什么要有个偏移呢?

我在《原码、补码、反码、移码是什么?》- ZhongUncle’s CSDN中介绍移码的时候说到,它的含义就是“给数加上一个偏移数后,使其具有非负的表达形式”。

接下来我来解释这句话

下面e为指数,E为阶值。
E=e+bias
FP32 的bias127
所以e的范围由Ebias决定。

E的范围是 1 1 1~ ( 2 n − 2 ) (2^n-2) (2n2),根据这个范围和上面的公式,可知指数e的范围是 ( 1 − 2 n ) (1-2^n) (12n)~ − 1 -1 1,也就是说,全是负的。加上偏移量bias之后,得到的阶码E就是正的了。这就是移码。

此外,你会发现E有两个数没有定义:E=0 和E= ( 2 n − 1 ) (2^n-1) (2n1),这也是为什么 FP32 的阶值E有 8 位,但是最大值是127,而不是255,是因为有一位用来表达其他的内容了。

阶值和尾数全为1或0的含义

教材中的IEEE 754(早期版本)

在某些教材中,会告诉你阶码自己也有个符号位,这么记也好。而且很多计算题都是这么出的。

1位	|	  8位	|23位|
|  符号	|阶符 | 阶码|尾数|

这里阶码全是1的情况就要讨论了:

  • 如果此时尾数非零,符号位任意,那么为NaN(不分两种);
  • 如果此时尾数为零,符号位为0(正),那么表示正无穷大;
  • 如果此时尾数为零,符号位为1(负),那么表示负无穷大;

这里阶码全是0的情况就要讨论了:

  • 如果此时尾数非零,符号位任意,那么为非规格化数,这里表示的阶值为-126,而且节约掉的小数点前那位是0
  • 如果此时尾数为零,符号位为0(正),那么表示正零;
  • 如果此时尾数为零,符号位为1(负),那么表示负零;

IEEE 754 2019

下面这段内容是我在 IEEE 754 2019 上看到的,早期的版本(2008 之前)似乎没有这个定义或者不明确,如果你要考试就别看了,容易干扰。

不论后面尾数是什么,阶码1111 111x前面的1111 111是表示NaN,也就是无定义的数。

如果最后一位为1,则是sNaN(signaling NaN),否则为qNaN(quiet NaN)。二者的区别在于“signaling(信号)”,前者会发出一些浮点异常信号,所以经常在异常和处理机制中使用,后者很少发出浮点异常信号,就是“安静”。

浮点十进制转二进制

浮点数十进制转二进制的时候,需要分别考虑整数和小数部分。

8.25为例。

整数部分8

2|__8__       	----0
  2|__4__   	----0
	2|__2__		----0
	    1		----1	

然后倒着取上面右列的结果,为1000

小数部分0.25

 0.25
x   2
------
 0.50 		----整数部分为0
x   2
------
 1.00 		----整数部分为1

按顺序取结果的整数部分,也就是01

合起来就是1000.01

浮点二进制转十进制

反过来转换方法如下。

1000.01为例。

整数部分1000

1	0	0	0
2^3 2^2 2^1 2^0
1x8+0x4+0x2+0x1=8

按位置对应的次方( 2 n − 1 2^{n-1} 2n1)相加结果为8

小数部分0.01同样使用位置对应的次方,不过这里小数点后面第一位对应的就是 2 − 1 2^{-1} 21,如下:

0			1
2^(-1)	2^(-2)
0x0.5	+ 	1x0.25	= 0.25

结果为0.25

整数和小数部分相加,得到8.25

浮点的加减计算

浮点数的运算时分开进行阶码和尾数运算。

对齐小数点

上面规格化的时候,我们强制让第一个1出现在小数点左边,所以不能直接尾数和尾数、阶数和阶数运算。比如 3.2 3.2 3.2x 1 0 3 10^3 103 1.2 1.2 1.2x 1 0 4 10^4 104就不能直接各部分相加。

所以我们要对齐小数点,换句话说就是对齐阶数。比如上面的 1.2 1.2 1.2x 1 0 4 10^4 104变成 12 12 12x 1 0 3 10^3 103就可以各部分相加了。

二进制的时候,由于阶数是倒着数的,所以小的一个加一个数就和大的一样了,或者大的减一个数就和小的一样。

比如指数3对应阶数为1000 00104对应的是1000 0011,可以看到前者加一就是后者。

在对齐小数点的时候,也要对尾数进行操作,方法就是右移(或者乘 2,对于二进制无符号数来说,这两个操作是等价的,右移更快,因为位移的电路比乘法的“便宜”)。

加减尾数

阶数对齐之后,注意还有规格化忽略掉的一位,还原那一位之后,就可以直接加减尾数了。

再次规格化

在计算完之后,需要对结构再次规格化。如果在规格化的时候,有位超出了规定位数,就要舍去了。方法有四种:

  • 0 舍 1 入(二进制版“四舍五入”);
  • 正向舍入:取大于自己的第一个可取数;
  • 负向舍入:取小于自己的第一个可取数;
  • 截断法:直接舍去超出的部分。

判断指数是否溢出

计算完之后要判断结果的指数是否超出范围,也就是是否溢出。

以 FP32 为例:

  • 如果指数超出 127,那么发生上溢,产生一个异常;
  • 如果指数小于 127,那么发生下溢,通常直接当0

希望能帮到有需要的人~

参考资料

IEEE 754-2019 - IEEE Standard for Floating-Point Arithmetic:2019年的新文档

IEEE 754-1985 - IEEE Standard for Floating-Point Arithmetic
:1985年的老文档。

BFloat16: The secret to high performance on Cloud TPUs - Google Cloud

Signaling NaN - From MathWorld

  • 8
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: IEEE 754浮点数是一种可表示实数的标准格式,在计算机科学中被广泛使用。LabVIEW作为一种高级程序设计语言,也支持IEEE 754浮点数转换。 在LabVIEW中,将浮点数转换IEEE 754格式可以通过使用“Type Cast”或“Flatten to String”函数来实现。Type Cast函数可以将任何数据类型转换为另一个数据类型,而Flatten to String函数则将任何数据类型转换为字符串格式。 另外,在LabVIEW中还可以使用“IEEE Floating Point”面板对象来表示IEEE 754浮点数。这个对象有多种不同的显示格式,可以根据实际需要选择。 同时,也可以使用“Unflatten from String”函数将字符串格式的IEEE 754浮点数转换为实数。这个函数与“Flatten to String”函数相对应,可以将任何字符串转换为指定数据类型的数据。 总之,通过上述方法,在LabVIEW中可以方便地进行IEEE 754浮点数转换和表示,方便实现各种复杂的计算任务。 ### 回答2: IEEE754浮点数是现代计算机系统中广泛使用的一种二进制数表示方法,用于表示实数。在LabVIEW中,通过使用数字数据类型的标签来指定浮点数据是单精度浮点数还是双精度浮点数。 为将浮点数转换IEEE754浮点数,需要将浮点数的符号、阶码和尾数转换成对应的二进制格式。在单精度浮点数中,符号位占1位,阶码占8位,尾数占23位,而在双精度浮点数中,符号位占1位,阶码占11位,尾数占52位。在进行浮点数转换时,需要注意计算机浮点数的字节序,以正确存储转换后的IEEE754浮点数。 为了在LabVIEW中完成浮点数转换,可以使用“单精度浮点数转换”或“双精度浮点数转换”函数。这些函数可以将浮点数转换IEEE754浮点数,并将结果存储在指定的输出变量中。此外,在LabVIEW中也可以使用“数字到字符串”函数,将浮点数转换为字符串格式,方便输出或显示。 需要注意的是,由于浮点数的精度限制,在进行浮点数计算时可能会出现舍入误差,这些误差可能会影响计算结果的精度和准确性。因此,在LabVIEW中进行浮点数计算时,需要注意浮点精度问题,并尽可能采用正确的计算方法来避免误差积累的影响。 ### 回答3: IEEE 754浮点数是一种二进制数的表示方式,用于表示实数。这种表示方式包括三个部分:符号位、指数位和尾数位。 在LabVIEW中,可以使用Float to Hex和Hex to Float这两个函数进行IEEE 754浮点数转换。Float to Hex函数将一个浮点数转换成其对应的16进制数,而Hex to Float函数将16进制数转换成对应的浮点数。 在进行转换时,需要注意保留位数的问题。IEEE 754浮点数中有单精度浮点数和双精度浮点数,其精度分别为32位(4字节)和64位(8字节)。在LabVIEW中,Float to Hex函数默认输出8位16进制数,而Hex to Float函数默认输入8位16进制数。如果需要更多的位数精度,可以在函数的属性中进行相应的设置。 除了转换函数外,LabVIEW中还提供了计算IEEE 754浮点数的函数,如Get Single Precision Float Info和Get Double Precision Float Info。这些函数可以获取浮点数的符号位、指数位和尾数位等信息,方便进行更复杂的运算。 总之,IEEE 754浮点数转换在LabVIEW中非常方便快捷。使用Float to Hex和Hex to Float这两个函数,可以轻松地完成浮点数转换,而通过更复杂的函数,还可以进行精度更高的运算。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值