简体   繁体   English

快速平方根逆算法中第一种类型校正的确切值是多少?

[英]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位float0x42c80000 ,这是1120403456十进制

To interpret 1120403456 or any other number as an IEEE basic 32-bit binary floating-point number: 要将1120403456或任何其他数字解释为IEEE基本的32位二进制浮点数:

  • Write the number as 32 bits, in this case, 01000010110010000000000000000000. 将数字写为32位,在这种情况下为01000010110010000000000000000000。
  • The first bit is the sign. 第一位是符号。 0 is + and 1 is −. 0是+,而1是-。
  • The next eight bits are an encoding of the exponent. 接下来的八位是指数的编码。 They are 10000101, which is 133 in decimal. 它们是10000101,即十进制133。 The exponent is encoded with a bias, 127, meaning the actual power of two represented is 2 133−127 = 2 6 . 指数使用偏差127进行编码,这意味着所表示的2的实际幂是2 133-127 = 2 6 (If the exponent is 0 or 255, it is a special value that has a different meaning.) (如果指数为0或255,则这是一个具有不同含义的特殊值。)
  • The remaining 23 bits encode the significand. 其余23位对有效位数进行编码。 For normal exponents (codes 1 to 254), they encode a significand formed by starting with “1.” and appending the 23 bits, “10010000000000000000000”, to make a binary numeral, “1.10010000000000000000000”. 对于普通指数(代码1到254),它们对以“ 1”开头并附加23位“ 10010000000000000000000”以形成二进制数“ 1.10010000000000000000000”而形成的有效位数进行编码。 In decimal, this is 1.5625. 以十进制表示,为1.5625。
  • The full value encoded is the sign with the power of two multiplied by the significand: + 2 6 • 1.5625, which equals 64•1.5625, which is 100. 编码的完整值是带2的幂乘以有效数的符号:+ 2 6 •1.5625,等于64•1.5625,即100。

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). 如果ExponentMantissa均为零,则值为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之间),而MMantissa的逻辑值(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≈1304381​​7825332782212单精度浮点近似值) ,你得到的平方根的倒数(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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM