任何人都可以用简单的方式解释下面的代码:
public unsafe static float sample(){
int result = 154 + (153 << 8) + (25 << 16) + (64 << 24);
return *(float*)(&result); //don't know what for... please explain
}
注意:以上代码使用不安全功能
对于上面的代码,我很难过,因为我不明白它的返回值与下面的返回值之间有什么区别:
return (float)(result);
如果您返回*(float*)(&result)
?
答案 0 :(得分:75)
在.NET上,使用32位存储的IEEE binary32单精度浮点数表示float
。显然,代码通过将位组合成int
然后使用float
将其转换为unsafe
来构造此数字。演员用C ++术语称为reinterpret_cast
,在执行强制转换时不进行转换 - 这些位只是重新解释为新类型。
汇总的数字是十六进制的4019999A
或二进制的01000000 00011001 10011001 10011010
:
10000000
(或128),导致指数128 - 127 = 1(分数乘以2 ^ 1 = 2)。00110011001100110011010
,如果没有别的话,几乎有一个可识别的0和1模式。返回的float与2.4转换为浮点的位完全相同,整个函数可以简单地用文字2.4f
替换。
那个“打破分数的位模式”的最后一个零可能是为了使float匹配可以用浮点文字写的东西?
那么常规演员和这个奇怪的“不安全演员”之间的区别是什么?
假设以下代码:
int result = 0x4019999A // 1075419546
float normalCast = (float) result;
float unsafeCast = *(float*) &result; // Only possible in an unsafe context
第一个转换采用整数1075419546
并将其转换为浮点表示,例如1075419546f
。这涉及计算将原始整数表示为浮点数所需的符号,指数和分数位。这是一项必须完成的非平凡计算。
第二次演员阵容更加险恶(并且只能在不安全的环境中演出)。 &result
获取result
的地址,返回指向存储整数1075419546
的位置的指针。然后可以使用指针解除引用运算符*
来检索指针指向的值。使用*&result
将检索存储在该位置的整数,但是首先将指针强制转换为float*
(指向float
的指针),而是从内存位置检索浮点数,从而导致float 2.4f
已分配给unsafeCast
。所以*(float*) &result
的叙述是给我一个指向result
的指针,并假设指针是指向float
的指针,并检索指针指向的值。
与第一次演员相反,第二次演员不需要任何计算。它只是将result
中存储的32位推入unsafeCast
(幸运的是也是32位)。
一般来说,执行类似的转换会在很多方面失败,但是使用unsafe
,你告诉编译器你知道你在做什么。
答案 1 :(得分:18)
如果我正在解释方法正确的做法,这是一个安全的等价物:
public static float sample() {
int result = 154 + (153 << 8) + (25 << 16) + (64 << 24);
byte[] data = BitConverter.GetBytes(result);
return BitConverter.ToSingle(data, 0);
}
如前所述,它正在将int
值重新解释为float
。
答案 2 :(得分:3)
这看起来像是一次优化尝试。您不是在进行浮点计算,而是对浮点数的整数表示进行整数计算。
请记住,浮点数就像int一样存储为二进制值。
计算完成后,您将使用指针和强制转换将整数转换为浮点值。
这与将值转换为float不同。这会将int值1转换为float 1.0。在这种情况下,您将int值转换为存储在int中的二进制值所描述的浮点数。
很难正确解释。我会找一个例子。 : - )
编辑: 看这里:http://en.wikipedia.org/wiki/Fast_inverse_square_root
您的代码基本上与本文中描述的相同。
答案 3 :(得分:2)
答案 4 :(得分:2)
因为Sarge Borsch问道,这里是'Union'等价物:
[StructLayout(LayoutKind.Explicit)]
struct ByteFloatUnion {
[FieldOffset(0)] internal byte byte0;
[FieldOffset(1)] internal byte byte1;
[FieldOffset(2)] internal byte byte2;
[FieldOffset(3)] internal byte byte3;
[FieldOffset(0)] internal float single;
}
public static float sample() {
ByteFloatUnion result;
result.single = 0f;
result.byte0 = 154;
result.byte1 = 153;
result.byte2 = 25;
result.byte3 = 64;
return result.single;
}
答案 5 :(得分:0)
正如其他人已经描述的那样,它将int的字节视为浮点数。
如果不使用不安全的代码,您可能会得到相同的结果:
public static float sample()
{
int result = 154 + (153 << 8) + (25 << 16) + (64 << 24);
return BitConverter.ToSingle(BitConverter.GetBytes(result), 0);
}
但是它不会再快了,你也可以使用浮点数/双打和数学函数。