1

2 つの浮動小数点値を比較することになっている次の関数がありますが、特定の場合 (Cortex-A8 など) では通常の比較よりも高速です。

int isGreater(float* f1, float* f2)
{
    int i1, i2, t1, t2;

    i1 = *(int*)f1; // reading float as integer
    i2 = *(int*)f2; // reading float as integer

    t1 = i1 >> 31;
    i1 = (i1 ^ t1) + (t1 & 0x80000001);

    t2 = i2 >> 31;
    i2 = (i2 ^ t2) + (t2 & 0x80000001);

    return i1 > i2;
}

誰かがそれがどのように正確に機能するか説明できますか?

4

1 に答える 1

5

このコードは、浮動小数点数のIEEE754形式の構造を利用しています。構造自体は、比較操作を高速化するために、このような操作用に特別に設計されています。

各単精度IEEE754番号には、次の3つの部分があります(MSBからLSBの順に)。

  • 符号ビット
  • 指数部(8ビット)
  • 仮数の仮数(23ビット)

f1次の場合よりも大きいf2

  • f1正でf2負です
  • f1両方ともf2正ですが、f1より大きな指数を持っていますf2
  • f1両方ともf2正であり、同じ指数を持ちますが、f1より大きな仮数を持ちますf2
  • f1f2が負の場合、前の2つの反対

2の補数表現の場合、両方の浮動小数点数を整数として比較することができます。残念ながら、IEEE 754は負の数を表すために2の補数を使用しません。そのため、このコードは、数値を符号付き整数として比較できるようにするために変換を実行します。

これは、コードの各行が何をするかについての段階的な解説です。

i1 = *(int*)f1; // reading float as integer
i2 = *(int*)f2; // reading float as integer

これは、ほとんどの32ビットシステムsizeof(int) == sizeof(float)で浮動小数点数を通常の符号付き整数変数に読み込むという事実を利用しています。

t1 = i1 >> 31;

これはの符号ビットを抽出しf1ます。が負の場合f1、そのMSBは負になり1、したがってi1負になります。31ビット右にシフトすると符号が保持されるため、i1負の場合はt1すべてのビットが1(-1に等しい)に設定されます。が正の場合f1、その符号ビットはで0あり、最終的にt1はに等しくなり0ます。

i1 = (i1 ^ t1) + (t1 & 0x80000001);

符号ビットが負の場合、1この行は2の補数表現への変換を実行します。f1

仕組みは次のとおりです。f1が正の場合、現在および将来t1は現在および将来であり、最終的には元の値を保持します。が負の場合、すべてのビットがに設定され、RHSの最初の式はのビット反転になり、2番目の式はに等しくなります。この方法はビット反転に変換され、追加されます。ただし、MSBがクリアされるため、これは正の数になります。そのため、数を負に保つために追加されます。0(i1 ^ t1)i1(t1 & 0x80000001)0i1f1t11i10x80000001i110x80000000

t2 = i2 >> 31;
i2 = (i2 ^ t2) + (t2 & 0x80000001);

上記と同じように実行しf2ます。

return i1 > i2;

結果として得られる2つの符号付き整数を比較するだけです。ほとんどのCPUには、ハードウェアで符号付き比較を実行するための専用の命令があります。

于 2012-06-19T09:23:00.200 に答える