【问题标题】:Compare two integers using bit operator使用位运算符比较两个整数
【发布时间】:2021-03-12 13:43:04
【问题描述】:

我需要使用位运算符比较两个整数。 我遇到了一个问题,我必须在不使用比较运算符的情况下比较两个整数。使用位运算符会有所帮助。但是如何?

让我们说 a = 4; b = 5;

我们必须证明 a 不等于 b。 但是,我想进一步扩展它,比如说,我们将展示哪个更大。这里 b 更大..

【问题讨论】:

  • 您能否提供一个描述您的问题的示例?
  • AFAIK,这在布尔表示为 int 的语言(如 c)中是可能的。但不是在 java 中,因为您可以仅使用比较来获得布尔值。 int 上的位运算符总是只会产生 int。

标签: java integer


【解决方案1】:

您至少需要与 0 进行比较,理论上这就是 CPU 用于比较的操作。例如

等于可以建模为^,因为位必须相同才能返回 0

(a ^ b) == 0

如果这是C,您可以删除== 0,因为这可以暗示

!(a ^ b)

但在 Java 中,您不能在没有比较的情况下将 int 转换为 boolean

为了比较,你通常会做一个减法,尽管它会处理溢出。

(long) a - b > 0 // same as a > b

减法与加负数相同,负数与~x+1相同,所以你可以这样做

(long) a + ~ (long) b + 1 > 0

要删除+1,您可以将其更改为

(long) a + ~ (long) b >= 0 // same as a > b

您可以使用>> << & |^+ 实现为一系列逐位操作,但我不会对您施加这种影响。

【讨论】:

  • 这个答案有一些问题。首先,在 C 中,!(a ^ b) 与 (a ^ b) == 0 在底层完全相同。没有特殊的汇编命令可以执行 !a。所以你还在做比较。您需要比较才能从整数获取 Java 中的布尔值是正确的,但您实际上可以在不使用比较的情况下获得 0 或 1。检查my answer
  • 对于!a vs a==0,取自C documentation section 6.5.3.3, The expression !E is equivalent to (0==E).
【解决方案2】:

如果没有像 Peter 提到的比较运算符,您无法将 10 转换为 bool。在没有比较运算符的情况下仍然可以得到max

为了避免混淆,我使用 bit(1 或 0)而不是 int

bit msb(x):
    return lsb(x >> 31)
bit lsb(x):
    return x &1

// returns 1 if x < 0, 0 if x >= 0
bit isNegative(x):
    return msb(x)

有了这些助手isGreater(a, b) 看起来像,

// BUG: bug due to overflow when a is -ve and b is +ve
// returns 1 if a > b, 0 if a <= b
bit isGreater_BUG(a, b):
    return isNegative(b - a)    // possible overflow

我们需要两个辅助函数来检测相同和不同的标志,

// toggles lsb only
bit toggle(x):
    return lsb(~x)

// returns 1 if a, b have same signs (0 is considered +ve).
bit isSameSigns(a, b):
    return toggle(isDiffSigns(a, b))
// returns 1 if a, b have different signs (0 is considered +ve).
bit isDiffSigns(a, b):
    return msb(a ^ b)

所以随着溢出问题的修复,

// returns 1 if a > b, 0 if a <= b
bit isGreater(a, b):
    return 
        (isSameSigns(a, b) & isNegative(b - a)) | 
        (isDiffSigns(a, b) & isNegative(b))

请注意,isGreater 也适用于输入 5, 00, -5

正确实施isPositive(x)棘手,因为0 也将被视为积极的。因此,不是使用上面的isPositive(a - b),而是使用isNegative(b - a),因为isNegative(x)0 有效。

现在 max 可以实现为,

// BUG: returns 0 when a == b instead of a (or b)
// returns a if a > b, b if b > a
int max_BUG(a, b):
    return
        isGreater(a, b) * a +   // returns 0 when a = b
        isGreater(b, a) * b     //

要修复使用了isZero(x) 的帮助器,

// returns 1 if x is 0, else 0
bit isZero(x):
    // x | -x will have msb 1 for a non-zero integer
    // and 0 for 0
    return toggle(msb(x | -x))

因此,当a = b 进行修复时,

