【问题标题】:How to tell if a 32 bit int can fit in a 16 bit short如何判断 32 位 int 是否适合 16 位短
【发布时间】:2011-09-07 16:44:21
【问题描述】:

仅使用:

! ~ & ^ | + << >>

我需要确定一个带符号的 32 位整数是否可以表示为 16 位二进制补码整数。

我的第一个想法是将 MSB 16 位和 LSB 16 位分开,然后对最后 16 位使用掩码,因此如果它不为零,则无法表示,然后使用该数字检查MSB 位。

我需要写的函数的一个例子是:fitsInShort(33000) = 0(不能表示)和fitsInShort(-32768) = 1(可以表示)

【问题讨论】:

    标签: c integer bit-manipulation


    【解决方案1】:
    bool fits16(int x)
    {
        short y = x;
        return y == x;
    }
    

    开个玩笑:)这是真正的答案,假设 int 是 32 位,short 是 16 位和二进制补码表示:

    编辑:正确答案请查看上次编辑!

    bool fits16(int x)
    {
        /* Mask out the least significant word */
        int y = x & 0xffff0000;
        if (x & 0x00008000) {
            return y == 0xffff0000;
        } else {
            return y == 0;
        }
    }
    

    如果没有我认为应该这样做的语句:

    return (
        !(!(x & 0xffff0000) || !(x & 0x00008000)) ||
        !((x & 0xffff0000) || (x & 0x00008000))
    );
    

    编辑:奥利说得对。我不知何故认为他们是被允许的。这是最后一次尝试,带有解释:

    我们需要x 的 17 个最高有效位为全 1 或全为零。因此,让我们从屏蔽其他位开始:

    int a = x & 0xffff8000; // we need a to be either 0xffff8000 or 0x00000000
    int b = a + 0x00008000; // if a == 0xffff8000 then b is now 0x00000000
                            // if a == 0x00000000 then b is now 0x00008000
                            // in any other case b has a different value
    int c = b & 0xffff7fff; // all zeroes if it fits, something else if it doesn't
    return c;
    

    或者更简洁:

    return ((x & 0xffff8000) + 0x8000) & 0xffff7fff;
    

    【讨论】:

    • 我也不能使用 if 语句。我需要一些全为 0 的东西,因为它适合,而其他东西不适合,所以我可以!数字并得到 0 或 1。
    • 刚刚编辑。如果我没记错的话!(!a || !b)==(a && b)。或类似的东西......
    • OP 没有提到逻辑运算符(&amp;&amp;||)。
    • @Vishal:您已接受此答案,但您没有在问题中提及逻辑运算符(&amp;&amp;||)。
    • 所以最后一个案例回答 0,如果它适合哪个是否定(doesntFit16)并且它有一个不必要的操作。我只想写#define fit16(x) (!(((unsigned)(x)+0x8000U) & OxFFFF0000U))
    【解决方案2】:

    如果 32 位数字在 [-32768,+32767] 范围内,则 17 msb 将全部相同。

    这是一种仅使用您的操作来判断 3 位数字是全 1 还是全 0 的糟糕方法(我假设您不允许使用条件控制结构,因为它们需要隐式逻辑操作):

    int allOnes3(int x)
    {
        return ((x >> 0) & (x >> 1) & (x >> 2)) & 1;
    }
    
    int allTheSame3(int x)
    {
        return allOnes3(x) | allOnes3(~x);
    }
    

    我会让你扩展/改进这个概念。

    【讨论】:

      【解决方案3】:

      这是一个没有强制转换、if 语句并且只使用您要求的运算符的解决方案:

      #define fitsInShort(x) !(((((x) & 0xffff8000) >> 15) + 1) & 0x1fffe)
      

      【讨论】:

      • 聪明的答案。如果您能解释它为什么起作用,这将对提问者有所帮助:)
      • 我注意到被接受的回答者接受了我的想法,并在被接受后将其添加到他的回答中。如果不是因为他改进了它,那将是可耻的。位移是不必要的,可以用 + 0x8000 和另一个掩码代替。请参阅他对为什么这样做的解释。基本思想是隔离应该全为 0 或全为 1 的位,然后加上 +1。如果数字合适,则必须是 (-1)+1 或 0+1,因此如果结果数字 & 0xfffe 为 0(忽略最后一位),则数字合适。
      【解决方案4】:
      short fitsInShort(int x)
      {
          int positiveShortRange = (int) ((short) 0xffff / (short) 2);
          int negativeShortRange = (int) ((short) 0xffff / (short) 2) + 1;
      
          if(x > negativeShortRange && x < positiveShortRange)
              return (short) x;
          else
              return (short) 0;
      }
      

      【讨论】:

      • 这个问题对允许哪些操作有一些人为的限制。
      • @Oli Charlesworth:我们的解决方案是相同的,但您按时击败了我。您的解决方案也会检查 x > -32768 && x
      【解决方案5】:
      if (!(integer_32 & 0x8000000))
      {
         /* if +ve number */
        if (integer_32 & 0xffff8000)
          /* cannot fit */
        else 
          /* can fit */
      }
      else if (integer_32 & 0x80000000)
      {
        /* if -ve number */
        if ( ~((integer_32 & 0xffff8000) | 0x00007fff))
          /* cannot fit */
        else
          /* can fit */
      }
      

      First if 首先通过检查有符号位来检查 +ve 数字。如果 +ve ,则检查第 15 位到第 31 位是否为 0,如果为 0,则无法放入 short,否则可以。

      如果第 15 位到第 31 位都设置(2 的补码方法表示),则负数在范围内。

      因此,第二个if 是一个 -ve 数字,然后将第 15 到 31 位屏蔽掉,并设置剩余的低位(0 到 14)。如果这是0xffffffff,那么只有一个的补码是0,表示第15到31位都已设置,因此可以拟合(else部分),否则无法拟合(if条件)。

      【讨论】:

      • 不处理负数。
      猜你喜欢
      • 2011-08-14
      • 1970-01-01
      • 2014-05-06
      • 1970-01-01
      • 2019-06-24
      • 2017-07-01
      • 2011-11-13
      • 2013-01-11
      • 2018-06-14
      相关资源
      最近更新 更多