大數階乘的計算(五)

對計算(四)我總覺得沒有發揮Long類型的最大潛力,一定是我的算法還有改進餘地。經進一步推敲,終於又有了突破,速度一下子又提高 4 倍!同一臺機器上10000!用時9.8秒,而且大膽的算了一次20000!,啊,43秒搞定。現將代碼貼出,供大家參考,看還能不能再快了?

Private Function cacl(num As Long) As String
Dim numlen As Long, last As Long, x As Long
Dim i As Long, m As Long, n As Long, nl As Long, s0 As String
Dim result() As Long, starttime As Single, s() As String
numlen = 1
starttime = Timer
ReDim result(1 To numlen)
nl = 9 - Len(CStr(num))   '根據兩數相乘最大得數長度,不會超過兩數長度總和的原理,
                    '讓數組中每個元素長度與階乘數長度之和不能超過9,以防止溢出。
If nl < 1 Then nl = 1   '最小長度是1位,若真到了這麼大的數,恐怕沒人會去試了^-^
n = 10 ^ nl         '緩存用於分隔大數的被除數,數組中每個元素的長度是 nl,該數就是10的 nl 次方
result(1) = 1
x = 1
Do While x <= num
   last = 0
   For i = 1 To numlen
        m = result(i) * x + last    '數組中每個元素進行與待乘數相乘後,再加上上次進位數
        result(i) = m Mod n         '分隔大數
        last = m / n                '保存進位數並等待累計進下一個數組元素
   Next
   If last > 0 Then
        m = Len(CStr(last)) / nl + 1    '對超過數組元素上限的進位數要增加數組大小,並按長度nl分隔
        ReDim Preserve result(1 To numlen + m)
        For i = 1 To m
            result(numlen + i) = last Mod n
            last = last / n
        Next
        numlen = UBound(result)
   End If
   x = x + 1
Loop
ReDim s(1 To numlen)
s0 = String(nl, "0")    '對長度不足nl的數組元素要在前面補0,不然結果就在錯特錯了
For i = 1 To numlen
s(i) = Format(result(numlen + 1 - i), s0)   '格式化補 0 每個數組元素
Next
s(1) = Val(s(1))
If s(1) = 0 Then s(1) = ""                  '最高位要去掉0,雖對得數沒影響,但位數會錯。
cacl = Join(s, "")
Debug.Print num & "! : 用時 "; Timer - starttime & " 秒, 結果 " & Len(cacl) & " 位"
End Function

Private Sub Command1_Click()
Dim i As Long
'cacl 20000
For i = 1 To 9
cacl i * 100
Next
For i = 1 To 10
cacl i * 1000
Next
End Sub

計算結果:

100! : 用時 0 秒, 結果 158 位
200! : 用時 0 秒, 結果 375 位
300! : 用時 .015625 秒, 結果 615 位
400! : 用時 0 秒, 結果 869 位
500! : 用時 .015625 秒, 結果 1135 位
600! : 用時 .015625 秒, 結果 1409 位
700! : 用時 .03125 秒, 結果 1690 位
800! : 用時 .03125 秒, 結果 1977 位
900! : 用時 .0625 秒, 結果 2270 位
1000! : 用時 .078125 秒, 結果 2568 位
2000! : 用時 .3125 秒, 結果 5736 位
3000! : 用時 .75 秒, 結果 9131 位
4000! : 用時 1.390625 秒, 結果 12674 位
5000! : 用時 2.265625 秒, 結果 16326 位
6000! : 用時 3.3125 秒, 結果 20066 位
7000! : 用時 4.609375 秒, 結果 23878 位
8000! : 用時 6.125 秒, 結果 27753 位
9000! : 用時 7.9375 秒, 結果 31682 位
10000! : 用時 9.890625 秒, 結果 35660 位

這個算法有個缺陷:就是階乘數位數越大時,效率就越會成倍的下降,當要計算8位數的階乘時,就會降到與計算(四)等效了,最大階乘數仍是不能超過20億。不過那時字符串的長度可能也會因超長溢出的。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章