【问题标题】:bitwise operators for finding less than in c在 c 中查找小于的位运算符
【发布时间】:2021-12-16 04:56:24
【问题描述】:

这是一个家庭作业,需要我想出一个函数来确定是否x < y,如果是,我必须返回1,只使用位运算符( ! ~ & ^ | + << >> )。我只被允许使用常量0 - 0xFF,并假设一个 32 位整数。没有循环、强制转换等。

我发现如果你只检查 4 位,你可以用x - y 来确定@​​987654327@ 是否小于y。如果x8 并且y9,那么-1 的结果将是1111

int lessThan(int x, int y){
    int sub = x + (~y+1); 

我感到困惑的是现在如何将该结果与x 进行比较,以确定它确实小于y

我一直在研究这篇文章here

但我对这种解决问题的方法有点困惑。我已经计算出了实现位拖尾的转变,但我对如何使用该结果来比较小于或大于的值感到困惑。我只是在寻找一些指导和清晰,而不是解决方案,这不是我的意图。

【问题讨论】:

  • !+ 什么时候变成了位运算符?你确定它们是合法的吗?
  • 是的,我确信它们是合法的,我想我应该说我只被允许使用这些算术和逻辑运算符。对不起。
  • 允许整数和无符号数。
  • 我对这个家庭作业和这门课都很熟悉。与其给您答案,不如尝试以下方法:考虑 x 和 y 的符号,然后将比较分为四种情况。您可以从那里简化解决方案。
  • 谢谢,我想这就是我正在努力解决的问题。

标签: c bitwise-operators


【解决方案1】:

我认为可以通过以下方式实现:

  1. Xor 两个数字,这会给你不同的位
  2. 获取不同的最重要位,因为这一位会有所不同
  3. 检查最高有效位是否属于更大的值

代码:

int less(int x, int y) {
    //Get only diffed bits
    int msb = x ^ y;
    //Get first msb bit
    msb |= (msb >>  1);
    msb |= (msb >>  2);
    msb |= (msb >>  4);
    msb |= (msb >>  8);
    msb |= (msb >> 16);
    msb = msb - (msb >> 1);
    //check if msb belongs to y;
    return !((y & msb) ^ msb);
}

【讨论】:

    【解决方案2】:

    实现减法的思路不错。

    int sub = x + (~y+1);
    

    从这里,您只需要检查sub 是否为负数,即提取其符号位。这就是技术难点出现的地方。

    假设xy 是无符号的32 位整数。然后减法的结果可以用带符号的 33 位整数表示(检查它的最小值和最大值以查看)。也就是说,直接使用x + (~y+1)这个表达式是没有用的,因为它会溢出。

    如果 xy 是 31 位无符号数怎么办?那么x + (~y+1)可以用一个32位的有符号数来表示,它的符号位告诉我们x是否小于y

    answer(x, y) := ((x + (~y+1)) >> 31) & 1
    

    要将 xy 从 32 位转换为 31 位,请将它们的 MSB(最高有效位)和所有其他 31 位分开为不同的变量:

    msb_x = (x >> 31) & 1;
    msb_y = (y >> 31) & 1;
    x_without_msb = x << 1 >> 1;
    y_without_msb = y << 1 >> 1;
    

    然后考虑其 MSB 的 4 种可能组合:

    if (msb_x == 0 && msb_y == 0)
        return answer(x_without_msb, y_without_msb);
    else if (msb_x == 1 && msb_y == 0)
        return 0; // x is greater than y
    else if (msb_x == 0 && msb_y == 1)
        return 1; // x is smaller than y
    else
        return answer(x_without_msb, y_without_msb);
    

    将所有这些 if 语句转换为一个又大又丑的逻辑表达式是“读者练习”。

    【讨论】:

      【解决方案3】:

      这是我的尝试(编译结果,x > y 然后 0,x

      ((((x + ~y) >> 31) + 1))^1
      

      【讨论】:

      • 我觉得你需要先加1。 -y = ~y+1 在两个补码中
      • 这对于家庭作业来说可能已经足够了,但是当有溢出时它会失败。
      • 3 &lt; 3 是从什么时候开始的?
      【解决方案4】:

      只是想补充一下这个讨论,因为我不确定它是否已经被提及。这里有些人提出了这一点

      ( x + ((~y) + 1)) >> 32) & 0x1
      

      不适用于溢出条件。对于二进制补码,整数 x 和 y 相加的溢出条件为:

      x > 0, y > 0, (x+y)

      x 0

      在这种情况下,我们将 x 和 (-y) 相加,还必须在确定是否 (x-y) 之前检查溢出条件

      long isLess(long x, long y) {
          long xs= (x>>63) & 0x1L; 
          long ys= (y>>63) & 0x1L;
          long s = x + (~y +1L);
      
          long ss= (s>>63) & 0x1L;
      
          /*
          //Code without SOP result for clarity
          if(xs & ~ys & ~ss) return 1;
          if(~xs & ys & ss)  return 0;
      
          return ss;
          */
      
          return (((xs | ~ys | ~ss) & (~xs | ys | ss)) & ss) |
                 (((~xs & ys & ss) | (xs & ~ys & ~ss)) & ~ss);
      }
      

      【讨论】:

        【解决方案5】:

        要知道是否为x &lt; y,您可以简单地询问是否为x - y &lt; 0

        也就是说x - y的结果的符号是什么。

        既然你说你要假设 32 位整数,以下将提供正确的结果:

        ((x - y) >> 31) & 0x1
        

        【讨论】:

        • 添加 &amp; 0x1 以防发生符号扩展移位
        • @ChrisDodd 正确
        猜你喜欢
        • 2022-09-24
        • 2010-11-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-11
        相关资源
        最近更新 更多