JavaScript大數(shù)相加相乘的實現(xiàn)方法實例
前言
JavaScript 中的最大安全整數(shù)是 2 ^{53} – 1 ,即 9007199254740991,當我們進行超出這個范圍的數(shù)值計算的時候就無法得到精確的值,而是一個近似值,比如我們計算 9007199254740991 + 10 得到的結(jié)果是 9007199254741000。本文講一下如何利用字符串在 JavaScript 中實現(xiàn)大數(shù)相加相乘。
相加
用字符串實現(xiàn)相加相乘基本思路就是按照我們在紙上進行豎式運算一樣。對于加法,我們需要將兩個數(shù) num1 和 num2 上下對齊,然后從個位開始計算兩個數(shù)對應(yīng)位的和,循環(huán)到最高位,將每一次運算的結(jié)果保存到一個數(shù)組 result 中去,最終用 Array.prototype.join() 方法還原成一個數(shù)組。
這里為了保持循環(huán)的正常進行,我們需要保證兩個字符串位數(shù)相等,所以我們要用 String.prototpye.padStart() 方法將位數(shù)比較小的那一個字符串的前面用 '0' 補齊。
按位相加有個問題就是進位如何保存,我的思路是這樣的。當我們相加 num1[i] 和 num2[i] 的時候,得到的最多是一個兩位數(shù),它將影響 result 的兩位,即當前的 result[0] 位置和即將 unshift 到 result 中的一位。當前的 result[0] 位置的數(shù)就是計算 [i -1] 是得到的數(shù)的高位(即進位),我們將我們計算的值加上進位,得到的數(shù)在分成兩位分別放到 result 中。
所以總結(jié)一下就是我們計算 num1[i] + num2[i] 得到一個兩位數(shù),這個兩位數(shù)要先和 num1[i-1] + num2[i-1] 的結(jié)果的進位(即 result[0] 相加,然后在分成 high 和 low 兩位,將 result[0] 的值用 low 位替換,然后將 high 位 unshift 到 result 最前面??梢詤⒖枷聢D理解。
所以我們每次計算都是確定一位和下一位的進位。最后代碼如下:
let add = function (num1, num2) { if (isNaN(num1) || isNaN(num2)) return ''; if (num1 === '0' || num2 === '0') return (num1 === '0' ? num2 : num1); let len = Math.max(num1.length, num2.length); num1 = num1.padStart(len, '0'); num2 = num2.padStart(len, '0'); let result = []; for (let i = len - 1; i >= 0; i--) { let sum = Number(num1[i]) + Number(num2[i]) + (result[0] || 0); let low = sum % 10; let high = Math.floor(sum / 10); result[0] = low; result.unshift(high); } return result.join(''); } console.log(add('10', '9007199254740991')) //09007199254741001
代碼中我們加了兩個判斷,判斷兩個參數(shù)是否是合法數(shù)字格式,以及如果一個數(shù)是 '0' 則直接返回另一個數(shù)。
相乘
相乘的邏輯要比相加復(fù)雜一點,但是總體思路還是根據(jù)豎式來實現(xiàn)算法,我畫了一張圖,我們借助圖來說明。
相乘是一個兩層循環(huán),我們要循環(huán)一個數(shù)的位,每一位再與另一個數(shù)循環(huán)的每一位相乘。我們每次相乘的結(jié)果最多是一個兩位數(shù)。但是與相加不同的是,相加的 high 每次都是 unshift 進去即可,而相乘的高位也要與 result 的位進行運算。
我們來看一看相乘的規(guī)律,當我們用 num1[i] * num2[j] 的時候,可能得到兩位數(shù),也可能得到一位數(shù),我們都統(tǒng)一算作兩位數(shù),高位沒有的就用 0 補齊,那么最后我們得到的結(jié)果將是一個 i + j 位的數(shù)(開頭可能存在補齊的 0)。而我們每次計算 num1[i] * num2[j] 的結(jié)果影響到的都是 result 中的 i + j 和 i + j + 1 位。
和加法中邏輯一樣,我們將 num1[i] * num2[j] 的結(jié)果和 result[i + j + 1] 相加,得到的結(jié)果分為 low 和 high 分別存入 reslut 的 [i + j +1] 和 [i +j] 中。但是這里要注意,和加法不同,加法的高位直接存入就可以,我們這里的 high 對應(yīng)的 result[i + j] 可能已經(jīng)有值了,我們需要將已經(jīng)存在的值加上。
high 和 result[i +j] 的相加可能存在進位怎么辦呢,看上圖中右邊的當前 result 值中我們可以看到有些位存了不止一位數(shù),我們將 high + result[i +j] 的值直接連進位一起保存到 result[i + j] 中。為什么能這樣做呢,因為下次計算 num1[i] * num2[j - 1] 的時候(注意我們是從后往前遍歷),會把 result[i + j]和 low 相加,進位自然能被處理,這也是這個算法比較重要的地方。
最后的代碼:
let multiply = function (num1, num2) { if (isNaN(num1) || isNaN(num2)) return ''; if (num1 === '0' || num2 === '0') return '0'; let l1 = num1.length, l2 = num2.length; let result = []; for (let i = l1 -1; i >= 0; i--) { for (let j = l2 - 1; j >= 0; j--) { let index1 = i + j; let index2 = i + j + 1; let product = num1[i] * num2[j] + (result[index2] || 0); result[index2] = product % 10; result[index1] = Math.floor(product / 10) + (result[index1] || 0); } } return result.join('').replace(/^0+/, ''); } console.log(multiply('123', '234')) //28782
代碼中加了兩個判斷:是否是合法數(shù)字,如果有一個值為 0 則直接返回 0。注意最后要判斷得到的結(jié)果是否開頭有 0,如果有則要去掉,這里用的正則表達式。
總結(jié)
到此這篇關(guān)于JavaScript大數(shù)相加相乘的實現(xiàn)方法的文章就介紹到這了,更多相關(guān)JavaScript大數(shù)相加相乘內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺談JS對html標簽的屬性的干預(yù)以及對CSS樣式表屬性的干預(yù)
下面小編就為大家?guī)硪黄獪\談JS對html標簽的屬性的干預(yù)以及對CSS樣式表屬性的干預(yù)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-06-06JavaScript結(jié)合AJAX_stream實現(xiàn)流式顯示
這篇文章主要介紹了JavaScript結(jié)合AJAX_stream實現(xiàn)流式顯示,需要的朋友可以參考下2015-01-01webpack里使用jquery.mCustomScrollbar插件的方法
malihu-custom-scrollbar-plugin是一個依賴jquery的自定義網(wǎng)頁滾動條樣式插件,這篇文章主要介紹了webpack里使用jquery.mCustomScrollbar插件的方法,感興趣的小伙伴們可以參考一下2018-05-05JavaScript數(shù)據(jù)結(jié)構(gòu)學習之數(shù)組、棧與隊列
這篇文章主要給大家介紹了JavaScript數(shù)據(jù)結(jié)構(gòu)之數(shù)組、棧與隊列的相關(guān)資料,文中對數(shù)組、棧與隊列的使用方法進行了詳細的總結(jié),相信對大家具有一定的參考學習價值,需要的朋友們下面來一起看看吧。2017-05-05博客側(cè)邊欄模塊跟隨滾動條滑動固定效果的實現(xiàn)方法(js+jquery等)
現(xiàn)在很多的獨立博客和網(wǎng)站如人人網(wǎng)等,都使用了讓側(cè)邊欄模塊隨滾動條滑動而位置固定的效果2013-03-03關(guān)于封裝axios網(wǎng)絡(luò)請求降低代碼耦合度詳解
在項目中直接使用Axios或其他第三方庫來發(fā)送網(wǎng)絡(luò)請求獲取數(shù)據(jù)時,會導(dǎo)致代碼與網(wǎng)絡(luò)請求的邏輯耦合度過高,導(dǎo)致難以維護,所以本文將講解如何將網(wǎng)路請求的代碼進行封裝來進行解耦操作,文中通過代碼示例和圖文講解的非常詳細,需要的朋友可以參考下2024-05-05使用JavaScript和CSS實現(xiàn)文本隔行換色的方法
這篇文章主要介紹了使用JavaScript和CSS實現(xiàn)文本隔行換色的方法,當然最普通的也可以單純用CSS實現(xiàn),需要的朋友可以參考下2015-11-11