繁体   English   中英

线应该是什么意思?

[英]What does line is supposed to mean?

float sqrt_approx(float z) {
    int val_int = *(int*)&z; /* Same bits, but as an int */
    /*
     * To justify the following code, prove that
     *
     * ((((val_int / 2^m) - b) / 2) + b) * 2^m = ((val_int - 2^m) / 2) + ((b + 1) / 2) * 2^m)
     *
     * where
     *
     * b = exponent bias
     * m = number of mantissa bits
     *
     * .
     */

    val_int -= 1 << 23; /* Subtract 2^m. */
    val_int >>= 1; /* Divide by 2. */
    val_int += 1 << 29; /* Add ((b + 1) / 2) * 2^m. */

    return *(float*)&val_int; /* Interpret again as float */
}

我正在阅读有关计算平方根的方法的 wiki 文章。 我来到了这段代码,并在这一行加注了星标。

 int val_int = *(int*)&z; /* Same bits, but as an int */

为什么他们将 z 转换为 int 指针然后取消引用它? 为什么不直接说val_int = z; 为什么要使用指针? PS:我是初学者。

这称为类型双关语 这种特殊用法违反了严格的别名规则

通过获取浮点值 z 的地址,并将其重新解释为 integer 值的地址,作者试图访问表示此浮点数的内存字节,但方便的是int

它与 int val_int = z; 不同。 这会将浮点值转换为 integer,从而导致 memory 中的位不同。

除了严格的别名问题之外,这里的一个大问题是代码对任何目标系统上的int大小字节序进行了假设。 因此,代码不可移植。

访问z字节的正确方法是char数组:

const uint8_t* zb = (const uint8_t*)&z;

然后,您可以使用特定的字节顺序从这些构造一个适当大小的 integer :

uint32_t int_val = ((uint32_t)zb[0]) |
                   (((uint32_t)zb[1]) << 8) |
                   (((uint32_t)zb[2]) << 16) |
                   (((uint32_t)zb[3]) << 24);

这类似于一个更简单的调用,假设您使用的是 little-endian 系统:

uint32_t int_val;
memcpy(&int_val, &z, sizeof(int_val));

但这不是全貌,因为float字节序是标准化的(至少,假设您的代码针对的是IEEE 754 ),而int是系统相关的。

至此,整个例子就崩溃了。 在基本层面上,原始代码是(假设)基于技巧的快速近似。 如果您想“正确”地执行这些技巧,那会变得有些混乱。

发生的情况是int val_int = *(int*)&z浮点数的位重新解释为整数或更确切地说是位域,并直接对浮点数的符号、尾数和指数进行操作,而不是依赖于处理器的操作。

int val_int = z将应用从 float 到 int 的转换——一个完全不同的操作。

通常,不建议此类操作,因为在不同的平台上,尾数、指数和符号的解释和位置可能有不同的约定。 int也可能具有不同的大小。 此外,最可以肯定的是,本地操作更高效、更可靠。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM