【问题标题】:Why does Swift use base 2 for the exponent of hexadecimal floating point values?为什么 Swift 使用以 2 为底的十六进制浮点值的指数?
【发布时间】:2014-06-29 15:31:24
【问题描述】:

根据Swift 编程语言

例如,0xFp2 表示 15 ⨉ 2^2,其计算结果为 60。 同样,0xFp-2 表示 15 ⨉ 2^(-2),其计算结果为 3.75。

为什么使用 2 而不是 16 作为指数的底?我本来希望0xFp2 == 15 * (16**2) 而不是0xFp2 == 15 * (2**2)

【问题讨论】:

    标签: floating-point swift


    【解决方案1】:

    Swift 的浮点数十六进制表示法只是 notation introduced for C in the C99 standard 的一种变体,用于输入和输出(使用 printf %a 格式)。

    该符号的目的是为了便于人类解释,同时让IEEE 754 representation 的位在一定程度上易于识别。 IEEE 754 表示使用以二为基数。因此,对于一个普通的浮点数,当p之前的数字在12之间时,p之后的数字直接是IEEE 754表示的指数字段的值。这符合人类可读性和接近位表示的双重目标:

    $ cat t.c
    #include <stdio.h>
    
    int main(){
      printf("%a\n", 3.14);
    }
    $ gcc t.c && ./a.out 
    0x1.91eb851eb851fp+1
    

    可以看到数字0x1.91eb851eb851fp+1 略高于 3,因为指数为1,有效数字靠近0x1.9,略高于0x1.8,这表示两个2 的幂之间的精确中间值。

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

    p 之前的数字使用十六进制,它对应于 IEEE 754 格式中的有效位,因为它比二进制更紧凑。 IEEE 754 binary64 数字的有效位需要0x1. 之后的 13 个十六进制数字才能完全表示,这很多,但在二进制中需要 52 位数字,这坦率地说是不切实际的。

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

    【讨论】:

    • 公平地说,任何特定类型的每个浮点数都将具有该形式的唯一规范表示,如果要为 +/- 零指定特定表示,否则需要前导数字是1 并且指定的位数足以“填写”类型?
    • @supercat 编译器输出实际上以与此类似的方式标准化(在我的编译平台上,除了 80 位 long double;这就是我获得 3.14 的替代形式的方式)。允许输入方向的所有变体有其优势,例如对于整数 (0x7fffffff.0p0) 和表条目(如 stackoverflow.com/a/23726810/139746 中)
    • 编译器接受非规范表示当然很有用,尤其是在许多值是 m/2^p 对于相同 p 形式的分数的情况下。 sin(x) 的输出具有从 0 到 1 的恒定有意义动态范围,即使 x 接近 pi 也是如此;以非规范化形式显示值使得它们的相对重要性比以规范化形式显示它们更清晰。
    猜你喜欢
    • 2022-11-25
    • 2014-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-05
    • 1970-01-01
    • 1970-01-01
    • 2010-12-08
    相关资源
    最近更新 更多