Why is (a | b ) equivalent to a - (a & b) + b?

前端 未结 4 1404
孤城傲影
孤城傲影 2021-02-04 03:26

I was looking for a way to do a BITOR() with an Oracle database and came across a suggestion to just use BITAND() instead, replacing BITOR(a,b) with a + b - BITAND(a,b).

4条回答
  •  旧时难觅i
    2021-02-04 04:09

    A&B = C where any bits left set in C are those set in both A and in B.
    Either A-C = D or B-C = E sets just these common bits to 0. There is no carrying effect because 1-1=0.
    D+B or E+A is similar to A+B except that because we subtracted A&B previously there will be no carry due to having cleared all commonly set bits in D or E.

    The net result is that A-A&B+B or B-A&B+A is equivalent to A|B.

    Here's a truth table if it's still confusing:

     A | B | OR   A | B | &    A | B | -    A | B | + 
    ---+---+---- ---+---+---  ---+---+---  ---+---+---
     0 | 0 | 0    0 | 0 | 0    0 | 0 | 0    0 | 0 | 0  
     0 | 1 | 1    0 | 1 | 0    0 | 1 | 0-1  0 | 1 | 1
     1 | 0 | 1    1 | 0 | 0    1 | 0 | 1    1 | 0 | 1  
     1 | 1 | 1    1 | 1 | 1    1 | 1 | 0    1 | 1 | 1+1

    Notice the carry rows in the + and - operations, we avoid those because A-(A&B) sets cases were both bits in A and B are 1 to 0 in A, then adding them back from B also brings in the other cases were there was a 1 in either A or B but not where both had 0, so the OR truth table and the A-(A&B)+B truth table are identical.

    Another way to eyeball it is to see that A+B is almost like A|B except for the carry in the bottom row. A&B isolates that bottom row for us, A-A&B moves those isolated cased up two rows in the + table, and the (A-A&B)+B becomes equivalent to A|B.

    While you could commute this to A+B-(A&B), I was afraid of a possible overflow but that was unjustified it seems:

    #include 
    int main(){ unsigned int a=0xC0000000, b=0xA0000000;
    printf("%x %x %x %x\n",a,   b,       a|b,       a&b);
    printf("%x %x %x %x\n",a+b, a-(a&b), a-(a&b)+b, a+b-(a&b)); }
    
    c0000000 a0000000 e0000000 80000000
    60000000 40000000 e0000000 e0000000
    

    Edit: So I wrote this before there were answers, then there was some 2 hours of down time on my home connection, and I finally managed to post it, noticing only afterwards that it'd been properly answered twice. Personally I prefer referring to a truth table to work out bitwise operations, so I'll leave it in case it helps someone.

提交回复
热议问题