-1

何百ものケースで機能する関数を作成しましたが、場合によっては失敗します。

C関数は次のとおりです。

unsigned negate_number(unsigned x) {
  int sign = (!(x & 0x80000000))<<31;
  int other = 0x7FFFFFFF & x;
  return (sign | other);
}

符号をマスキングし、それを反転して、マスクされた指数と仮数で OR (結合) を実行しているだけです。したがって、これはすべての場合に機能するはずです。

しかし、失敗するケースがあります: x = 0x7fc00000 (2143289344)

4

1 に答える 1

1

私は尋ねた:

コードが整数で動作しているのに、なぜタイトルの「浮動小数点数」について尋ねているのですか? 関数を a で呼び出して、float多かれ少なかれビットの配列として扱おうとしていますか? もしそうなら、あなたは何にも隠れていません!スコープ内のプロトタイプで関数を呼び出すと、C コンパイラは を に変換floatunsigned intます。スコープ内のプロトタイプでそれを呼び出さない場合、C コンパイラは関数を呼び出す前に を に変換floatします。double

そして、応答は次のとおりでした。

これは、32 ビットの IEEE 754 単精度数です。したがって、最上位ビット (符号ビット) を反転しているだけです。

32 ビット (符号なし整数) 量の最上位ビットを反転するには、単純に次のように記述できます。

x ^= 0x80000000;

ただし、私が示したようfloatに、コンパイラに嘘をついていない限り、32 ビットが渡されないだけです。次のものがあれば、「動作させる」ことができます(一部のマシンでは、場合によっては):

偽のコード

ファイルA.c

extern float negate_number(float x);

...
float f1 = 3.14159;
float f2 = negate_number(f1);
...

ファイルB.c

unsigned negate_number(unsigned x)
{
    return x ^ 0x80000000;
}

ただし、コンパイラに火をつけて遊んでいます。コンパイラは嘘をつくことを嫌い、しばしば自分自身を取り戻す方法を見つけます。 こんなことしないで!

主にコーシャコード

最小限の問題で(「問題なし」ではない)必要な効果を多かれ少なかれ達成するには、おそらく次のものが必要です。

ファイルB.c

float negate_number(float f)
{
    union { unsigned x; float y; } u;
    u.y = f;
    u.x ^= 0x80000000;
    return u.y;
}

u.x厳密には、に割り当てた後の読み取りと書き込みu.yは未定義の動作ですが、通常は必要なことが行われます。u.y操作後に戻る場合も同様u.xです。

floatこれはすべて、とのビット レイアウトがunsignedの符号ビットfloatが の最上位ビットになることを前提としていますunsigned

于 2012-09-09T05:35:48.783 に答える