各位今天過得好嗎?是不是又在深夜時刻不睡覺自己在emo呢?
一樣!半夜睡不著非常推薦看看三角函數,再不行就看反三角函數。
如果很喜歡emo,那今天就來介紹emo的好朋友imul給大家認識認識!肯定會比自己一個人emo有趣許多喔~
跟著一起唸!
「寐偲,愛莫!!!」
Math.imul()
這個方法的命名來源是來自integer multiply
「整數乘法」,顧名思義就是針對整數的乘法,這與原本JS中的運算子*
有所區別,Math.imul()
專門針對整數做乘法,且會轉換為32位元的形式做計算,類似於C語言的乘法運算,在溢出時也會模擬C語言的處理方式。
Math.imul(a, b)
放入第一個數字
放入第二個數字
根據給定的參數,回傳類似C語言的32位元乘法結果。
喔!非常簡短呢!
這個函式會執行以下步驟:
a
,值會是將x
轉為32為元且轉成數學值。b
,值會是將y
轉為32為元且轉成數學值。product
,值會是(a * b) modulo 2^32
。product
大於等於2^31
,回傳(product - 2^32)
,除此之外就將product
轉成 ECMAScript 中的數值回傳。很簡短,但包含了一些一言難盡的概念呢哇哈哈!
其中第一個位元是用來表示「符號」,所以剩下31個位置來放二進位的數字,所以可以表現的值就是2^31 - 1
這麼大,那再加上符號可以表示的範圍就是-2^31
~2^31-1
。詳細情況可以到下方參考資料:32位元的維基百科解釋
關於modulo
,ECMAScript這麼說:
The notation “x modulo y” (y must be finite and non-zero) computes a value k of the same sign as y (or zero) such that abs(k) < abs(y) and x - k = q × y for some integer q.
「x modulo y
(y有限且非0
)計算出一個跟y
符號相同的值k
,使得絕對值k
小於絕對值y
,且會有某個整數q
滿足x - k = q * y
。」
好吧我知道很難懂~這邊大家可以先暫時理解為x modulo y
就是x % y
,x
除以y
之後得到的餘數。舉例來說7 modulo 3
就會得到1
,因為7
除以3
會得到2
餘1
。
想更深入理解可以到最下面參考資料中參考維基百科的模運算~
理解模運算以後回來看看第四點吧!
「如果product
大於等於2^31
,回傳(product - 2^32)
,除此之外就將product
轉成 ECMAScript 中的數值回傳。」
所以(a * b)
的結果拿去跟2^32
做模運算,得出來的結果就會是(a * b)
除以2^32
的餘數。那如果這個餘數大於等於2^31
代表什麼呢?代表他超過了32位元可以表示的數啦!!!(因為32位元第一個位元在表示正負號)這時候就要做類C語言的溢出處理了,也就是將他的值扣掉2^32
。
為什麼是扣掉2^32
呢?因為第一位元表示符號,後面31位元表示數字,當31位元溢位了,就會補到第一位元,也就是正負號反轉了,值的部分就會是以二補數的形式表現,這個行為透過扣掉2^32
,也能夠達成同樣的結果,也就是將這個超過範圍的數映射回可表現的範圍內。
來用看看吧!
console.log(Math.imul(6, 8)); //48
console.log(Math.imul(Math.pow(2, 31) - 1, 1)); //2147483647
console.log(Math.imul(0b1011, 0b10)); //22
//溢位處理
console.log(Math.imul(Math.pow(2, 31), 1)); //-2147483648
console.log(Math.imul(-Math.pow(2, 31) - 1, 1)); //2147483647
那我們究竟該怎麼選擇Math.imul()
跟*
呢?
跟大家說說我自己的看法吧!
Math.imul()
只接收整數,所以如果資料有小數的情況,就是*
優先,因為Math.imul()
還要對資料做取整。(超過32位元可表示的範圍一樣需要再額外做溢位處理,所以也會耗費資源)
那但是如果資料都保證是整數,且保證落在32位元可表示的範圍呢?我認為解答也不是絕對的,Math.imul()
在規範中第一步就已經表明他會將傳入的資料做ToUnit32
的抽象操作,這個過程也許也會耗費資源,那也許我們會認為進到32位元數字的乘法運算後,可能就有優勢了!因為這時候的乘法運算將會以「平移」的方式進行,可能會在CPU中更有效率的運算,但這也取決於不同CPU對於複雜運算的優化程度。
還是說原本是使用C語言的工程師會比較習慣這樣的溢位處理?
講了這麼多,我就是沒有答案XDD
不同的CPU就是不同的運算環境,不同的環境對於同樣的運算也會有不同的運行成本,有沒有大神可以解救我,對於想理解這些的人來說,我真的愛莫能助...
「寐偲,愛莫...」
參考資料:
MDN-Math.imul()
ECMAScript-Math.imul()
維基百科-32位元
維基百科-模運算
Why is Math.imul() faster than a regular multiplication (*)...