[英]What is the exact value of the first type-punning in fast square root inverse algorithm?
Having this code, (this is a well-known fast square root inverse algorithm, that was used in Quake 3) I am unable to understand the print output. 有了这段代码,(这是Quake 3中使用的众所周知的快速平方根逆算法),我无法理解打印输出。 I understand the entire algorithm superficially but want to get an in-depth understanding.
我从表面上了解了整个算法,但希望获得深入的了解。 What is the value of
i
when printf
prints it? printf
打印时i
的值是什么? This gives 1120403456 for me. 这给了我1120403456。 Does it depend on the computer's architecture?
是否取决于计算机的体系结构? I've read somewhere that type-punning like this results in undefined behaviour.
我读过某处这样的类型操纵会导致不确定的行为。 On the other website I've read that the value of
i
at that point is the exact value of bits that are used by this variable. 在另一个网站上,我读到了那时
i
的值是此变量使用的位的确切值。 I am confused with this and honestly expected the value of i
to be 100. How do I interpret the resulting 1120403456? 我对此感到困惑,并且诚实地期望
i
的值为100。如何解释结果1120403456? How do I convert this value to decimal 100? 如何将此值转换为十进制100? Are those bits encoded somehow?
这些位是以某种方式编码的吗? This is the code excerpt:
这是代码摘录:
#include<stdio.h>
int main()
{
float x = 100;
float xhalf = 0.5f*x;
int i = *(int*)&x;
printf("%d", i);
i = 0x5f3759df - (i>>1);
x = *(float*)&i;
x = x*(1.5f-xhalf*x*x);
return x;
} }
The value of i
printed after int i = *(int*)&x;
在
int i = *(int*)&x;
之后打印的i
的值int i = *(int*)&x;
is the bit representation of the floating-point 100.0
, which is what x was initialised to. 是浮点数
100.0
的位表示形式,这是x初始化的对象。 Since you're using the %d
format in printf
it will print that representation as a decimal integer. 由于您在
printf
使用%d
格式,因此它将表示形式打印为十进制整数。
The bitpattern of 100.0
in an IEEE 32-bit float
is 0x42c80000
, which is 1120403456
in decimal 的位模式
100.0
在IEEE 32位float
是0x42c80000
,这是1120403456
十进制
To interpret 1120403456 or any other number as an IEEE basic 32-bit binary floating-point number: 要将1120403456或任何其他数字解释为IEEE基本的32位二进制浮点数:
If the exponent code were 0, it represents 2 −126 , and the significand would be formed by starting with “0.” instead of “1.” 如果指数代码为0,则表示2 -126 ,并且有效位数将以“ 0.”而不是“ 1”开头。
If the exponent code were 255, and the significand bits were zero, the object would represent infinity (+∞ or −∞ according to the sign bit). 如果指数代码为255,且有效位为零,则对象将表示无穷大(根据符号位为+∞或-∞)。 If the exponent code were 255, and the significand bits were not zero, the object would represent a Not a Number (NaN).
如果指数代码为255,并且有效位不为零,则该对象将表示非数字(NaN)。 There are additional semantics to NaN not covered in this answer.
NaN还有其他语义未包含在此答案中。
It is much older than Quake III , although the exact magic constant has varied a bit. 它比Quake III早得多 ,尽管确切的魔术常数有所变化。
The encoding of a finite single-precision floating point number according to IEEE-754 (which is what most modern computers use) is 根据IEEE-754(大多数现代计算机使用的)对有限单精度浮点数进行编码是
31 30 23 22 0
├─┼─┬─┬─┬─┬─┬─┬─┬─┼─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┤
│S│ Exponent │ Mantissa │
└─┴───────────────┴─────────────────────────────────────────────┘
The highest bit, S
is the sign. 最高位
S
是符号。 The value is negative if it is set, positive otherwise. 如果设置,则该值为负,否则为正。
If Exponent
and Mantissa
are both zero, then the value is either 0.0 (if S
is zero) or -0.0 (if S
is 1). 如果
Exponent
和Mantissa
均为零,则值为0.0(如果S
为零)或-0.0(如果S
为1)。
If Exponent
is zero, but Mantissa
nonzero, you have a denormal number very close to zero. 如果
Exponent
为零,但Mantissa
非零,则您有一个非常接近零的非正规数 。
Representations where Exponent
is 255 (all bits set) are reserved for infinity (if Mantissa
is zero), and not-a-number (if Mantissa
is nonzero). Exponent
为255(所有位均已设置)的表示形式保留为无穷大(如果Mantissa
为零),而不是数字(如果Mantissa
不为零)。
For Exponent
values from 1 to 254, inclusive, Mantissa
contains the fractional bits of the mantissa, with an implicit 1 in the integers position (This is what the (1)
means in eg 0 10000001 (1)1011011011011011011011
.) In other words, the value Mantissa
represents for these Exponent
values, is from 1.00000000000000000000000 2 (1.0 in decimal) to 1.11111111111111111111111 2 (1.99999994 in decimal), inclusive. 对于从1到254(含)之间的
Exponent
值, Mantissa
包含Mantissa
的小数位,在整数位置含一个隐式1(这是(1)
在0 10000001 (1)1011011011011011011011
。)换句话说,对于这些Exponent
值, Mantissa
表示的值是从1.00000000000000000000000 2 (十进制1.0)到1.11111111111111111111111 2 (十进制1.99999994)(含)。
Now, if we consider only nonnegative values (with S
clear), with E = Exponent
(between 1 and 254, inclusive), and M the logical value of Mantissa
(between 1.0 and 1.99999994), then the value V the single-precision floating point represents is 现在,如果我们仅考虑非负值(
S
清除), E = Exponent
(1到254之间,包括1和254之间),而M为Mantissa
的逻辑值(1.0到1.99999994之间),则值V为单精度浮点点代表是
V = 2 E - 127 × M V = 2 E -127 × M
The 127 is the exponent bias. 127是指数偏差。 The square root of V is
V的平方根是
√ V = 2 ( E - 127)/2 × √ M = 2 E /2 - 127 × 2 63 × √2 × √ M √V = 2(E - 127)/ 2×√M = 2 E / 2 - 127×2 63×√2×√ 中号
and the inverse square root, which is the target operation here, 和平方根反比,这是这里的目标运算,
1/√ V = 2 (127 - E )/2 × 1/√ M = 2 - E /2 - 127 × 2 63 × √2 × 1/√ M 1 /√V = 2(127 - E)/ 2×1 /√M = 2 - E / 2 - 127×2 63×√2×1 /√ 中号
noting that 2 127/2 = 2 63.5 = 2 63 × √2. 注意2127/2 = 2 63.5 = 2 63 ×√2。
If we take the integer representation, and shift it one bit to the right, we effectively halve E . 如果我们采用整数表示形式,并将其向右移一位,我们实际上将E减半。 To multiply by 2 63 , we need to add 63 to the exponent;
要乘以2 63 ,我们需要将63加到指数上。 63×2 23 .
63×2 23 。 However, for the square root operation, instead of multiplying by √2 × √ M , we effectively just multiply by M /2.
然而代替,对于平方根运算,乘以√2×√ 男 ,我们有效地只是乘以M / 2。 This means that that (shifting the integer representation one bit right, then adding 63 to the exponent) yields an estimate of a square root that is off by a factor between 0.7071067 and 0.75 for arguments greater than 1.0, and by a factor between 0.7071067 and 1448.155 for values between 0 and 1. (It yields 5.421×10 -20 for √0, and 0.75 for √1.)
这意味着(将整数表示右移一位,然后将63加到指数上)会得出平方根的估计值,对于大于1.0的自变量,其平方差在0.7071067到0.75之间,而系数在0.7071067到0.05之间。 0和1之间的值是1448.155(对于√0,它的输出为5.421×10 -20,对于√1,它的输出为0.75。)
Note that for the inverse square root operation, we wish to negate E . 注意,对于平方根的倒数运算,我们希望对E求反。
It turns out that if you shift the integer representation right by one bit, and then subtract that from (1 01111100 1101110101100111011111) 2 (1597463007 in decimal, 0x5f3759df in hexadecimal, a single-precision floating-point approximation of √2 127 ≈ 13043817825332782212), you get a pretty good approximation of the inverse square root (1/√ V ). 事实证明,如果向右一位移位整数表示,然后减去从(1 01111100 1101110101100111011111)2(1597463007十进制,十六进制0x5f3759df,的√2127≈13043817825332782212单精度浮点近似值) ,你得到的平方根的倒数(1 /√V)的一个很好的近似。 For all finite normal arguments, the approximation is off by a factor of 0.965624 to 1.0339603 from the correct value;
对于所有有限的普通自变量,近似值与正确值之间的距离为0.965624至1.0339603。 a very good approximation!
一个非常好的近似值! All you need is one or two iterations of Newton's method for the inverse square root operation on top.
对于顶部的平方根逆运算,您需要做的是一两次牛顿方法迭代。 (For f( X ) = 0 iff X = 1/√ V you need f( X ) = 1/ X ^2 - V . So, each iteration in X is X - f( X )/f'( X ) = X × (1.5 - 0.5 × V × X × X . Which should look quite familiar.)
(对于f(X)= 0当且仅当X = 1 /√v您需要F(X)= 1 / X ^ 2 - V因此,在X每次迭代是X - F(X)/ F'(X)= X ×(1.5-0.5× V × X × X 。应该看起来很熟悉。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.