平方根联合和位移

时间:2015-02-01 15:20:29

标签: c bit unions shift

我发现这个获得平方根的代码让我感到惊讶的是它的方式,使用union和bit shift这就是代码:

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;
} 

首先保存在 ux x 的值中,然后为 ui 分配一个值,然后是数字的平方根,并且会神奇地显示的 UX

¿有人向我解释这个算法怎么样?

2 个答案:

答案 0 :(得分:3)

上面的代码展示了UB(未定义的行为),因此不应该信任它在任何平台上工作。这是因为它写入union的成员并从与上次用于编写union的成员不同的成员读回。它还在很大程度上取决于字节顺序(多字节整数内字节的排序)。

然而,它通常会做出预期的事情,并理解为什么值得您阅读IEEE 754 binary32 floating-point format

IEEE754二进制32格式的速成课程

IEEE754通常将32位浮点数分为1个符号位,8个指数位和23个尾数位,从而得出

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

这个数字基本上是“科学记数法,基础2”。

作为细节,指数以“偏向”形式存储(即,它具有127个单位的值太高)。这就是我们从编码指数中减去127得到“真实”指数的原因。

简短说明

你的代码所做的是 exponent 部分减半并损坏尾数。这是完成的,因为数字的平方根的指数大约是幅度的一半

基地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)

答案 1 :(得分:1)

您可以在维基百科上找到完美的解释:

Methods of computing square roots

参见章节:取决于浮点表示的近似值

  

因此,对于IEEE格式的32位单精度浮点数   (特别值得注意的是,功率偏差为127   form)你可以通过解释它的二进制来得到近似的对数   表示为32位整数,将其缩放2 ^ { - 23},和   消除127的偏见,即

     

要获得平方根,将对数除以2并将值转换回来。