在一次代碼優化的過程當中把html
// a,b都爲正整數且大於0
while (a>=b) {
a-=b;
}
複製代碼
優化爲bash
// a,b都爲正整數且大於0
while (a>=b) {
let tmpB = b;
while (a>=tmpB) {
let tmpShiftB = tmpB<<1;
if (a>=tmpShiftB) {
tmpB = tmpShiftB;
} else {
a-=tmpB;
}
}
}
複製代碼
本意是若是a很大,b很小的狀況,也能把快速進行減法運算。
但後來發現a一旦很大,就會死循環,這個仍是機率出現。
後來debug發現到必定時候tmpShiftB會變成0,致使死循環。
當時就想確定是位移符的坑,後來發現有下面問題
優化
tmpShiftB到達2147483648後左移一位變0
複製代碼
我一看樂了,這不是2的-32次方嘛,確定是JS當有符號的int32型算了,而後溢出了,八成是谷歌引擎的的BUG!
但想一想別高興的太早,看看標準怎麼說,畢竟制定標準的人也賊坑。讓咱們看看標準怎麼寫的。
ui
12.9.3The Left Shift Operator ( << )
NOTE
Performs a bitwise left shift operation on the left operand by the amount specified by the right operand.
12.9.3.1Runtime Semantics: Evaluation
ShiftExpression:ShiftExpression<<AdditiveExpression
Let lref be the result of evaluating ShiftExpression.
Let lval be ? GetValue(lref).
Let rref be the result of evaluating AdditiveExpression.
Let rval be ? GetValue(rref).
Let lnum be ? ToInt32(lval).
Let rnum be ? ToUint32(rval).
Let shiftCount be the result of masking out all but the least significant 5 bits of rnum, that is, compute rnum & 0x1F.
Return the result of left shifting lnum by shiftCount bits. The result is a signed 32-bit integer.
複製代碼
翻譯下來大概意思是:spa
左表達式<<右表達式
左表達式結果轉成Int32(有符號的int的32位類型),結果取名lnum
右表達式結果轉成Uint32(無符號的int的32未類型),同時進行& 0x1F運算(即保留2進制的後5位,再白話一點就是保留32之內的位的數值,但和%32又有些不一樣),結果取名shiftCount
最後再把lnum左位移shiftCount位,並把這個結果再轉換成有符號的int的32位類型
複製代碼
一看下來壞了,果真是標準坑爹,且不說左表達式結果轉成了有符號的int的32位類型,位移後的結果也給轉成了有符號的int的32位類型。果真是標準坑爹。翻譯
看來之後使用左位移符都要當心了,只適用於int32的範圍(-2^32~2^32),要是有可能超過,看來是斷斷不能用了。看來JS的世界精確整數也不必定就是(-2^53~2^53)範圍了。debug