似乎关于IEEE 754标准中十进制浮点数的中文资料不多,所以写了这篇。
什么是十进制浮点数
十进制浮点数(Decimal floating-point,DFP)是指以10为底数的浮点数表示法,主要解决的是二进制浮点数(Binary floating-point,BFP,常见的浮点数,底数为2)存在的精度问题(例如在财务计算等场景下,使用二进制浮点数经常无法满足需求)。
关于IEEE的十进制浮点数的一些历史。
- IEEE 854中规范引入了十进制浮点数,但其标准不够完善,缺少对用来和其他系统交换的数据编码方式的规定。
- IEEE 754-2008(IEEE浮点运算标准,此为2008年发布的修订版)中合并了IEEE 854中对十进制浮点数的规范,并且补全了之前的缺陷。ISO/IEC/IEEE 60559:2011标准与此标准内容相同。
- IEEE 754-2019是现行有效的修订版本,相关的修改不是很多。
编码
和二进制浮点数相似,也有符号(Sign)、阶码(Exponent,指数)和尾数(Coefficient)三个部分。但不同点是它不一定都是规格化(Normalized)的,即尾数的最高位不一定是1,所以一些数值可以有多种表示方法,例如1×102=0.1×103;而且多了一个组合位(Combination field),用来扩展阶码和尾数的范围以提高存储空间利用率;剩下的“剩余位”,就是组合位组合剩下的(参见“具体规则”一节的“编码规则”小节)。
DFP的存储格式:
| 长度 | 符号位 | 组合位 | 阶码剩余位(e) | 尾数剩余位(m) |
| 32位(Decimal32) | 1 | 5 | 6 | 20 |
| 64位(Decimal64) | 8 | 50 | ||
| 128位(Decimal128) | 12 | 110 | ||
| 32k位(Decimal32k) | 2k+4 | 30k-10 |
DFP的数据范围:
| 长度 | 尾数长度(十进制的数字位数)(p) | 指数范围(从0到x) | 数据最大值(Emax) | 归一化后的数据最小值(Emin) | 数据最小非零值(Etiny) | |
| 32位 | 7 | 192 | 96 | -95 | -101 | |
| 64位 | 16 | 768 | 384 | -383 | -398 | |
| 128位 | 34 | 12288 | 6144 | -6143 | -6176 | |
| 32k位 | (3t)/10+1 | 或者9k-2 | 3×2e=48×4k | 3×2e-1 | 1-Emax | 2-p-Emax |
为了描述的简洁,后续的介绍中会引用表中的字母来代指对应的数据,对照如下:
- e:阶码剩余位的长度
- m:尾数剩余位的长度
- p:尾数以十进制表示的数字位数
- x:指数的最大取值
有效数字的两种不同编码方式
这两种不同的编码方式都可以用于编码阶码和尾数,且不论用哪种方式都不影响编码规则(数据范围相同)。
- 二进制整数编码的有效位(Binary integer significand field,BIS或BID)
- 它使用二进制整数(取值在0到(10p-1)之间)来编码有效数字。
- 适合于在原本用于处理二进制的算数逻辑单元(ALU)上用软件实现DFP。
- 紧凑十进制编码的有效位(Densely packed decimal significand field)
- 紧凑十进制编码(Densely packed decimal,DPD)能更好地编码十进制数字,可以加快与二进制浮点数的相互转换。
- 需要专用的ALU来提高效率,适合用硬件实现的DFP。
- DPD编码是一种效率较高的BCD编码,但其细节不属于本文的内容,可以参考它的维基百科页面(本文的引用[3])。
具体规则
对阶码和尾数的约束
阶码最多(2+e)位,最高2位二进制只能取00、01、10。
尾数最多(4+m)位,最高4位二进制只允许0000~1001(即十进制的0~9)。
编码规则
符号位的定义和二进制浮点数中的相同,0表示正数,1表示负数。
当尾数的最高4位是0000~0111(即十进制的0~7)时,省略最高位相同的0,此时组合位前两位是阶码最高2位的三种取值,后三位是尾数剩下的000~111。
当尾数的最高4位是1000~1001(即十进制的8或9)时,省略最高3位相同的100,此时组合位的前两位是11,再往后两位是阶码最高2位的三种取值,最后一位是尾数剩下的0或者1。
余下的e位阶码和m位尾数分别存入阶码剩余位和尾数剩余位。
如果阶码或尾数的编码结果长度n不足以填充所有位时——即长度小于(2+e)或者(4+m),则先填满组合位,剩下的(e-n)或者(m-n)位在左侧补0。
特殊值的表示
正负无穷(±∞):组合位是11110,符号位表示正负。
静默NaN(Quiet NaN,QNaN):组合位为11111,阶码剩余位的最高位是0。
信号NaN(Signaling NaN,SNaN):组合位为11111,阶码剩余位的最高位是1。
对于这两种NaN,没有提到的所有位都会被忽略,因此初始化数组为NaN可以通过简单地把内存区域全部填充为某个字节来实现(例如全部填充0x7E=(0111 1110)b,会被解码为SNaN)。
这两种NaN的主要区别是QNaN用于表示计算无效,例如0/0等,它会静默传播,参与的所有运算结果都为QNaN;而SNaN用于快速失败(Fail-fast),在使用时产生异常。
参考资料
- IEEE Standards Association. IEEE Standard for Floating-Point Arithmetic: IEEE Std 754-2019[S]. New York: IEEE, 2019-07-22. ISBN: 978-1-5044-5924-2. DOI: 10.1109/IEEESTD.2019.8766229. ICS Code: 07.020, 35.080. Available at: https://ieeexplore.ieee.org/servlet/opac?punumber=8766227.
- Wikipedia contributors. Decimal floating point[EB/OL]. Wikipedia, The Free Encyclopedia. [2024-09-24]. [2024-11-16]. Available at: https://en.wikipedia.org/w/index.php?title=Decimal_floating_point&oldid=1247444055.
- Wikipedia contributors. Densely packed decimal[EB/OL]. Wikipedia, The Free Encyclopedia. [2024-06-30]. [2024-11-18]. Available at: https://en.wikipedia.org/w/index.php?title=Densely_packed_decimal&oldid=1237650875.
发表回复