1. ホーム
  2. c++

[解決済み] なぜこの2つのコードは異なる出力をするのでしょうか?// bits.c float_i2f

2022-02-02 23:54:44

質問

/* 
 * float_i2f - Return bit-level equivalent of expression (float) x
 *   Result is returned as unsigned int, but
 *   it is to be interpreted as the bit-level representation of a
 *   single-precision floating point values.
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
 *   Max ops: 30
 *   Rating: 4
 */
unsigned float_i2f(int x) {
int sign = x & (1 << 31);
int minus = 1 << 31; 
int exp = 31;
int bias = 127;
int frac;
if (!x)
   return 0;
if (x == minus)
   return minus | ((exp + bias) << 23);
if (sign)
   x = ~x + 1;
while (!(x & minus))
{
   x <<= 1;
   exp -= 1;
}
frac = (((~minus) & x) >> 8);
if (x & 0x80 && ((frac & 1) ||((x & 0x7f) > 0)))
   frac++;
return sign + ((exp + bias) << 23) + frac;
}

このコードをdriver.plでチェックすると、答えの正しさがチェックされる。 しかし、私は奇妙なことを発見しました。

最後のreturn文が

return sign | ((exp + bias) << 23) | frac;

に変更すると、うまくいかないと表示されます。

return sign + ((exp + bias) << 23) + frac;

が正しくなります。

2つのコードの違いは何ですか?なぜ最初のものは動作しないのでしょうか? 私を助けてください :(

解決方法は?

この問題は、数字が大きくなると発生します。例えば、2 25 - 1 = 33554431で、その2の補数2進表現は次のようになります。

00000001 11111111 11111111 11111111           // or --> 0 00000011 11111111111111111111111

指数を求めた後、このコードでは frac として

frac = (((~minus) & x) >> 8);                 //   -->  0 00000000 11111111111111111111111

しかし、これを丸めなければならないので、次のように実行されます。

if (x & 0x80 && ((frac & 1) ||((x & 0x7f) > 0)))
    frac++;                                     // -->  0 00000001 00000000000000000000000

基本的にキャリーがあるので、999を1x10と表現する場合のように指数を大きくする必要があります。 3 ではなく、9.99x10 2 . の違いがわかるようになりました。 | または + :

sign + ((exp + bias) << 23) + frac;              // --> 0 10011000 00000000000000000000000

sign | ((exp + bias) << 23) | frac;              // --> 0 10010111 00000000000000000000000