Math.abs(~2018)
某前端群的入門問題長姿勢了,一個簡單的入門問題卻引發了我的思考,深深的體會到自己在學習前端技術的同時忽略遺忘了一些計算機的基礎知識。
對於 JS Math對象沒什么可說的, Math.abs(x)指的是返回一個數的絕對值,而解題關鍵在“~2018”,乍一看,這是什么意思,不會是“-2018”符號打錯了吧?細思一下才恍然大悟,這是取反操作符,故取相反數得結果為-2018,Math.abs(-2018) 即2018,大功告成!可是,輸入進去發現,What!錯誤!Why!
首先,取反操作是按位取反,而不是取相反數,即把數據的二進制數中0變1,1變0;
然后,要考慮到計算機中數據的存儲是二進制數據,以補碼的形式存在;
此處,我們要把2018轉化為二進制數,然后取反之后在轉化為十進制數嗎?顯然這對於2018這么大的數很麻煩,不如我們分析下有什么規律可循。
舉個栗子:
var x = 10;
在計算機中一個整型數4字節,1字節8位,所以數字10在計算機中存儲占32位,即
00000000 00000000 00000000 00001010,
按位取反,得
11111111 11111111 11111111 11110101,
這個二進制數據就是“~10”,最高位是1表示它是個負數,那么我們如何轉化為十制數呢?
這里又涉及到了負數在計算機里的存儲問題,計算機里,負數以其正值的補碼形式存在。
再舉個例子:
-10 ,二進制表示為
10000000 00000000 00000000 00001010
原碼,取其絕對值也就是10,即
00000000 00000000 00000000 00001010
反碼,按位取反,得
11111111 11111111 11111111 11110101
補碼,即將反碼加1,得
11111111 11111111 11111111 11110110
至此,我們得到了計算機中-10的二進制存儲形式。
然后我們再回到上一個問題,我們怎么根據計算機中的補碼得到這個負數呢?
我們可以按原路返回,就是將計算機中存儲的二進制補碼減1,然后取反,再得到原碼,換成相應負數即可,不過這樣有點麻煩,因為涉及到了減法操作。
另一種方法,將負數的補碼先取反,然后加1,最高位置換為1即可。
對於~10,在計算機中存儲為
11111111 11111111 11111111 11110101 (這是10取反的結果,但卻是未知數X的補碼形式)
先取反,得
00000000 00000000 00000000 00001010 (此處,再次取反,返回10)
再加1,得
00000000 00000000 00000000 00001011 (10+1得11)
最高位變1,即
10000000 00000000 00000000 00001011 (取相反數即-11)
結果是“-11”
由此我們可以看出規律:“~x”的結果為“-(x+1)”
所以“~2018”就等於“-2019”,Math.abs(-2019)即2019!!