在寫代碼時遇到了“判斷一個正整數是否是2的N次方”的問題,不想調用 java.lang 的 Math 類庫進行浮點運算,覺得轉換為浮點不是個好辦法。
遂在網上搜索了一下,發現有人列出來好幾種寫法,列舉幾種:
1、通過循環除2;這種方法不值一提,略過;
2、針對32位/64位只有有限個 2 的N次方的常量值,逐個進行比較;額。。。這個也略過;
3、通過正則表達式進行文本匹配,判斷是否2的后面都是 0 ;這個繞得更遠了。。。
最后,有一種最簡潔優雅的寫法:(value & (value -1)) == 0;
喔,的確是簡潔優雅!!!
不過,等等,接下來有人提出,似乎“所有2的N次方的結果都符合這個表達式”這點很容易證明;
可是如何證明符合條件“(value & (value -1)) == 0”的一定就是 2 的 N 次方呢?(N 是整數且大於等於0)。
想了一下,證明也不難,遂在此記下:
1、首先,記 A = value; B = value - 1;
2、既然 A & B == 0,那么意味着,A和B的二進制形式中,每一位都不相同;(例外的情況只有“兩者都是 0” ,否則存在相同位的兩個數的按位相與的結果不可能為 0)
3、由於 B = A - 1,即 A > B;基於第2點,A 和 B 每一位都不同,則可以推斷出只有兩種情況:
(1)以二進制形式, A 最高位 1 與 B 的最高位 1 的位數相差 1 ;(x表示后面跟隨的位數是 0 位到多位)
A: 10xxxxxxx
B: 01xxxxxxx
(2)第二種情況就是:A = 1,B = 0;
顯然第二種情況是符合命題的,因為 N = 0 ,2 的 N 次方的結果為 1 ; 接下來繼續針對第一種情況做推導。
4、由於 A 與 B 僅相差1,那意味着在 B 的二進制的末尾加上 1 ,將會連續地向高位產生進位,最終導致 B 的最高位 01 進位為 10 ;
注意,二進制形式中,能夠“連續向高位產生進位”的情況只有一種,即 xxxxxxx 全部都是 1 ,也就是說 B 的全部是 1 ;
由此,基於第2點,A 和 B 的每一位都不同,那么 A 除了最高位 1 之外,所有低位都是 0 ;
由此證得命題!