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