为什么这两个代码给出不同的输出? // bits.c float_i2f

时间:2019-09-17 05:56:05

标签: c++ bitwise-operators

/* 
 * 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;

它正确了。

两个代码有什么区别?为什么第一个不起作用? 请帮助我:(

1 个答案:

答案 0 :(得分:1)

大量出现此问题。考虑例如2 25 -1 = 33554431,其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