我使用的是在 SoftFloat 库中实现的半 float (阅读:100% IEEE 754 兼容),为了完整起见,我希望为我的代码提供与 float.h> 用于 float
、double
和 long double
。
我知道有不同风格的半 float ,但我只对 IEEE 754 的标准化部分感兴趣,称为 binary16
。
根据我的研究和测试,我有信心定义一些常量如下:
#define HALF_MANT_DIG 11
#define HALF_DIG 3
#define HALF_DECIMAL_DIG 5
#define HALF_EPSILON UINT16_C(0x1400) /* 0.00097656 */
#define HALF_MIN UINT16_C(0x0400) /* 0.00006103515625 */
#define HALF_MAX UINT16_C(0x7BFF) /* 65504.0 */
注意:epsilon、min 和 max 定义为该类型采用的 16 位的原始十六进制表示。将原始值分配给类型的正确方法取决于所使用的半 float 库。
但是,对于与指数相关的定义,我未能达成共识。我看过Wikipedia page for binary16 , 在这other SO question , 在 Half library ,以及 GitHub 和其他地方的其他几个代码。
proposal linked从另一个 SO 问题听起来对我来说很有声望,以及 Half library 好消息是它们匹配。但是,我在 FP16.java implementation 发现了分歧。 , 在 this implementation , 在 Zig language implementation ,并在 Sargon对于 D.
#define HALF_MIN_EXP The article and Half say (-13) but FP16.java and sargon say (-14)
#define HALF_MAX_EXP The article and Half say 16 but others say 14 or 15
#define HALF_MIN_10_EXP The article and Half say (-4) but sargon says (-5)
#define HALF_MAX_10_EXP The article and Half say 4 but sargon says 5
我想这篇文章和 Half 可能是正确的来源,但是,我能确定 IEEE 754 binary16 的良好值吗?
最佳答案
#define HALF_MANT_DIG 11
是的,binary16 格式有 11 个有效数字(位)。 (10 存储在主要有效数字字段中,1 通过指数字段编码。)
#define HALF_DIG 3
我手头没有引用资料,所以不做评论。但这可以毫不费力地进行测试。
#define HALF_DECIMAL_DIG 5
IEEE 754-2019 将其定义为 1+ceiling(p×log10(2)),其中 p 是“数字格式中的有效位”,因此为 11,因此 1+ceiling(11•.3010299957) = 1+ceiling(3.3) = 1+4 = 5。
#define HALF_EPSILON UINT16_C(0x1400) /* 0.00097656 */
是的,有 11 个有效位,1 表示为高位 20 和低位 2−10,即 .0009765625。这是用 15 的指数偏差编码的,因此指数字段中为 5,所以 5 << 11
, 即 140016。
#define HALF_MIN UINT16_C(0x0400) /* 0.00006103515625 */
是的,最小正态指数编码为1,去除偏差得到-14,即.00006103515625,指数字段中的1给出 0400<子>16子>。
#define HALF_MAX UINT16_C(0x7BFF) /* 65504.0 */
是的,最大正规指数字段是30,30 << 11
给出 780016 并且最大有效数字段是 11111111112 = 3FF16,将它们合并给出 7BFF16。去除 15 的指数偏差得到 15,因此表示的值为 215•(2−2−10) = 65,504。
#define HALF_MIN_EXP The article and Half say (-13) but FP16.java and sargon say (-14)
#define HALF_MAX_EXP The article and Half say 16 but others say 14 or 15
C 将浮点表示定义为有效数位在小数点之后开始,而不是在小数点之前有一个,其余的在小数点之后。也就是说,对于基数为 b 的浮点格式,有效数在 [1/b, 1) 而不是 [1, b>).这在 *_MIN_EXP
的值中可见和 *_MAX_EXP
和 frexp
的行为函数,并且指数与 IEEE 754 中使用的更常见定义相差一个。
根据 IEEE-754,指数范围是 [−14, 15],因此,对于 C 标准的缩放,它是 [−13, 16]。
#define HALF_MIN_10_EXP The article and Half say (-4) but sargon says (-5)
C 2018 5.2.4.2.2 12 表示这是 ⌈log10bemin−1⌉,其中 emin 为 HALF_MIN_EXP
, 所以我们有 ⌈log102−13−1⌉ = ⌈−4.2144…⌉ = −4。我们从HALF_MIN
知道高于 10−4 是在正常范围内,而 10−5 不是,所以 −4 是“最小负整数,使得 10 的次方在范围内归一化 float ”,也在 5.2.4.2.2 12 中。
#define HALF_MAX_10_EXP The article and Half say 4 but sargon says 5
如上,C 标准将其表示为 ⌊log10((1−b− p)bemax)⌋ = ⌊log10((1−2− 11)2 16)⌋ = ⌊log10((1−2− 11)216)⌋ = ⌊log 10(65,504)⌋ = ⌊4.8162…⌋ = 4,而 104 低于 HALF_MAX
但是 105 不是。
关于ieee-754 - IEEE 754 binary16 半 float 的类似 float.h 的定义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73529209/