整數的位操做:判斷一個整數的二進制是否含有至少兩個連續的位爲1

碰到一個利用字節位操做解決的問題,如何判斷一個整數的二進制是否含有至少兩個連續的1.python

問題自己並不複雜,利用二進制的未操做便可完成,方法也有多種,不一樣方法效率也差不少,分別利用Python和C來實現並對比一下。算法

方法一:從頭至尾遍歷一遍每一位便可找出是否有連續的1存在

這個方法是最廣泛的、第一感受就能想到的方法,下面咱們看一下它的具體實現:工具

Python代碼:oop

def method_1(n) :                                                                                                               
    last_is_one = False
    this_is_one = False
    while n > 0:
        this_is_one = n % 2 
        if this_is_one and last_is_one:
            return True
        n = n >> 1
        last_is_one = this_is_one
    return False

上面的實現中,對於整數n先作取餘運算(n % 2),若是餘數爲1,則n的最後一位是1,不然爲0,並用this_is_one記錄當前位;性能

而後判斷一下,此次和上次的最後一位是否是都是1,若是是,則能夠斷定該整數有兩個連續的1,不然把n向左移一位,繼續循環開始的取餘操做。測試

方法二:無需遍歷每一位,但仍是位操做:移一位(左移、右移皆可)而後和原數「位與」一下便可

這個原理不復雜,思考一下:優化

若是有兩個連續的位爲1,原數和移爲後的數「位與」操做,就是會發生這兩個連續的1進行「位與操做」,則結果中必出現至少一個位爲1 (1&1 == 1),結果不爲零;this

若是沒有至少兩個連續的位爲1,則1的兩邊都是0,原數和移爲後的數「位與」操做,就是1與兩邊的0進行「位與操做」,則全部的1都變成了0 (1&0 == 0),結果必爲零;spa

由以上推理,算法就簡化的不少,只用一行代碼便可搞定。code

Python代碼:

def foo2(n):
    return (n & n<<1) > 0

那麼,上面兩種方法的效率差多少呢,咱們來測試一下看看:

Python代碼

def test(func, loops):
    b = time.time()
    for n in range(loops):
        func(n)
    e = time.time()
    print(loops, ', time cost:', e-b)


if __name__ == '__main__':
    test(foo1, 10**6)
    test(foo2, 10**6)

 

看一下運行結果,循環1百萬次,方法二的速度是方法一的4倍多:

<function method_1 at 0x7f60de787e18> 1000000 , time cost: 0.6687741279602051
<function method_2 at 0x7f60de75b598> 1000000 , time cost: 0.16364359855651855

接下來,用C實現一下看看效率如何

C語言代碼

#include 
#include <sys/time.h>


int method_1(int n) {
  int last_is_one = 0;
  int this_is_one = 0;
  while(n > 0) {
    this_is_one = n % 2;
    if(this_is_one && last_is_one) {
      return 0;
    }
    n = n >> 1;
    last_is_one = this_is_one;
  }
  return 1;
}

int method_2(int n) {
  return n & n >> 1;
}

void test(int (*func)(int), int loops) {
  struct timeval b, e;
  gettimeofday(&b, 0);
  for(int i = 0; i < loops; i++) {
    (*func)(i);
  }
  gettimeofday(&e, 0);
  double timecost = (e.tv_sec - b.tv_sec)*1000.0 + (e.tv_usec - b.tv_usec)/1000.0;                               
  printf("loops: %d, timecost: %f ms\n", loops, timecost);
}

int main(int argc, char** argv) {
  test(method_1, 1000000);
  test(method_2, 1000000);
  return 0;
}

編譯並運行以上C代碼:

gcc two-consecutive-bits.c
./a.out

loops: 1000000, timecost: 50.572000 ms
loops: 1000000, timecost: 4.253000 ms

從以上結果看,C語言實現的算法二比算法一塊十幾倍。

編譯優化後運行:

gcc two-consecutive-bits.c -O3
./a.out

loops: 1000000, timecost: 13.407000 ms
loops: 1000000, timecost: 3.537000 ms

編譯器優化後的結果,算法二比算法一塊4倍多,但都比未優化的快了不少。

順便也「自黑」一下Python的性能,確實比起C來差很遠。可是合適的工具作適合的事情永遠是對的,不妨理解如下下面一段引文:

有個須要天天運行的Python程序,運行大概須要1.5秒。
我花了六小時用Rust重寫它,如今運行須要0.06秒。
效率的提高意味着,我要花41年零24天,才能找回我多花的時間 :-)

相關文章
相關標籤/搜索