iT邦幫忙

2024 iThome 鐵人賽

DAY 22
1
Modern Web

如何詠唱JavaScript的Math咒語系列 第 22

[Day22]-我真的愛莫能助...Math.imul()

  • 分享至 

  • xImage
  •  

各位今天過得好嗎?是不是又在深夜時刻不睡覺自己在emo呢?

一樣!半夜睡不著非常推薦看看三角函數,再不行就看反三角函數。

如果很喜歡emo,那今天就來介紹emo的好朋友imul給大家認識認識!肯定會比自己一個人emo有趣許多喔~

跟著一起唸!

「寐偲,愛莫!!!」

Math.imul()

Math.imul()這個方法的命名來源是來自integer multiply「整數乘法」,顧名思義就是針對整數的乘法,這與原本JS中的運算子*有所區別,Math.imul()專門針對整數做乘法,且會轉換為32位元的形式做計算,類似於C語言的乘法運算,在溢出時也會模擬C語言的處理方式。

語法

Math.imul(a, b)

參數

  • a

    放入第一個數字

  • b

    放入第二個數字

回傳值

根據給定的參數,回傳類似C語言的32位元乘法結果。

規範

image
喔!非常簡短呢!

這個函式會執行以下步驟:

  1. 令一個a,值會是將x轉為32為元且轉成數學值。
  2. 令一個b,值會是將y轉為32為元且轉成數學值。
  3. 令一個product,值會是(a * b) modulo 2^32
  4. 如果product大於等於2^31,回傳(product - 2^32),除此之外就將product轉成 ECMAScript 中的數值回傳。

很簡短,但包含了一些一言難盡的概念呢哇哈哈!

32位元數字?

其中第一個位元是用來表示「符號」,所以剩下31個位置來放二進位的數字,所以可以表現的值就是2^31 - 1這麼大,那再加上符號可以表示的範圍就是-2^312^31-1。詳細情況可以到下方參考資料:32位元的維基百科解釋

modulo?

關於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 % yx除以y之後得到的餘數。舉例來說7 modulo 3就會得到1,因為7除以3會得到21

想更深入理解可以到最下面參考資料中參考維基百科的模運算~

理解模運算以後回來看看第四點吧!

「如果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 (*)...


上一篇
[Day21]-傳說中的,阿姆斯特朗炫風噴射阿姆斯特朗,砲。Math.pow()
下一篇
[Day23]-向左走,向右走...先向左就好。 << 位元運算子
系列文
如何詠唱JavaScript的Math咒語30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言