1. 程式人生 > >高精度加,減法演算法

高精度加,減法演算法

大數加,減法目前我所知道的演算法:

1)對於用子符串形式表示的數,可以直接相加,減,例:1 的ascii碼為49,2 的ascii碼為50,1+2的字串相加為49+50=99 ,再減去一次48等於51,51是3的ascii碼。

2)對於直接用數的值表示的數,可以直接相加減,也可以換算成大的進製表示形式進行運算,理論上大進製表示的數執行效率更高,如:1234+4567,當十進位制時要執行4次加法,萬進位制時只需一次加法,那麼我們進行大數加法時,有必要把十進位制轉換成萬進位制計算完後,再轉換回來,答案是沒必要,這樣做只會更慢,因為進位制轉換所需時間大大超過十進位制的直接加法運算,作為單次的大數加法運算,假如能直接相加(包括用子符串形式表式的數),那麼直接相加就是最快的演算法。

假如你要進行綜合運算,如sin(x)的高精運算,裡面有大量的加減乘除運算,一般情況為了更高的計算速度,常常採用大進製表示數,但大進位制數加,減計算時會出現指數難以對位的問題。

本篇文章主要也是討論網上查不到大數加減法中的指數或小數對位問題:

雖然理論上所有的有理數都可以化為整數進行計算,大數庫也只提供對整數的支援,但這個例子的整數演算法為:1.23E10*1.23E-10;化為整數為(12300000000*123)/10^12 = 1.5129

我的乘法因為直接對有理數操作運算,步驟是這樣的,先1.23*1.23= 1.5129;再指數位相加,10+(-10)=0,結果為1.5129E0,這種方法比化為整數再呼叫整數乘法子程式計算,效率更高,特別是這種(1.23E1000*1.23E-1000)數,更是相差巨大,這些都不是大問題,關鍵是通過呼叫大數整數子程式實現的有理數的大數支援,所需的呼叫前和呼叫後小數點或指數調整還是很複雜的,最難的是你需要很長的除錯驗證才能保證執行結果的正確性

這裡我講講我的有理數加法(減法原理是一致的)的兩種實現:

第一個方法是把數轉換為十進位制數,再把指數調整為相等,把兩數以小數點位置為中心向兩邊擴充對位,最後運算。

例:1.23456789+9.87654e3 轉換為:1.23456789e0+9876.54e0   記憶體擴充對位為:0001. 23456789+9876. 54000000,然後兩數從右向左加,得結果為:9877. 77456789

第二個方法是採用大進位制,這裡以千進位制數講一下我的具體演算法:這裡設定千進位制下的指數位為十進位制下的指數位,十進位制數9.87654e3換算成千進位制數為009.876 540e3,為什麼這麼設定,當時也是進行了綜合考慮,這樣更利於後面的指數對位計算和進位制轉換。

1.23456789+9.87654e4的千進製表示形式為:0.123 456 789e1+0.987 654e5(這裡實際應用時要採用純小數的表達形式0.xxx...10^n,

這裡也必須要指數對位後才能運算,這裡要用到兩個引數x=(5-1)\3 =1 ,y=(5-1) mod 3 =1'這裡的5是較大的數的指數,1是較小數的指數,3是千進位制時的基數,根據x的值把較小的數調整為0.000 123 456 789,再根據y的值把前一次調整後的值調整為0.000 012 345 678 900,此時把兩個運算元調整為等長,即:0.000 012 345 678 900+0.987 654 000 000 000,運算,運算後的結果的指數採用較大數的指數,最終結果為9.876663456789e4

其實上述方法中也可以根據x和y的值直接對兩數(沒有進行後續調整的兩數0.123 456 789e1+0.987 654e5)進行運算,程式碼更簡潔,速度有很小的下降,我目前就是採用的這種方法。

為什麼我對千進位制加法講了這麼多,因為綜合運算需要大進位制的有理數加法運算支援,剛開始我不知道大進位制下的指數如何對位,我只能把大進位制數換算成十進數後再相加,然後在轉換回大進位制數,大量的進位制轉換使綜合運算效率很低,最後得到一個網友的幫助,對大進位制數採用純小數的表達形式才解決了千進位制加法的問題,然後才能使我的落葉高精度表示式計算器1.2版的速度獲得了很大的提升。