Ade*_*kal 2 c c++ floating-point pointers reference
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 */
}
Run Code Online (Sandbox Code Playgroud)
我正在阅读一篇关于计算平方根方法的维基文章。我来到了这段代码,并在这一行出演。
int val_int = *(int*)&z; /* Same bits, but as an int */
Run Code Online (Sandbox Code Playgroud)
为什么他们将 z 转换为 int 指针然后取消引用它?为什么不直接说val_int = z;
为什么要使用指针呢?PS:我是初学者。
这称为类型双关。这种特殊用法违反了严格的别名规则
通过获取浮点值 z 的地址,并将其重新解释为整数值的地址,作者试图访问表示此浮点数的内存字节,但为了方便 a int。
它与 int val_int = z; 不同。这会将浮点值转换为整数,从而导致内存中的位不同。
除了严格的别名问题之外,这里的一个大问题是代码int对任何目标系统上的大小和字节序进行了假设。因此,代码不可移植。
访问字节的正确方法z是char数组:
const uint8_t* zb = (const uint8_t*)&z;
Run Code Online (Sandbox Code Playgroud)
然后,您可以从这些具有特定字节序的整数中构造一个适当大小的整数:
uint32_t int_val = ((uint32_t)zb[0]) |
(((uint32_t)zb[1]) << 8) |
(((uint32_t)zb[2]) << 16) |
(((uint32_t)zb[3]) << 24);
Run Code Online (Sandbox Code Playgroud)
这类似于一个更简单的调用,假设您使用的是小端系统:
uint32_t int_val;
memcpy(&int_val, &z, sizeof(int_val));
Run Code Online (Sandbox Code Playgroud)
但这并不是全貌,因为float字节序是标准化的(至少,假设您的代码针对的是IEEE 754)而int依赖于系统。
在这一点上,整个示例崩溃了。在基本层面上,原始代码是基于技巧的(据说)快速近似。如果你想“正确”地做这些技巧,它就会变得有点混乱。
| 归档时间: |
|
| 查看次数: |
78 次 |
| 最近记录: |