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