自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

看了就會的大整數(shù)乘法運算與分治算法

開發(fā) 前端 算法
在數(shù)據(jù)加密處理中有很多復(fù)雜的加密算法,這些加密算法往往會用到很多超大的整數(shù)運算。

[[352004]]

在數(shù)據(jù)加密處理中有很多復(fù)雜的加密算法,這些加密算法往往會用到很多超大的整數(shù)運算。不過,程序設(shè)計語言對數(shù)據(jù)的大小會有一定的限制,數(shù)據(jù)太大就會出現(xiàn)數(shù)據(jù)溢出的情況,這是無法進行大整型數(shù)據(jù)運算的。本文將和大家一起學(xué)習(xí)如何實現(xiàn)大整數(shù)的數(shù)據(jù)運算,本文代碼我們使用C++實現(xiàn)。

普通乘數(shù)運算

對于乘數(shù)運算有一種比較簡單較為容易理解的方法,我們可以利用小學(xué)時期學(xué)的列豎式的計算方法進行乘法運算。

列豎式乘法運算

參考上圖中的列豎式計算方法,我們進行代碼實現(xiàn)。

  1. #include <iostream> 
  2. #include <string> 
  3. #include <stdlib.h> 
  4. #include <vector> 
  5. #include <cstring> 
  6. #include <algorithm> 
  7.  
  8. std::string multiply(std::string a, std::string b) 
  9.     std::string result = ""
  10.     int row = b.size(); 
  11.     int col = a.size() + 1; 
  12.     int tmp[row][col]; 
  13.     memset(tmp,0, sizeof(int)*row*col); 
  14.      
  15.     reverse(a.begin(),a.end()); 
  16.     reverse(b.begin(),b.end()); 
  17.      
  18.     for(int i = 0; i < b.size(); i++) 
  19.     { 
  20.         for(int j = 0; j < a.size(); j++) 
  21.         { 
  22.             std::string bit_a = std::string(1, a.at(j)); 
  23.             std::string bit_b = std::string(1, b.at(i)); 
  24.              
  25.             tmp[i][j] += std::stoi(bit_a) * std::stoi(bit_b); 
  26.          
  27.             tmp[i][j+1] = tmp[i][j] / 10; 
  28.             tmp[i][j] %= 10; 
  29.  
  30.         } 
  31.  
  32.     } 
  33.  
  34.     int N =  a.size() + b.size(); 
  35.     int sum[N]; 
  36.     memset(sum, 0, sizeof(int)*N); 
  37.      
  38.     for(int n = 0; n < N; n++) 
  39.     { 
  40.         int i = 0; 
  41.         int j = n; 
  42.          
  43.         while (i <= n && j >= 0 ) 
  44.         { 
  45.             if(i < row && j < col) 
  46.             { 
  47.                 sum[n] += tmp[i][j]; 
  48.             } 
  49.              
  50.             i++; 
  51.             j--; 
  52.         } 
  53.  
  54.         if( n+1 < N ) 
  55.         { 
  56.             sum[n+1] = sum[n] / 10; 
  57.             sum[n] %= 10; 
  58.         } 
  59.  
  60.     } 
  61.  
  62.     bool zeroStartFlag = true
  63.     for (int i = N-1; i >= 0; i--) 
  64.     { 
  65.         if(sum[i]==0 && zeroStartFlag) 
  66.         { 
  67.             continue
  68.         } 
  69.          
  70.         zeroStartFlag = false
  71.         result.append(std::to_string(sum[i])); 
  72.     } 
  73.      
  74.     return result; 
  75.  
  76.  
  77. int main() 
  78.     std::string a = "3456"
  79.     std::string b = "1234"
  80.  
  81.     std::string result = multiply(a, b);     
  82.     std::cout << a << " * " << b << " = " << result <<std::endl; 
  83.      
  84.     return 0; 

為了方便我們先將各個乘數(shù)做了翻轉(zhuǎn)處理,最后需要再將結(jié)果翻轉(zhuǎn)回來。在運算過程中用來存放乘法運算結(jié)果的數(shù)組,我們沒有進行移位處理同列相加,而是對角線相加,這樣可以減少空間和運算步驟。上面的代碼運行結(jié)果如下所示。

運行結(jié)果

因為字符串的長度沒有特別的限制,所以上面的算法可以適用大整數(shù)運算。

分治算法

雖然上面的列豎式的方法可以很好的解決大整數(shù)乘法的問題,但是我們還用一種更加高效的方法可以選擇,這就是分治(Divide and Conquer)算法。它是一種非常重要的算法,可以應(yīng)用到很多領(lǐng)域,比如快速排序,二分搜索等。從算法的名字我們可以看出它是將大的問題拆分進行細化,由大變小,先將小的問題解決,最終將這個問題解決,所以叫Divide and Conquer。在這里我們可以通過這種方法將大整數(shù)進行拆分,拆分成一個個可以通過程序語言直接進行運算的小整進行計算,最后求得到大整數(shù)的值。

假設(shè)有兩個大整數(shù),我們設(shè)為a(大小為n位)和b(大小為m位),這里我們將使用二分法對數(shù)據(jù)進行拆分,這兩個整數(shù)我們可以分解為:

則,

令,

根據(jù)上面公式里,我們可以將a*b分解為四個小的整數(shù)的乘法,即z3,z2,z1,z0四個表達式。如果分解出來的乘法數(shù)值還是很大,還可以按照同樣的方法進行拆解直到拆解成較小的數(shù)值乘法,直到計算機程序語言可以直接運算。

比如,上面的3456和1234相乘,參考下圖通過二分法逐級對整數(shù)進行拆分,我們將兩個整數(shù)拆分到一位整數(shù)進行運算。

