我发现这个获得平方根的代码让我感到惊讶的是它的方式,使用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
¿有人向我解释这个算法怎么样?
答案 0 :(得分:3)
上面的代码展示了UB(未定义的行为),因此不应该信任它在任何平台上工作。这是因为它写入union
的成员并从与上次用于编写union
的成员不同的成员读回。它还在很大程度上取决于字节顺序(多字节整数内字节的排序)。
然而,它通常会做出预期的事情,并理解为什么值得您阅读IEEE 754 binary32 floating-point format。
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 部分减半并损坏尾数。这是完成的,因为数字的平方根的指数大约是幅度的一半。
假设我们想要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并将值转换回来。