計算機中是用二進制數來存儲計算的,在我們學習計算機程式設計語言是總會遇到二進制數的計算,本文就來為大家介紹一下JavaScript中的二進制數,希望對大家有一定的幫助。

在本文中你将學到如下知識:二進制數的表示
js中的二進制數整數
js中的位運算
二進制數
本文假設你知道計算機中用二進制數來存儲,計算數字,并且熟悉二進制數的表示方法。
為了實作不同的目的,其實都是為了簡化問題,二進制數在計算機中有不同的表示方法,如原碼、反碼、補碼和移碼等。
注意:本文問了簡化運算,二進制數都是用一個位元組——8個二進制位來簡化說明
先來說說真值吧,我們表示自然數包括正數,負數和0,下面是1和-1的二進制表示,我們稱為真值+ 00000001 # +1
- 00000001 # -1
8位二進制數能表示的真值範圍是[-2^8, +2^8]。
由于計算機隻能存儲0和1,不能存儲正負,是以用8個二進制位的最高位來表示符号,0表示正,1表示負,用後七位來表示真值的絕對值,這種表示方法稱為原碼表示法,簡稱原碼,上面的1和-1的原碼如下:0 0000001 # +1
1 0000001 # -1
由于10000000的意思是-0,這個沒有意義,所有這個數字被用來表示-128,所有負數就比整數多一個。
由于最高位被用來表示符号了,現在能表示的範圍是[-2^7, +2^7-1],即[-128, +127]
反碼是另一種表示數字的方法,其規則是整數的反碼何其原碼一樣,負數的反碼将其原碼的符号位不變,其餘各位按位取反0 0000001 # +1
1 1111110 # -1
反碼的表示範圍是[-2^7, +2^7-1],即[-128, +127]
補碼是另外一種表示方法,主要是為了簡化運算,将減法變為加法而發明的數字表示法,其規則是整數的補碼和原碼一樣,負數的補碼是其反碼末尾加10 0000001 # +1
1 1111111 # -1
快速計算負數補碼的規則就是,由其原碼低位向高位找到第一個1,1和其低位不變,1前面的高位按位取反即可,不知道聰明的你能不能想到原理。
8位補碼表示的範圍是[-2^7, +2^7-1],即[-128, +127]
js中的二進制數整數
再來說說js中的二進制整數表示,一名合格的jser應該支援在js中隻有一種數字類型,就是浮點型,js的浮點數遵循IEEE 754規範。
然而在js中還有另一種類型的資料,那就是用32個比特位表示的整數,隻要對js中的任何數字做位運算作業系統内部都會将其轉換成整形,嘗試在控制台輸入下面的代碼2.1 | 0 # 或運算
>>> 2
js中的這種整形是區分正負數的,我們根據上面的知識推斷js中的整數的表示範圍是[-2^31, +2^31-1],即[-2147483648, +2147483647],在控制台輸出下面的代碼來驗證我們的推斷。-2147483648 | 0
>>> -2147483648
-2147483649 | 0
>>> 2147483647
2147483647 | 0
>>> 2147483647
2147483648 | 0
>>> -2147483648
從上面的結果可以看出,大于和小于最低和最高的值再去進行轉換時都将改變正負号
js中的位運算
js中的位運算符有下面這些,對數字進行這些操作時,系統内部都會講64的浮點數轉換成32位的整形& 與
| 或
~ 非
^ 異或
<< 左移
>> 算數右移(有符号右移)
>>> 邏輯右移(無符号右移)
下面舉例子來說明每個運算符的作用,開始之前先來介紹幾個會用到的知識點
原生二進制字面量
es6中引入了原生二進制字面量,二進制數的文法是0b開頭,我們将會用到這個新功能,目前chrome最新版已經支援。0b111 // 7
0b001 // 1
Number.prototype.toString
先來介紹下下面會用到的一個方法——Number.prototype.toString方法可以講數字轉化為字元串,有一個可選的參數,用來決定将數字顯示為指定的進制,下面可以檢視3的二進制表示3..toString(2)
>> 11
& 與
&按位與會将操作數和被操作數的相同為進行與運算,如果都為1則為1,如果有一個為0則為0101
011
---
001
101和011與完的結果就是001,下面在js中進行驗證(0b101 & 0b011).toString(2)
>>> "1"
| 或
|按位或是相同的位置上隻要有一個為1就是1,兩個都為0則為0
101
001
---
101
101和001或完的結果是101,下面在js中進行驗證(0b101 | 0b001).toString(2)
>>> "101"
~ 非
~操作符會将操作數的每一位取反,如果是1則變為0,如果是0則邊為1101
---
010
101按位非的結果是010,下面在js中驗證(~0b101).toString(2)
>>> "-110"
啊呀,怎麼結果不對呢!!!上面提到了js中的數字是有符号的,我們忘記了最高位的符号了,為了簡化我們将32位簡化為8位,注意最高位是符号位0 0000101
1 1111010 // 非後的結果
1 0000101 // 求反
1 0000110 // 求補
1 1111010明顯是一個負數,而且是負數的補碼表示,我們的求它的原碼,也就是再對它求補1 0000110就是這個數的真值,也就是結果顯示-110,這下總算自圓其說了,O(∩_∩)O哈哈~
其實上面的與和或也都是會操作符号位的,不信你試試下面這兩個,可以看到符号位都參與了運算(0b1&-0b1)
>>> 1
(0b1|-0b1)
>>> -1
^ 異或
再來說說異或,這個比較有意思,異或顧名思義看看兩個位是否為異——不同,兩個位不同則為1,兩個位相同則為0101
001
---
100
101和001異或的結果是100,js中驗證(0b101^0b001).toString(2)
>>> "100"
<< 左移
左移的規則就是每一位都向左移動一位,末尾補0,其效果相當于×2,其實計算機就是用移位操作來計算乘法的010
---
0100
010左移一位就會變為100,下面在js中驗證(0b010<<1).toString(2)
>>> "100"
>> 算數右移(有符号右移)
算數右移也稱為有符号右移,也就是移位的時候高位補的是其符号位,整數則補0,負數則補1(0b111>>1).toString(2)
>>> "11"
(-0b111>>1).toString(2)
>>> "-100"
負數的結果好像不太對勁,我們來看看是怎麼回事-111 // 真值
1 0000111 // 原碼
1 1111001 // 補碼
1 1111100 // 算數右移
1 0000100 // 移位後的原碼
-100 // 移位後的真值
>>> 邏輯右移(無符号右移)
邏輯右移又稱為無符号右移,也就是右移的時候高位始終補0,對于整數和算數右移沒有差別(0b111>>>1).toString(2)
>>> "11"
對于負數則就不同了,右移後會變為正數(-0b111>>>1).toString(2)
>>> "1111111111111111111111111111100"
關于開頭的問題
關于二進制數就說這麼多吧,再來說說開頭的問題,開頭的問題其實可以分解為下面的問題因為search會傳回-1 和找到位置的索引,也就成了下面的問題!~-1
>>> ture
!~0
>>> false
!~1
>>> false
非運算對于數字的結果相當于改變符号,并對其值的絕對值-1~-1
>>> 0
~0
>>> -1
~1
>>> -2
其實可以看出!~x的邏輯就是判斷x是否為-1,my god這邏輯真是逆天了,我還是勸大家直接寫成 x === -1多好啊
本文轉自:https://yanhaijing.com/javascript/2016/07/20/binary-in-js/