Floating point 为什么Swift使用基数2表示十六进制浮点值的指数?

Floating point 为什么Swift使用基数2表示十六进制浮点值的指数?,floating-point,swift,Floating Point,Swift,根据Swift编程语言: 例如,0xFp2表示15⨉ 2^2,计算结果为60。 类似地,0xFp-2表示15⨉ 2^(-2),计算结果为3.75 为什么指数的基数是2而不是16?我希望0xFp2==15*(16**2)而不是0xFp2==15*(2**2)Swift的浮点数十六进制表示法只是输入和输出的一种变体(使用printf%a格式) 这种表示法的目的是既便于人类解释,又能让人们在某种程度上辨认出符号的各个部分。IEEE 754表示法使用基数2。因此,对于普通浮点数,当p之前的数字介于1和2

根据Swift编程语言:

例如,0xFp2表示15⨉ 2^2,计算结果为60。 类似地,0xFp-2表示15⨉ 2^(-2),计算结果为3.75


为什么指数的基数是2而不是16?我希望
0xFp2==15*(16**2)
而不是
0xFp2==15*(2**2)
Swift的浮点数十六进制表示法只是输入和输出的一种变体(使用printf
%a
格式)

这种表示法的目的是既便于人类解释,又能让人们在某种程度上辨认出符号的各个部分。IEEE 754表示法使用基数2。因此,对于普通浮点数,当
p
之前的数字介于
1
2
之间时,
p
之后的数字直接是IEEE 754表示的指数字段的值。这符合人类可读性和接近bit表示的双重目标:

$ cat t.c
#include <stdio.h>

int main(){
  printf("%a\n", 3.14);
}
$ gcc t.c && ./a.out 
0x1.91eb851eb851fp+1
$cat t.c
#包括
int main(){
printf(“%a\n”,3.14);
}
$gcc t.c&./a.out
0x1.91eb851eb851fp+1
可以看到数字
0x1.91eb851eb851fp+1
略高于3,因为指数为
1
,有效位接近
0x1.9
,略高于
0x1.8
,表示二的两次幂之间的精确中间

这种格式有助于记住,十进制的紧凑表示形式的数字不一定是二进制的简单表示形式。在上面的示例中,
3.14
使用有效位的所有数字进行近似(即使如此,它也不能精确表示)

十六进制用于
p
之前的数字,它对应于IEEE 754格式的有效位,因为它比二进制更紧凑。IEEE 754 binary64数字的有效位要求在
0x1之后有13位十六进制数字。
才能完整表示,这是一个很大的数字,但需要52位二进制数字,这显然是不切实际的


十六进制的选择实际上有它的缺点:由于这种选择,同一个数字的几个等价表示并不总是容易识别为等价的。例如,
0x1.3p1
0x2.6p0
表示相同的数字,尽管它们的数字没有任何共同之处。在二进制中,这两个符号对应于
0b1.0011p1
0b10.011p0
,更容易将其视为等效符号。再举一个例子,
3.14
也可以表示为
0xc.8f5c28f5c28f8p-2
,很难将其视为与
0x1.91eb851eb851fp+1
相同的数字。如果
p
后面的数字表示16的幂,则不存在此问题,正如您在问题中所建议的,但是,当C99标准化时,表示的唯一性不是一个目标:接近IEEE 754表示是一个目标。

如果要为+/-0指定特定的表示,公平地说,任何特定类型的每个浮点数都会有一个唯一的标准表示形式,另外,要求前导数字为a
1
,并且指定的位数足以“填充”类型?@supercat编译器输出在实践中以类似于此的方式进行规范化(在我的编译平台上,除了80位
长双精度
;这是我获得3.14的替代形式的方式)。允许输入方向上的所有变量都有其优点,例如整数(0x7fffffff.0p0)和表项(如中所示)对于编译器来说,接受非规范表示肯定是有用的,特别是在许多值都是相同p的m/2^p形式的分数的情况下。sin(x)的输出具有从0到1的恒定有意义的动态范围,即使x接近pi;以非规范化形式显示值比以规范化形式显示值更清晰。