1. 程式人生 > >大數除法之估商法

大數除法之估商法

我用VB完整的實現了估商法,支援正負,小數,科學計數法,之所以說完整實現,是因為這個程式是我寫的(落葉高精度表示式計算機)的子程式,能夠和其它計算程式配合,實現高精度加減乘除,階乘,乘方,開N次方,函式等混合運算.
例:能夠執行萬位精度,開10000次方根正確運算,開N次方根是用的迭代法,為什麼舉這個例子,因為參入運算的子程式如果有問題,是計算不出正確結果的,現在這個計算機已完善:

另外我再談談我對除法的一些看法,不能利用計算硬體的演算法不是好演算法,所以設計演算法時要充分考慮硬體的效能,這裡可以理解為大進位制數比小進位制數效率更高,當然這個進位制的基數不要超過cpu位長的二分之一,例萬進位制要比十進位制數運算更快。例:採用百進位制時,12*34需要一次乘法運算,而採用十進位制時需要4次乘法運算。

簡單說一下我知道的一些大數除法演算法,

第一:用減法實現,從高位向低位減,我最早用的是這個方法並實現,該方法效率低下;

第二:試商法,針對十進位制數,從0-9試商,或按二分法試商,效率稍高,試商法也是一個效率低下的方法;

第三:是一個論文上說的方法,用的是十進位制,儲存除數和1-9相乘的得數,其它步驟和估商法差不多,這個方法因為預算了除數和商的值,省除了後面的乘法重複運算,但當採用萬進位制等大進位制數時,這個方法不適用;

第四:估商法(不是試商,試商非常慢),整理除數,利用被除數和除數的前幾位估出一個不小於正確商的數,做乘法,再大數減,判斷是否發生借位(不是用cpu的借位標誌判斷),若產生借位,商減一,餘數加一次除數

,判斷餘數和除數的大小,進入相應的步驟....,速度還滿意;

第五:迭代法,對於大長度數運算超快!

這裡我先講一講我的估商演算法,我所採用的數使用萬進製表示,我的估商演算法單就估商環節已經比較完美了。估商法的基本實現原理就是模擬我們常用的筆算除法,在採用大進位制數進行運算時,估商的準確度決定了這個演算法的效率。

(提高精度的基本原則: 
  一般的,對於乘法和除法。如果希望結果精確到n位元,兩個源運算元至少包含n位元資料。所以,為了估商準確,我們總是儘可能讓更多的位元參與運算。)這段話是一個高手對外國文獻的解析,可以作為如何提高估商精確度和高精運算的理論指導。

下面是我從另一個角度敘估商的原理:

第一步:除數整理,就是把除數乘以一個數(1-9),使這個除數儘量接近你所採用的進位制的最大值,2^32進位制時,就是65535,萬進位制就是10000

Knuth(高德納)對估商做出了一個數學推導,公式一大堆,一句話,就是左移除數,乘2乘2...,例:0011 0101 左移成1101 0100,當時硬體差,他以左移替代乘法,估商誤差平均2次中誤差1次,這種演算法最佳實現是一次單精對多精乘法,一次多精減法,50%錯誤修正(具體怎麼修正,各有各的演算法,我的演算法是商減一,餘數加一次除數);總的思路就是整理除數。

我在推算估商演算法時也發現了類似方法(當時沒查到上面所述資料),我的方法也是整理除數,但我是以萬進製為基作調整,

舉例:萬進位制時:下面的例子中因被除數第一位小於除數第一位,合併被除數第一位和第二位,整除除數第一位估商,如下:
0999 5678 1000/1000 9999 ,估商9995,正確商為9985,把被除數,除數乘9,8996 1102 9000/9008 9991,估商9986,另外被除數變了有沒有影響,但綜合下來影響很小,經測試除數整理好後,估商誤差比Knuth(高德納)的方法小,我也是不明白,老K的主思路和我一樣,為什麼誤差要大些,最後發現原因就在於左移,只有乘2,乘4,乘8,除數沒有調整到最佳狀態,為什麼這麼說呢?
如果一個除數需要調整,乘以3最合適,按老K的演算法你就只能乘2了,或乘4了。我覺得老K的左移操作對用資料頭表示的高精度數沒多大用處,向這種左移右移的操作,在資料頭裡把指數改一下就可以了,如萬進位制:1234*0100,只需要把1234的指數位加2就行了
詳細說一下我的除數整理演算法:
0999 5678 1000/0010 0099,除數乘100(不是真乘,只是調整數的位長度,和小數點位置),jw=2(這個用於後面調整小數位),變成0999 5678 1000/1000 9900,用(1000 9900)*1-9

從小向大試,找出一個最大的數,使它倆的積不超過100000000,這裡是9,把被除數,除數乘9,好吧,除數整理已完成,進入主程式。

第二步:估商演算法,

有一個估商演算法用被除數的前三個進位制位(這裡假設萬進位制時:一個進位制位為四位)除以除數的前兩個進位制位估商,估商精度要高於Knuth(高納德)的演算法,不過32位機存不下三個進位制位,要單獨處理,我放棄了,後來我又重新思考這個問題,得出如下結論:估商時並不一定要用三個進位制位,估四位商時,參入估商的除數位大於四位時,可以大大增加正確率,

下面這個是我的估商原始碼: 
方法一:ysjg(i) = yShu(2) \ b(2)        ‘ysjg(i)存放估出的商, yShu(2)存放被除數的前8位, b(2) 存放優化過的除數前四位,估商誤差小於50%,只是粗略估計,沒有數學論證;
這個是我借鑑上述結論後改進的程式碼:
方法二:ysjg(i) = (yShu(2) * 10 + yShu(3) \ 1000) \ (b(2) * 10 + b(3) \ 1000),現在估商誤差5.2%,每計算出2500(相當於一萬位)個萬進製得數,估商錯誤修正函式執行130次左右(商減一修正),上式實際上是9個十進位制位除以5個十進位制位獲得4個十進位制位的商。

現在估商誤差已經很小,甚至可以忽略不計

估商的誤差主要是除數第二個進位制位的進位造成的,當第二個進位制位全部為零時,估商準確率接近百分之百,例:22220000,因為是進位造成的誤差,所以我們用整除方式估商時,錯誤的商只會大於正確商。