45

誰でも簡単に以下のコードを説明できますか?

public unsafe static float sample(){    
      int result = 154 + (153 << 8) + (25 << 16) + (64 << 24);

      return *(float*)(&result); //don't know what for... please explain
}

注:上記のコードはunsafe関数を使用しています

上記のコードでは、戻り値と以下の戻り値の違いが分からないため、苦労しています。

return (float)(result);

戻る場合、安全でない関数を使用する必要があります*(float*)(&result)か?

4

6 に答える 6

76

.NETでは、aは32ビットを使用して格納されたIEEEbinary32単精度浮動小数点数floatを使用して表されます。どうやら、コードはビットをにアセンブルしてこの数値を作成し、それをusingにキャストしているようです。キャストとは、C ++の用語で呼ばれるもので、キャストの実行時に変換は行われません。ビットは新しいタイプとして再解釈されるだけです。intfloatunsafereinterpret_cast

IEEE単精度浮動小数点数

アセンブル4019999Aされた数は16進数または01000000 00011001 10011001 100110102進数です。

  • 符号ビットは0です(正の数です)。
  • 指数ビットは10000000(または128)であり、指数128-127 = 1になります(小数部に2 ^ 1 = 2が掛けられます)。
  • 小数ビットは00110011001100110011010、他に何もないとしても、ほとんど認識可能な0と1のパターンを持っています。

返されるfloatは、2.4が浮動小数点に変換されたものとまったく同じビットを持ち、関数全体をリテラルに置き換えることができます2.4f

分数の「ビットパターンを壊す」ような最後のゼロは、おそらく浮動小数点リテラルを使用して記述できるものと浮動小数点を一致させるためにありますか?


では、通常のキャストとこの奇妙な「安全でないキャスト」の違いは何ですか?

次のコードを想定します。

int result = 0x4019999A // 1075419546
float normalCast = (float) result;
float unsafeCast = *(float*) &result; // Only possible in an unsafe context

最初のキャストは整数1075419546を受け取り、それを浮動小数点表現に変換し1075419546fます。これには、元の整数を浮動小数点数として表すために必要な符号、指数、および小数ビットの計算が含まれます。これは、実行する必要のある重要な計算です。

2番目のキャストはより不吉です(そして安全でない状況でのみ実行できます)。は、整数が格納されている場所へのポインタを返す&resultアドレスを取ります。次に、ポインターの間接参照演算子を使用して、ポインターが指す値を取得できます。を使用すると、その場所に格納されている整数が取得されますが、最初にポインタを(へのポインタ)にキャストすると、代わりにfloatがメモリ位置から取得され、floatがに割り当てられます。したがって、の説明は、へのポインタを与え、そのポインタがaへのポインタであると想定し、ポインタが指す値を取得しますresult1075419546**&resultfloat*float2.4funsafeCast*(float*) &resultresultfloat

最初のキャストとは対照的に、2番目のキャストは計算を必要としません。に格納されている32ビットをresult押し込むだけですunsafeCast(幸いにも32ビットです)。

一般に、そのようなキャストの実行は多くの点で失敗する可能性がありますが、使用することによりunsafe、コンパイラーに自分が何をしているかを知っていることを伝えています。

于 2012-10-04T08:09:14.920 に答える
19

メソッドが正しく行っていることを解釈している場合、これは安全な同等物です:

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

于 2012-10-04T08:11:58.367 に答える
3

これは最適化の試みのようです。浮動小数点計算を行う代わりに、浮動小数点数の整数表現で整数計算を行っています。

float は int と同様にバイナリ値として格納されることに注意してください。

計算が完了したら、ポインターとキャストを使用して整数を浮動小数点値に変換します。

これは、値を float にキャストすることと同じではありません。これにより、int 値 1 が float 1.0 に変わります。この場合、int 値を、int に格納されているバイナリ値によって記述される浮動小数点数に変換します。

きちんと説明するのはかなり難しいです。例を探します。:-)

編集: ここを見てください: http://en.wikipedia.org/wiki/Fast_inverse_square_root

コードは基本的に、この記事で説明したものと同じです。

于 2012-10-04T08:11:01.970 に答える
2

Re:それは何をしているのですか?

intに格納されているバイトの値を取得し、代わりにこれらのバイトをfloatとして解釈します(変換なし)。

幸い、floatとintのデータサイズは同じ4バイトです。

于 2012-10-04T08:10:28.570 に答える
0

他の人がすでに説明したように、int のバイトを float のように扱っています。

次のような安全でないコードを使用しなくても、同じ結果が得られる可能性があります。

public static float sample()
{
    int result = 154 + (153 << 8) + (25 << 16) + (64 << 24);
    return BitConverter.ToSingle(BitConverter.GetBytes(result), 0);
}

しかし、それはもはや非常に高速ではなく、float/double と Math 関数を使用することもできます。

于 2012-10-04T08:21:48.587 に答える