3456和1234拆分步驟圖

下面我們看一下分治算法的代碼實現(xiàn),這里我們使用遞歸的方法。

  1. #include <iostream> 
  2. #include <string> 
  3. #include <stdlib.h> 
  4. #include <vector> 
  5. #include <cstring> 
  6. #include <algorithm> 
  7. #include <cmath> 
  8.  
  9. std::string add(std::string a, std::string b) 
  10.     int N = std::max(a.size(), b.size()); 
  11.     int sum[N]; 
  12.     memset(sum, 0, sizeof(int)*N); 
  13.      
  14.     reverse(a.begin(),a.end()); 
  15.     reverse(b.begin(),b.end()); 
  16.  
  17.     for(int i = 0; i< N; i++) 
  18.     { 
  19.         int bit_a = 0; 
  20.         int bit_b = 0; 
  21.         if(i < a.size()) bit_a = std::stoi(std::string(1, a.at(i))); 
  22.         if(i < b.size()) bit_b = std::stoi(std::string(1, b.at(i))); 
  23.  
  24.         sum[i] += (bit_a + bit_b); 
  25.  
  26.         if(i < N-1 && sum[i]>9) 
  27.         { 
  28.             sum[i+1] = sum[i] / 10; 
  29.             sum[i] %=10; 
  30.         } 
  31.     } 
  32.  
  33.     std::string result=""
  34.     bool zeroStartFlag = true
  35.     for (int i = N-1; i >= 0; i--) 
  36.     { 
  37.         if(sum[i]==0 && zeroStartFlag) 
  38.         { 
  39.             continue
  40.         } 
  41.          
  42.         zeroStartFlag = false
  43.         result.append(std::to_string(sum[i])); 
  44.     } 
  45.  
  46.  
  47.     return result; 
  48.  
  49. std::string divideAndConquer(std::string a, std::string b) 
  50.     if( a.size() < 2 && b.size() < 2)  
  51.     { 
  52.         return std::to_string(std::stoi(a) * std::stoi(b)); 
  53.     } 
  54.      
  55.     int n = a.size(); 
  56.     int m = b.size(); 
  57.      
  58.     int halfN = n/2; 
  59.     int halfM = m/2; 
  60.  
  61.     std::string a0 = "0"
  62.     std::string a1 = "0"
  63.     if(a.size() > halfN && halfN > 0) 
  64.     { 
  65.         a1 = a.substr(0, halfN); 
  66.         a0 = a.substr(halfN, a.size() - halfN); 
  67.     } 
  68.     else 
  69.     { 
  70.         a1 = "0"
  71.         a0 = a; 
  72.     } 
  73.      
  74.     std::string b0 = "0"
  75.     std::string b1 = "0"
  76.     if(b.size() > halfM && halfM > 0) 
  77.     { 
  78.         b1 = b.substr(0, halfM); 
  79.         b0 = b.substr(halfM, b.size() - halfM); 
  80.  
  81.     } 
  82.     else 
  83.     { 
  84.         b1 = "0"
  85.         b0 = b; 
  86.     } 
  87.  
  88.     std::string a1b1 = divideAndConquer(a1, b1); 
  89.     std::string a0b0 = divideAndConquer(a0, b0); 
  90.     std::string a1b0 = divideAndConquer(a1, b0); 
  91.     std::string a0b1 = divideAndConquer(a0, b1); 
  92.      
  93.     a1b1.append((n - halfN) + (m - halfM), '0'); 
  94.     a1b0.append(n - halfN, '0'); 
  95.     a0b1.append(m - halfM, '0'); 
  96.  
  97.     std::string result = ""
  98.     result = add(a1b1, a1b0); 
  99.     result = add(result, a0b1); 
  100.     result = add(result, a0b0); 
  101.  
  102.     return result; 
  103.  
  104. int main() 
  105.     std::string a = "3456"
  106.     std::string b = "1234"
  107.  
  108.     std::cout << a << " * " << b << " = " << divideAndConquer(a, b) << std::endl;  
  109.  
  110.     return 0; 

程序的運行結(jié)果如下:

分治算法運行結(jié)果

本文轉(zhuǎn)載自微信公眾號「Will的大食堂」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系Will的大食堂公眾號。

 

責任編輯:武曉燕 來源: Will的大食堂
相關(guān)推薦

2022-07-12 08:27:18

Zadig開源

2021-04-19 11:40:15

瀏覽器路徑

2020-06-05 18:09:14

TomcatWeb應(yīng)用服務(wù)器

2021-05-12 09:07:09

Java數(shù)據(jù)結(jié)構(gòu)算法

2023-01-08 23:06:14

css3d變換

2020-10-20 08:14:08

算法與數(shù)據(jù)結(jié)構(gòu)

2020-12-02 09:36:20

算法分支思想

2021-03-24 15:10:11

算法科學(xué)技術(shù)

2019-05-28 14:33:07

Javascript運算符前端

2024-03-11 12:21:07

模型數(shù)據(jù)

2020-11-09 10:01:29

Python乘法位運算

2024-12-30 00:01:00

多模態(tài)大模型Python

2021-07-16 10:46:52

PythonNumpy數(shù)據(jù)溢出

2017-09-18 09:26:51

PHP代碼大整數(shù)

2011-06-08 17:45:54

AOFAX傳真機

2024-10-22 15:41:47

NumPyPython

2020-08-12 07:59:15

Long類型

2020-09-15 12:40:16

回溯算法代碼回溯法

2022-08-28 20:50:29

算法模型機器學(xué)習(xí)
點贊
收藏

51CTO技術(shù)棧公眾號