日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

长整数的乘法运算

發(fā)布時(shí)間:2024/8/23 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 长整数的乘法运算 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

概述

都知道, 計(jì)算機(jī)中存儲(chǔ)整數(shù)是存在著位數(shù)限制的, 所以如果需要計(jì)算100位的數(shù)字相乘, 因?yàn)榫幊瘫旧硎遣恢С执鎯?chǔ)這么大數(shù)字的, 所以就需要自己實(shí)現(xiàn), 當(dāng)然了, 各個(gè)編程語(yǔ)言都有大數(shù)的工具包, 何必重復(fù)造輪子, 但我還是忍不住好奇他們是如何實(shí)現(xiàn)的, 雖然最終沒(méi)有翻到他們的底層源碼去, 但查詢(xún)的路上還是讓我大吃一驚, 來(lái)吧, 跟我一起顛覆你的小學(xué)數(shù)學(xué).

長(zhǎng)乘運(yùn)算

當(dāng)然, 如果自己實(shí)現(xiàn)這樣一個(gè)大數(shù), 用數(shù)組來(lái)存儲(chǔ)每一位是我當(dāng)前想到的方法. 那如何進(jìn)行乘法運(yùn)算呢? 因?yàn)橛脭?shù)組來(lái)存儲(chǔ)數(shù)字, 那么數(shù)字的加法也要采用每一位進(jìn)位的方式來(lái)進(jìn)行, 所以下面為了方便說(shuō)明算法的效率, 以一次個(gè)位數(shù)的運(yùn)算視為一個(gè)運(yùn)算單位.

上小學(xué)知識(shí):

  • 4?5=204*5=204?5=20
    • 個(gè)位數(shù)相乘, 一次運(yùn)算
  • 14?5=(4?5)+(1?5)?10=7014*5=(4*5)+(1*5)*10=7014?5=(4?5)+(1?5)?10=70
    • 2位數(shù)乘1位數(shù), 分解后共: 2次乘法和2位數(shù)的加法, 4次運(yùn)算(乘10可看做移位操作)
  • 134?6=(4?6)+(3?6)?10+(1?6)?100=804134*6=(4*6)+(3*6)*10+(1*6)*100=804134?6=(4?6)+(3?6)?10+(1?6)?100=804
    • 3位數(shù)乘1位數(shù), 分解后共: 3次乘法, 3位數(shù)的加法(不要看兩個(gè)加號(hào), 可以乘法運(yùn)算完后做連加運(yùn)算, 當(dāng)然, 也可能連加之后發(fā)生溢出, 暫不考慮. 此處簡(jiǎn)化只看加法的位數(shù)即可), 6次運(yùn)算.
  • 1234?7=(4?7)+(3?7)?10+(2?7)?100+(1?7)?1000=86381234*7 = (4*7) + (3*7)*10 + (2*7)*100 + (1*7)*1000 = 86381234?7=(4?7)+(3?7)?10+(2?7)?100+(1?7)?1000=8638
    • 4位數(shù)乘1位數(shù), 8次運(yùn)算.

通過(guò)上面可總結(jié)規(guī)律, n位數(shù)乘一位數(shù), 需要 2n 次運(yùn)算. 將 n 位數(shù)乘1位數(shù)的運(yùn)算稱(chēng)作短乘. 然后下面再看一下 n 位數(shù)乘 n 位數(shù).

  • 14?13=(14?3)+(14?1)?10=18214*13=(14*3) + (14*1)*10=18214?13=(14?3)+(14?1)?10=182
    • 兩位數(shù)相乘, 2次短乘, 4位數(shù)加法(99*9*10 最差情況). 共: 2?(2n)+4=122*(2n) + 4 = 122?(2n)+4=12 次運(yùn)算
  • 132?256=(132?6)+(132?5)?10+(132?2)?100=33792132*256=(132*6)+(132*5)*10+(132*2)*100=33792132?256=(132?6)+(132?5)?10+(132?2)?100=33792
    • 三位數(shù)相乘: 3次短乘, 6位數(shù)加法(最差情況), 共: 3?(2n)+6=243*(2n) + 6=243?(2n)+6=24次運(yùn)算.

通過(guò)上面, 總結(jié)規(guī)律, n位數(shù)相乘(長(zhǎng)乘)的運(yùn)算次數(shù)是: n?(2n)+2n=2n2+2nn*(2n) + 2n = 2n^2+2nn?(2n)+2n=2n2+2n 次運(yùn)算. 當(dāng)然, 這就是我們從小接受的進(jìn)行乘法運(yùn)算的方法, 所以寫(xiě)成這樣還好, 比較合乎常理. 時(shí)間復(fù)雜度是 O(n^2)

