[英]Why is (a | b ) equivalent to a - (a & b) + b?
我正在尋找一種方法來使用Oracle數據庫進行BITOR()並且遇到了一個建議,只需使用BITAND()代替BITOR(a,b)替換為+ b - BITAND(a,b)。
我用手測試了幾次並驗證它似乎適用於我能想到的所有二進制數,但我無法想出為什么這是正確的快速數學證明。
有人可以開導我嗎?
A和B是在A和B中都打開的位組.A - (A和B)為您留下所有那些僅在A中打開的位。將B添加到該位,並獲得所有位在A中或在B中的那些
簡單地添加A和B將不起作用,因為攜帶兩個都有1位。 通過首先去除A和B共同的位,我們知道(A-(A和B))將沒有與B共同的位,因此保證將它們加在一起不會產生進位。
想象一下,你有兩個二進制數: a
和b
。 並且假設這些數字在同一位中同時沒有1,即如果a
在某個位中有1,則b
在相應位中始終為0。 而在其它方向上,如果b
在一些比特具有1,則a
總是在該位為0。 例如
a = 00100011
b = 11000100
這將是滿足上述條件的a
和b
的示例。 在這種情況下很容易看出a | b
a | b
與a + b
完全相同。
a | b = 11100111
a + b = 11100111
現在讓我們取兩個違反我們條件的數字,即兩個數字在某個公共位中至少有一個1
a = 00100111
b = 11000100
是a | b
a | b
在這種情況下是否與a + b
相同? 沒有
a | b = 11100111
a + b = 11101011
他們為什么不同? 它們是不同的,因為當我們+
在兩個數字中都有1的位時,我們產生所謂的進位 :結果位為0,並且1被傳送到左邊的下一位: 1 + 1 = 10
。 操作|
沒有攜帶,所以1 | 1
1 | 1
再次只是1。
這意味着a | b
的區別 當且僅當數字在公共位中具有至少一個1時,才出現a | b
和a + b
。 當我們將兩個數字與1個公共位相加時,這些公共位被“加”兩次並產生一個進位,這破壞了a | b
之間的相似性a | b
a | b
和a + b
。
現在看看a & b
。 a & b
計算什么? a & b
產生的數字在a
和b
都有1的所有位中都有1.在我們的最新例子中
a = 00100111
b = 11000100
a & b = 00000100
如上所述,這些正是使a + b
與a | b
不同的位 a | b
。 a & b
的1表示將發生進位的所有位置。
現在,當我們做a - (a & b)
我們有效地從a
和僅這樣的位中刪除 (減去)所有“有問題”的位
a - (a & b) = 00100011
數字a - (a & b)
和b
沒有共同的1位,這意味着如果我們添加a - (a & b)
和b
我們將不會遇到進位,並且,如果你考慮它,我們應該最后得到的結果就像我們剛剛做a | b
a | b
a - (a & b) + b = 11100111
A和B = C,其中在C中設置的任何位是在A和B中設置的位。
AC = D或BC = E將這些公共位設置為0.沒有攜帶效應,因為1-1 = 0。
D + B或E + A類似於A + B,不同之處在於因為我們先前減去了A和B,所以由於清除了D或E中所有常用的位,所以不會有進位。
最終結果是AA&B + B或BA&B + A等同於A | B.
這是一個真值表,如果它仍然令人困惑:
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
注意+和 - 操作中的進位行,我們避免那些,因為A-(A和B)設置的情況都是A中的位,B中的A是1到0,然后從B中添加它們也帶來了其他情況在A或B中是1,但兩者都不是0,所以OR真值表和A-(A&B)+ B真值表是相同的。
另一種觀察它的方法是看到A + B幾乎像A | B,除了底行的進位。 A&B隔離了我們的底行,AA&B將那些隔離的那些移動到+表中的兩行,並且(AA和B)+ B變得等同於A | B.
雖然你可以將它轉交給A + B-(A和B),但我擔心可能出現溢出,但這似乎是不合理的:
#include <stdio.h>
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
編輯 :所以我在得到答案之前寫了這個,然后在我的家庭連接上有兩個小時的停機時間,我終於設法發布它,之后才注意到它已經被正確回答了兩次。 就個人而言,我更喜歡使用真值表來計算按位運算,所以我會留下它以防萬一它可以幫助某人。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.