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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

长整数的乘法运算

發布時間:2024/8/23 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 长整数的乘法运算 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

概述

都知道, 計算機中存儲整數是存在著位數限制的, 所以如果需要計算100位的數字相乘, 因為編程本身是不支持存儲這么大數字的, 所以就需要自己實現, 當然了, 各個編程語言都有大數的工具包, 何必重復造輪子, 但我還是忍不住好奇他們是如何實現的, 雖然最終沒有翻到他們的底層源碼去, 但查詢的路上還是讓我大吃一驚, 來吧, 跟我一起顛覆你的小學數學.

長乘運算

當然, 如果自己實現這樣一個大數, 用數組來存儲每一位是我當前想到的方法. 那如何進行乘法運算呢? 因為用數組來存儲數字, 那么數字的加法也要采用每一位進位的方式來進行, 所以下面為了方便說明算法的效率, 以一次個位數的運算視為一個運算單位.

上小學知識:

  • 4?5=204*5=204?5=20
    • 個位數相乘, 一次運算
  • 14?5=(4?5)+(1?5)?10=7014*5=(4*5)+(1*5)*10=7014?5=(4?5)+(1?5)?10=70
    • 2位數乘1位數, 分解后共: 2次乘法和2位數的加法, 4次運算(乘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位數乘1位數, 分解后共: 3次乘法, 3位數的加法(不要看兩個加號, 可以乘法運算完后做連加運算, 當然, 也可能連加之后發生溢出, 暫不考慮. 此處簡化只看加法的位數即可), 6次運算.
  • 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位數乘1位數, 8次運算.

通過上面可總結規律, n位數乘一位數, 需要 2n 次運算. 將 n 位數乘1位數的運算稱作短乘. 然后下面再看一下 n 位數乘 n 位數.

  • 14?13=(14?3)+(14?1)?10=18214*13=(14*3) + (14*1)*10=18214?13=(14?3)+(14?1)?10=182
    • 兩位數相乘, 2次短乘, 4位數加法(99*9*10 最差情況). 共: 2?(2n)+4=122*(2n) + 4 = 122?(2n)+4=12 次運算
  • 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
    • 三位數相乘: 3次短乘, 6位數加法(最差情況), 共: 3?(2n)+6=243*(2n) + 6=243?(2n)+6=24次運算.

通過上面, 總結規律, n位數相乘(長乘)的運算次數是: n?(2n)+2n=2n2+2nn*(2n) + 2n = 2n^2+2nn?(2n)+2n=2n2+2n 次運算. 當然, 這就是我們從小接受的進行乘法運算的方法, 所以寫成這樣還好, 比較合乎常理. 時間復雜度是 O(n^2)

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

Karatsuba方法

由簡入難, 先看一下兩位數的乘法:

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

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 \\ =& …

當化簡到這里, 2位數相乘需要幾次運算? 來算一下:

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

此時, 需要的運算次數已經較之前的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

是不是和上面的公式一樣了呢? 是的, 那轉換公式是為了什么呢? 當然是為了減少運算次數啦. 算一下:

  • 計算u : 1次運算
  • 計算w: 1次運算
  • 計算 s: 3次運算
  • 計算 u+w-s: 2位數運算, 2次運算
  • 計算最外層加法: 3位數運算, 3次運算
  • 共: 10次運算.

這和我剛才計算的不也是10次么? 不過個位數的乘法換成加法就會變快了么? 不要小看這個一次乘法運算的減少, 從上面能夠看出, 乘法運算的運算次數是隨位數成指數增長的, 而加法運算則隨位數成線性增長, 等看了下面的多位數相乘, 你就知道減少的這一次乘法運算有什么用了.

不過下面才是重頭戲, 數字多了之后, 此算法就明顯比傳統的快的多了.

4位數乘法

計算: 1234?56781234*56781234?5678

設:

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)

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

此次進行了幾次運算呢? 算一下:

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

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

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

8位數乘法

8位數乘法就不展開了, 直接套用4位數乘法得出的結論, 其運算次數為:

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

原來的長乘需要幾次呢? 2?(8?8)+2?8=1442*(8*8) + 2*8=1442?(8?8)+2?8=144次.

是不是有一種動態規劃, 分而治之的感覺? 可以利用函數遞歸來實現.

問題

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

算法比較

為了比較兩個算法的運算次數, 讓我們忽略運算的低次冪以及常數項, 則(以下 n 為2的冪):

長乘

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?

分別進行計算:

2的冪/數字位數長乘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

可以看出來, 當數字的位數越大, 則兩個算法之間的差距越明顯.


有沒有被顛覆的感覺? 是不是自己知道了20多年的乘法運算, 根本沒有想到還有其他計算乘法的運算規則? 我也沒想到, 漲見識了…

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

總結

以上是生活随笔為你收集整理的长整数的乘法运算的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。