但是, 他還可以更快么? 我以為就這樣了, 是我小看了偉大的數(shù)學(xué)家. .

Karatsuba方法

由簡(jiǎn)入難, 先看一下兩位數(shù)的乘法:

12*34, 為了方便初中方程未知數(shù)的思維, 我們將這兩個(gè)數(shù)字拆解一下:

KaTeX parse error: No such environment: align* at position 8: \begin{?a?l?i?g?n?*?}? 12 &= 10a+b (其…

則,

KaTeX parse error: No such environment: align* at position 8: \begin{?a?l?i?g?n?*?}? & 12*34 \\ =& …

當(dāng)化簡(jiǎn)到這里, 2位數(shù)相乘需要幾次運(yùn)算? 來(lái)算一下:

  • 10(am+bn)10(am + bn)10(am+bn) : 共2次乘法, 2位數(shù)加法, 共4次運(yùn)算.
  • an 和 bm : 共2次乘法, 共2次運(yùn)算
  • 剩下最外層的加法, 最差情況: (100?9?9100*9*9100?9?9 4位數(shù), 10?(9?9+9?9)10*(9*9 + 9*9)10?(9?9+9?9) 4位數(shù)), 共4次運(yùn)算
  • 則總計(jì), 4+4+2=104+4+2=104+4+2=10次運(yùn)算.

此時(shí), 需要的運(yùn)算次數(shù)已經(jīng)較之前的12次少一些了, 但是別急, 容我把公式再變換一下.

令:

u=anw=bms=(b?a)?(m?n)u=an \\ w=bm \\ s=(b-a)*(m-n) u=anw=bms=(b?a)?(m?n)

公式:

100u+(u+w?s)?10+w=100an+(an+bm?(b?a)?(m?n))?10+bm=100an+(an+bm?bm+bn+am?an)?10+bm=100an+(bn+am)?10+bm100u + (u+w-s)*10+w \\ = 100an + (an + bm - (b-a) * (m-n)) *10 + bm \\ = 100an + (an + bm - bm + bn + am - an)*10 + bm \\ = 100an + (bn + am) * 10 + bm 100u+(u+w?s)?10+w=100an+(an+bm?(b?a)?(m?n))?10+bm=100an+(an+bm?bm+bn+am?an)?10+bm=100an+(bn+am)?10+bm

是不是和上面的公式一樣了呢? 是的, 那轉(zhuǎn)換公式是為了什么呢? 當(dāng)然是為了減少運(yùn)算次數(shù)啦. 算一下:

  • 計(jì)算u : 1次運(yùn)算
  • 計(jì)算w: 1次運(yùn)算
  • 計(jì)算 s: 3次運(yùn)算
  • 計(jì)算 u+w-s: 2位數(shù)運(yùn)算, 2次運(yùn)算
  • 計(jì)算最外層加法: 3位數(shù)運(yùn)算, 3次運(yùn)算
  • 共: 10次運(yùn)算.

這和我剛才計(jì)算的不也是10次么? 不過(guò)個(gè)位數(shù)的乘法換成加法就會(huì)變快了么? 不要小看這個(gè)一次乘法運(yùn)算的減少, 從上面能夠看出, 乘法運(yùn)算的運(yùn)算次數(shù)是隨位數(shù)成指數(shù)增長(zhǎng)的, 而加法運(yùn)算則隨位數(shù)成線性增長(zhǎng), 等看了下面的多位數(shù)相乘, 你就知道減少的這一次乘法運(yùn)算有什么用了.

不過(guò)下面才是重頭戲, 數(shù)字多了之后, 此算法就明顯比傳統(tǒng)的快的多了.

4位數(shù)乘法

計(jì)算: 1234?56781234*56781234?5678

設(shè):

1234=100a+b(其中a=12,b=34)5678=100n+m(其中n=56,m=78)1234+5678=(100a+b)?(100n+m)1234=100a+b (其中 a=12, b=34) \\ 5678=100n+m (其中 n=56, m=78) \\ 1234+5678 = (100a + b) * (100n + m) 1234=100a+b(a=12,b=34)5678=100n+m(n=56,m=78)1234+5678=(100a+b)?(100n+m)

套用上面的公式:

令:

u=anw=bms=(b?a)?(m?n)u=an \\ w=bm \\ s=(b-a)*(m-n) u=anw=bms=(b?a)?(m?n)

則結(jié)果為: 10000u+(u+w?s)?100+w10000u + (u+w-s)*100+w10000u+(u+w?s)?100+w

此次進(jìn)行了幾次運(yùn)算呢? 算一下:

  • 計(jì)算 u: 兩位數(shù)乘法, 10次運(yùn)算
  • 計(jì)算w: 10次運(yùn)算
  • 計(jì)算s: 兩位數(shù)減法兩次, 一次乘法, 14次運(yùn)算
  • 計(jì)算整體: 8位數(shù)相加(99?99?1000099*99*1000099?99?10000), 8次運(yùn)算
  • 整體: 10+10+14+8=3210+10+14+8=3210+10+14+8=32次運(yùn)算.

32次運(yùn)算, 之前長(zhǎng)乘的方式需要幾次呢? 2?(4?4)+2?4=402*(4*4) + 2*4=402?(4?4)+2?4=40. 是不是少了.

也就是說(shuō), 4位數(shù)的乘法, 其中用到了3次兩位數(shù)乘法, 2次兩位數(shù)減法, 1次8位數(shù)加法.

8位數(shù)乘法

8位數(shù)乘法就不展開(kāi)了, 直接套用4位數(shù)乘法得出的結(jié)論, 其運(yùn)算次數(shù)為:

  • 3次4位數(shù)乘法: 3?32=963*32=963?32=96
  • 2次4位數(shù)減法: 2?4=82*4=82?4=8
  • 1次 9999?9999?1000000009999*9999*1000000009999?9999?100000000 位數(shù)加法: 17次
  • 共: 96+8+17=12196+8+17=12196+8+17=121次運(yùn)算.

原來(lái)的長(zhǎng)乘需要幾次呢? 2?(8?8)+2?8=1442*(8*8) + 2*8=1442?(8?8)+2?8=144次.

是不是有一種動(dòng)態(tài)規(guī)劃, 分而治之的感覺(jué)? 可以利用函數(shù)遞歸來(lái)實(shí)現(xiàn).

問(wèn)題

想必此算法的問(wèn)題也很明顯了, 為了每次都能將數(shù)字拆成左右兩部分, 所以只能夠計(jì)算位數(shù)是2的 n 次方的數(shù)字, 如果位數(shù)不足, 則需要在前邊進(jìn)行補(bǔ)0.

算法比較

為了比較兩個(gè)算法的運(yùn)算次數(shù), 讓我們忽略運(yùn)算的低次冪以及常數(shù)項(xiàng), 則(以下 n 為2的冪):

長(zhǎng)乘

f(n)={1,n==?12?(2n)2,elsef(n) = \begin{cases} 1, \text{ $n$ == 1} \\ 2 * (2^n)^2, \text{else} \end{cases} f(n)={1,?n?==?12?(2n)2,else?

Karatsuba:

f(n)={3,n==13?f(n?1),elsef(n) = \begin{cases} 3, \text{$n$==1} \\ 3*f(n-1), \text{else} \end{cases} f(n)={3,n==13?f(n?1),else?

分別進(jìn)行計(jì)算:

2的冪/數(shù)字位數(shù)長(zhǎng)乘Karatsuba
20=12^0=120=111
21=22^1 = 221=283
210=10242^{10}=1024210=10242097152
220=10485762^{20}=1048576220=104857621990232555521162261467
250=11258999068426242^{50}=1125899906842624250=11258999068426242535301200456458802993406410752239299329230617529590083
2100=12676506002282294014967032053762^{100}=12676506002282294014967032053762100=12676506002282294014967032053763213876088517980551083924184682325205044405987565585670602752171792506910670443678820376588540424234035840667

可以看出來(lái), 當(dāng)數(shù)字的位數(shù)越大, 則兩個(gè)算法之間的差距越明顯.


有沒(méi)有被顛覆的感覺(jué)? 是不是自己知道了20多年的乘法運(yùn)算, 根本沒(méi)有想到還有其他計(jì)算乘法的運(yùn)算規(guī)則? 我也沒(méi)想到, 漲見(jiàn)識(shí)了…

果然, 沒(méi)有什么是偉大的科學(xué)家們做不到的, 這算法我看了近乎整整一天, 草稿紙廢了四十張, 總算是略知一二了.

總結(jié)

以上是生活随笔為你收集整理的长整数的乘法运算的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。