碰到一個利用字節位操做解決的問題,如何判斷一個整數的二進制是否含有至少兩個連續的1.python
問題自己並不複雜,利用二進制的未操做便可完成,方法也有多種,不一樣方法效率也差不少,分別利用Python和C來實現並對比一下。算法
這個方法是最廣泛的、第一感受就能想到的方法,下面咱們看一下它的具體實現:工具
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語言代碼
#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天,才能找回我多花的時間