// returns 1 if a == b else 0
bit isEqual(a, b):
    return isZero(a - b) // or isZero(a ^ b)

int max(a, b):
    return
        isGreater(a, b) * a +   // a > b, so a
        isGreater(b, a) * b +   // b > a, so b
        isEqual(a, b) * a       // a = b, so a (or b)

也就是说,如果 isPositive(0) 返回 1,那么 max(5, 5) 将返回 10 而不是 5。所以正确的 isPositive(x) 实现将是,

// returns 1 if x < 0, 0 if x >= 0
bit isPositive(x):
    return isNotZero(x) & toggle(isNegative(x))

// returns 1 if x != 0, else 0
bit isNotZero(x):
    return msb(x | -x)

【讨论】:

    【解决方案3】:

    使用二进制补码表示法

    int findMax( int x, int y)
    {
     int z = x - y;
     int i  = (z  >>  31)  &  0x1;
     int  max  =  x - i  *  z;
     return max;
    }
    

    参考:Here

    【讨论】:

    • 您是否建议您找到一种方法来避免首先进行比较?
    • 这找不到两个值是否相等。
    • 是的先生,这是第二部分的答案:'但是,我想进一步扩展它,比如说,我们将展示哪个更大。'没有比较。
    【解决方案4】:
    a ^ b = c                    // XOR the inputs
                                 //  If a equals b, c is zero. Else c is some other value
    
    c[0] | c[1] ... | c[n] = d   // OR the bits
                                 //  If c equals zero, d equals zero. Else d equals 1
    

    注意:a,b,c 是 n 位整数,d 是位

    【讨论】:

      【解决方案5】:

      java中不使用比较运算符的解决方案:

          int a = 10;
          int b = 12;
          boolean[] bol = new boolean[] {true};
      
          try {
            boolean c = bol[a ^ b];
            System.out.println("The two integers are equal!");
          } catch (java.lang.ArrayIndexOutOfBoundsException e) {
            System.out.println("The two integers are not equal!");
            int z = a - b;
            int i = (z >> 31) & 0x1;
            System.out.println("The bigger integer is " + (a - i * z));
          }
      

      【讨论】:

        【解决方案6】:

        我将假设您需要一个整数(0 或 1),因为您需要比较才能从 java 中的整数获取布尔值。

        这里是一个简单的解决方案,它不使用比较,而是使用实际上可以使用按位运算完成的减法(但不推荐,因为它需要大量的软件周期)。

        // For equality,
        // 1. Perform r=a^b.
        //    If they are equal you get all bits 0. Otherwise some bits are 1.
        // 2. Cast it to a larger datatype 0 to have an extra bit for sign.
        //    You will need to clear the high bits because of signed casting.
        //    You can split it into two parts if you can't cast.
        // 3. Perform -r.
        //    If all bits are 0, you will get 0.
        //    If some bits are not 0, then you get a negative number.
        // 4. Shift right to extract MSB.
        //    This will give -1 (because of sign extension) for not equal and 0 for equal.
        //    You can easily convert it to 0 and 1 by adding 1 (I didn't include it in below function).
        int equality(int a, int b) {
            long r = ((long)(a^b)) ^0xffffffffl;
            return (int)(((long)-r) >> 63);
        }
        
        // For greater_than,
        // 1. Cast a and b to larger datatype to get more bits.
        //    You can split it into two parts if you can't cast.
        // 2. Perform b-a.
        //    If a>b, then negative number (MSB is 1)
        //    If a<=b, then positive number or zero (MSB is 0)
        // 3. Shift right to extract MSB.
        //    This will give -1 (because of sign extension) for greater than and 0 for not.
        //    You can easily convert it to 0 and 1 by negating it (I didn't include it in below function).
        int greater_than(int a, int b) {
            long r = (long)b-(long)a;
            return (int)(r >> 63);
        }
        
        

        小于等于大于,但你交换 a 和 b。

        琐事:这些比较函数实际上用于安全(密码学),因为 CPU 比较不是恒定时间的;也不能防止定时攻击

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-01-20
          • 1970-01-01
          • 2014-02-14
          • 2016-02-22
          • 2011-05-26
          相关资源
          最近更新 更多