c - 平方根 union 和位移位

标签 c bit unions shift

我发现了这段获得平方根的代码,令我惊讶的是它的工作方式,使用 union 和位移这是代码:

float sqrt3(const float x)  
{
  union
  {
    int i;
    float x;
  } u;

  u.x = x;
  u.i = (1<<29) + (u.i >> 1) - (1<<22); 
  return u.x;
} 

先把u.x的值保存在u.x中,然后给u.i赋值,然后求平方根,神奇地出现u.x

¿有人向我解释一下这个算法吗?

最佳答案

以上代码表现出 UB(未定义行为),因此不应相信它可以在任何平台上运行。这是因为它写入 union 的成员,并从与上次用于写入 union 的成员不同的成员中读回。它还在很大程度上取决于字节序(多字节整数中字节的顺序)。

但是,它通常会执行预期的操作,并了解为什么值得您阅读 IEEE 754 binary32 floating-point format .

IEEE754 binary32 格式速成类(class)

IEEE754通常将一个32位的 float 分成1个符号位、8个指数位和23个尾数位,从而得到

                   31 30-23           22-0
Bit#:               ||------||---------------------|
Bit Representation: seeeeeeeemmmmmmmmmmmmmmmmmmmmmmm
Value:              sign * 1.mantissa * pow(2, exponent-127)

数字本质上是“科学记数法,基数 2”。

作为一个细节,指数以“有偏差”的形式存储(也就是说,它的值高了 127 个单位)。这就是我们从编码指数中减去 127 以获得“真实”指数的原因。

简短说明

您的代码所做的是指数部分减半并损坏尾数。这样做是因为一个数的平方根的指数大约是幅度的一半

以 10 为基数的例子

假设我们想要 4000000 = 4*10^6 的平方根。

4000000 ~ 4*10^6  <- Exponent is 6
4000    ~ 4*10^3  <- Divide exponent in half

只需将指数 6 除以 2,得到 3,并将其作为新指数,我们就已经在正确的数量级内,并且更接近真相,

2000 = sqrt(4000000)

.

关于c - 平方根 union 和位移位,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28264277/

相关文章:

c - C中什么情况下可以使用long int

c - 将 getline() 输出保存到外部数组

c++ - sprintf 和 char [] 与字符串

c++ - 检查 union 平等

c - 为什么 GCC 在使用 WinAPI : COLORREF/RGB? 时不报告任何错误或警告

javascript - 使用 % 和获取奇数/偶数的最低有效位之间的区别

c - 如何在 C 中正确地重新分配一个位数组

c# - 如何检查字节数组中有多少位?

c - 使用 union 存储的值显示不正确

recursion - F# - 在运行时创建递归可区分联合