1. 程式人生 > >ORBSLAM2計算描述子距離——C++ 位操作得到二進位制32位int值中有多少個1

ORBSLAM2計算描述子距離——C++ 位操作得到二進位制32位int值中有多少個1

看ORBSLAM2時算描述子之間的距離時看到的神奇的位操作,特此記錄一哈。

    unsigned  int v = *pa ^ *pb;   
    v = v - ((v >> 1) & 0x55555555);
    v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
    dist += (((v + (v >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;

pa和pb分別是兩個描述子,進行異或操作得到一個32位int值,裡面包含多個1,1的個數和即為兩個描述子之間的距離。
然後通過三個語句12個操作即可得到1的個數。

大概說一下我自己的解釋,比較蠢吧,僅供參考。

0x55555555=01010101 01010101 01010101 01010101
我們把32位分成16個2位來看,即XX(X未知,可0可1),我們會發現int a=XX-(XX>>1)&01的結果即為XX中1的數量。

XX>>1=0X

然後會發現int a=XX-(XX>>1)&01後得到的int值即為XX中1的個數。即XX=00時,a=0,XX=01時,a=1,XX=10時,a=1,XX=11時,a=2。

那麼同理,v=v-((v>>1)&0x55555555)得到了32位int值v,將此時的v每兩位表示的int值相加即為原v中1的個數。

接下來

v = (v & 0x33333333) + ((v >> 2) & 0x33333333);

0x33333333=00110011 00110011 00110011 00110011

很明顯,這一步操作是v拆成8個4位,每個4位代表的int值之和即為原v中1的個數,每個4位是由上式中的結果v的相鄰2位拼接得到的。

同理可得v + (v >> 4)) & 0xF0F0F0F是把之前的相鄰4位拼接成8位,則此時32位int值四個八位代表的int值之和即為1的個數。

之後乘0x1010101的目的是把每個8位的數加到25-32位上,然後右移24位移到末8位,即可得到四個八位的int值之和,即1的個數。