iT邦幫忙

2024 iThome 鐵人賽

DAY 24
1
Modern Web

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

[Day24]-雖然愛莫能助,但還是盡力理解了。二進位的乘法

  • 分享至 

  • xImage
  •  

昨天學會了位元運算「旭賦忑」,今天就能來看看Math.imul()到底怎麼做32位元的乘法吧!

我們用簡單的範例來模擬一次平移乘法的運算吧!

假設我們要計算3乘以6,用位元運算的方式,首先我們要將他們視為二進位的數字:

console.log(3 .toString(2)); //'11'
console.log(6 .toString(2)); //'110'
console.log(12 .toString(2)); //'10010'

toString(2)就能將數字轉為二進位表示。

我們現在知道3 * 6 = 18
也就是11乘上110等於10010

要怎麼解讀呢,我這邊提供一個方法讓大家比較好理解,也就是「分配律」。
我們知道數字向左移動一個單位就是將這個數乘以二,移動兩個單位就是乘以四,但是今天想做到的是乘以六呢?要如何平移才會是乘以六呢???

十進位的乘法

我們回想一下十進位的乘法,假設我們要做23 * 45我們可以怎麼做呢?沒錯,打開計算機按下去。,先把45拆成40 + 5,然後做(23 * 40) + (23 * 5) = 920 + 115 = 1035,理解了吧!聰明的你肯定理解了乘法可以將每個位數拆開來乘再加起來!

那讓我們回到二進位吧!

二進位的乘法

回到11乘以110,將乘數110分解成100 + 10,再利用分配律乘進去,也就是乘以2^22^1,那這時候乘以二的次方我們就可以用「向左平移」來處理了!2^2就是向左平移兩單位;2^1就是向左平移一單位,將他們加起來就是乘以110的結果了!

所以我們可以記成(0b11 << 2) + (0b11 << 1)

console.log((0b11 << 2) + (0b11 << 1)); //18

成功了!我們成功算出正確答案了~~

再來簡單包裝成函式吧!

function shiftMultiply(multiplicand, multiplier) {
    let result = 0;
    let shift = 0;
    
    while(multiplier > 0) {
        if(multiplier & 1) {
            result += multiplicand << shift
        }
        shift++;
        multiplier >>= 1;
    }
    
    return result;
}

console.log(shiftMultiply(3, 6)); //18

首先令結果result0,向左平移的量shift也為0,接著判斷當乘數不為0的時,近一步判斷要不要平移,這邊用了& 1來判斷最右的位元是否為1,是就平移之後加進result,接著shift加一、乘數向右平移將剛剛判斷完的位元擠掉,繼續判斷下個位元。全部平移完就回傳result,這是一個簡單實現32位元乘法的範例。

但開頭其實要說的是Math.imul()對吧?實際上我們少了幾個要點:溢位時的處理,負數的計算等等。不過別在意!我們今天也成功學到了如何實作二進位的乘法了!應該也算是半個Math.imul()吧...

同場加映
如果各位對什麼時候要加一、什麼時候要終止迴圈覺得很難控制,這邊提供另一個奇妙的做法,使用array method~~但就會需要先將要處理的資料用split轉成陣列,然後我們就能盡情的揮灑array咒語啦~

這邊就留給大家參考參考:

function shiftMultiple(twoBitNumber, multiplier) {
    return multiplier .toString(2)
        .split('')
        .map(str => Number(str))
        .reverse()
        .reduce((sum, shiftable, shiftTimes, numberStr) => {
            if (shiftable) {
                sum.result += twoBitNumber << shiftTimes;
                return sum
            }
            else sum;
        }, {origin: twoBitNumber, result: 0})
}

shiftMultiple(4, 3);

有任何想法也歡迎大家底下留言一起討論喔!

各位明天見~

參考資料
Number.prototype.toString()


上一篇
[Day23]-向左走,向右走...先向左就好。 << 位元運算子
下一篇
[Day25]-奢踢兔竟然出現在函式名稱上啦!!!Math.clz32()
系列文
如何詠唱JavaScript的Math咒語30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言