實現超大整數的方法

2021-05-23 06:24:36 字數 1643 閱讀 9435

前幾天做的產品測試,發現內建最大的整數值只有10的9次方,沒有實現超大整數的功能。現在海量計算和海量儲存應用越來越多,而且已經有很多人實現了超大整數的儲存和運算,調查了一些這方面的方法,根本上都是自定義乙個多位元組的資料結構,以便對程式語言的內建int型做擴充套件。自定義結構的方式儘管人人不同,但是本質上,都是選取某一種數學進製表示超大數,同時用鍊錶或者陣列的方式組織成大數的進製的位元。比如我們習慣的10進製,表示12345這個數時,其本質含義是

1×10^4+2×10^3+3×10^2+4×10^1+5×10^0

這裡,10即使進製,10的n次方表示該位權為n,而權左邊的係數就是位元,計算機中的16進製制也是同樣的道理。因此任意乙個10進製數ps,在進製s中,其位元為ai,則可以用公式表示為:

ps=a0s^0+a1s^1+a2s^2+...+an-1s^(n-1)

大數的實現原理就是設定乙個進製s,然後使用鍊錶或者陣列,從表頭開始每乙個元素表示s進製從低位到高位(或者相反)的各個權的位元。這就是大數的儲存方式。大數的各種,最基本的是四則運算,本質上也是我們小學學的方法,由低向高,相同權的位元對應著逐個計算。因此,僅從資料結構上考慮,大數的各種計算效能差異就取決與進製的選擇了。

通過調查,前人大數實現的方法主要有:

1、字串表示法:即乙個大數比如12345,就用字串"12345」方式儲存,這是10進製的,優點是表示簡單易於理解,但計算時總需要做字元到數字的對映,效率低且浪費空間。

2、10進製表示法,包括bcd編碼表示,計算機上每個位元組有16個儲存狀態,該方法只用其中0x00-0x09這10個狀態,用1個或者半個位元組表0-9,這樣最接近人的理解,且計算也不麻煩,效率上,在32位機中,每次運算需要把位元從乙個或者半個位元組轉成int型。並且顯而易見,儲存時有浪費。

3、10^n進製表示法,即用乙個或幾個位元組表示從0-10^n的數,這樣做的目的是提高效率並且節省空間,因為有時10進製大數可能是數百萬位的,節省空間很必要。如果用1個位元組表示0-9顯然浪費空間,半個位元組表示時每次計算又需要把位元組高四位處理,效率低。索性用100進製表示法,乙個位元組上表示0-99。也有人用2個位元組表示0-9999的位元,即10000進製。

4、2進製/16進製制,本質上是一樣的,只是在進製計算時的判斷值不同,這種方式理論上最省空間的,效率上來講,32位機中,每次應該充分利用其運算的有效範圍,如果每次用32位的空間操作幾個位元,必然會增加運算迴圈的次數。

綜上分析後,我打算採用65536進製表示大數,也就是16位的2進製全部使用,這樣位元的範圍就是0x00-0xffff。大數的所有運算只不過是分解成了32位機的小運算,所以不能再增大進製了,因為做乘法時,兩個位元相乘最大的結果應該小於unsigned int型的資料,65536進製時,乘法口訣的最大值是0xffff*0xffff,如果再增加進製量,必然會導致32位機的乘法溢位了。而每次計算兩個位元組,32位機中,型別轉換的代價也最小。

資料結構的儲存上,既然是65536進製,那麼比較適合用unsigned short int 陣列的方式,從低位向高位儲存,這也是與正常資料完全一樣的儲存方式。如果是乙個占用100位元組的大數,那麼該陣列正是這個數的2進製表示。

用陣列計算效率顯然也比鍊錶高的多,並且動態申請陣列的方法也比鍊錶每次單個申請空間更快。

大數應該實現基本的四則運算,+,-,/,都沒有什麼問題,對於乘法,目前最快的是傅利葉變換法,該方法的推導之後再談。用c++實現這些運算子的過載,也不是什麼難事。具體的思路就是這樣了。

超大整數相加

輸入 第乙個數字m代表接下來有幾組資料 接下來每一組資料報含兩個資料,數字很大哦 確保沒有字首0,資料很大 輸出輸出計算後的結果,每個結果佔一行 樣例輸入 3123 456 1234567890987654321 9876543210123456789 11111111111111111111111...

實現超大整數(超過long長度範圍)的加法運算

昨天筆試,遇到這麼乙個問題 如果系統要使用超大整數 超過long長度範圍 請你設計乙個資料結構來儲存這種超大型數字以及設計一種演算法來實現超大整數加法運算 其實這個問題很好解決,超大整數可以直接使用string來儲存。對於兩個string儲存的超大整數的相加,先比較二者長度,在短的那個前面補0,使兩...

php實現讀取超大檔案的方法

通常來說在php讀取大檔案的時候,我們採用的方法一般是一行行來講取,而不是一次性把檔案全部寫入記憶體中,這樣會導致php程式卡死,下面就給大家介紹這樣乙個例子。讀取大檔案最後幾行資料 取檔案最後 n行 param string filename 檔案路徑 param int n 最後幾行 retur...