首 页 | 新 闻 | 技术中心 | 第二书店 | 《程序员》 | 《开发高手》 | 社 区 | 黄 页 | 人 才
移 动专 题SUNIBM微 软微 创精 华Donews人 邮
我的技术中心 
我的分类 我的文档
全部文章 发表文章
专栏管理 使用说明



 RSS 订阅 
最新文档列表
Windows/.NET
.NET  (rss)    
Visual C++  (rss)    
Delphi  (rss)    
Visual Basic  (rss)    
ASP  (rss)    
JavaScript  (rss)    
Java/Linux
Java  (rss)    
Perl  (rss)    
综合
其他开发语言  (rss)    
文件格式  (rss)    
企业开发
游戏开发  (rss)    
网站制作技术  (rss)    
数据库
数据库开发  (rss)    
软件工程
其他  (rss)    

积极原创作者 
goodboy1881 (13)
wangchinaking (58)
iiprogram (67)
fancyhf (1)
harrymeng (41)
yjz0065 (113)
coofucoo (105)
Drate (69)
lphpc (30)
smallnest (61)
CSDN - 文档中心 - Visual Basic 阅读:11661   评论: 2    参与评论
标题   大数阶乘的计算(五)     选择自 northwolves 的 Blog
关键字   数组 阶乘
出处  

很难想象只要改动几句代码就可以大幅提高执行的效率,在前几篇文章中我写了几种大数阶乘的算法(http://www.csdn.net/Develop/read_article.asp?id=28306http://www.csdn.net/Develop/read_article.asp?id=28308http://www.csdn.net/Develop/read_article.asp?id=28432),效率都比较低。今日看了homezj(http://www.csdn.net/Develop/article/28/28584.shtm )的代码,很受启发,优化如下:

 

<一>按每四位进行一次计算:

Sub calcfactorial(ByVal num As Long, Optional ByRef factorial As String)

Dim numlen As Long, last As Long, i As Long, j As Long, temp As Long

Dim result() As Long, s() As String, stime As Double
numlen = 1
stime = Timer
ReDim result(1 To numlen)
result(1) = 1
i = 0
Do While i < num
i = i + 1
   last = 0
   For j = 1 To numlen
        temp = result(j) * i + last
        result(j) = temp Mod 10000
        last = temp \ 10000
   Next
   Do While Not last = 0
           ReDim Preserve result(1 To numlen + 1)
            result(numlen + 1) = last Mod 10000
            last = last \ 10000
           numlen = UBound(result)
  Loop
Loop
ReDim s(1 To numlen)
For i = 2 To numlen
s(i) = Format(result(numlen + 1 - i), "0000")
Next
s(1) = result(numlen)

factorial = Join(s, "")
Debug.Print num & "! : 用时 "; Timer - stime & " 秒, 结果 " & Len(factorial) & " 位,前5位为 " & Left(factorial, 5)
'Debug.Print factorial
Erase s
Erase result
End Sub

Private Sub Command1_Click()
For i = 1 To 20
calcfactorial i * 1000
Next
End Sub

输出结果:
'1000! : 用时 7.82500000059372E-02 秒, 结果 2568 位,前5位为 40238
'2000! : 用时 .391499999997905 秒, 结果 5736 位,前5位为 33162
'3000! : 用时 .968875000005937 秒, 结果 9131 位,前5位为 41493
'4000! : 用时 1.78174999999464 秒, 结果 12674 位,前5位为 18288
'5000! : 用时 2.84412500000326 秒, 结果 16326 位,前5位为 42285
'6000! : 用时 4.20387500000652 秒, 结果 20066 位,前5位为 26839
'7000! : 用时 5.84387500000594 秒, 结果 23878 位,前5位为 88420
'8000! : 用时 7.75012500000594 秒, 结果 27753 位,前5位为 51841
'9000! : 用时 9.98512500000652 秒, 结果 31682 位,前5位为 80995
'10000! : 用时 12.5160000000033 秒, 结果 35660 位,前5位为 28462
'11000! : 用时 15.2818750000006 秒, 结果 39681 位,前5位为 31624
'12000! : 用时 18.4063750000059 秒, 结果 43742 位,前5位为 12018
'13000! : 用时 21.7975000000006 秒, 结果 47838 位,前5位为 77871
'14000! : 用时 25.5320000000065 秒, 结果 51969 位,前5位为 13864
'15000! : 用时 29.5627499999973 秒, 结果 56130 位,前5位为 27465
'16000! : 用时 33.90625 秒, 结果 60320 位,前5位为 51187
'17000! : 用时 38.5786249999946 秒, 结果 64538 位,前5位为 13797
'18000! : 用时 43.5477499999979 秒, 结果 68781 位,前5位为 13525
'19000! : 用时 48.84375 秒, 结果 73048 位,前5位为 18269
'20000! : 用时 54.4375 秒, 结果 77338 位,前5位为 18192

 

<二>按每五位进行一次计算:

Sub calcfactorial(ByVal num As Long, Optional ByRef factorial As String)

Dim numlen As Long, last As Long, i As Long, j As Long, temp As Long

Dim result() As Long, s() As String, stime As Double

numlen = 1
stime = Timer
ReDim result(1 To numlen)
result(1) = 1
i = 0
Do While i < num
i = i + 1
   last = 0
   For j = 1 To numlen
        temp = result(j) * i + last
        result(j) = temp Mod 100000
        last = temp \ 100000
   Next
   Do While Not last = 0
           ReDim Preserve result(1 To numlen + 1)
            result(numlen + 1) = last Mod 100000
            last = last \ 100000
           numlen = UBound(result)
  Loop
Loop
ReDim s(1 To numlen)
For i = 2 To numlen
s(i) = Format(result(numlen + 1 - i), "00000")
Next
s(1) = result(numlen)

factorial = Join(s, "")
Debug.Print num & "! : 用时 "; Timer - stime & " 秒, 结果 " & Len(factorial) & " 位,前5位为 " & Left(factorial, 5)
'Debug.Print factorial
Erase s
Erase result
End Sub

Private Sub Command1_Click()
For i = 1 To 20
calcfactorial i * 1000
Next
End Sub

输出结果:

1000! : 用时 6.26250000059372E-02 秒, 结果 2568 位,前5位为 40238
2000! : 用时 .297124999997322 秒, 结果 5736 位,前5位为 33162
3000! : 用时 .782000000006519 秒, 结果 9131 位,前5位为 41493
4000! : 用时 1.421875 秒, 结果 12674 位,前5位为 18288
5000! : 用时 2.26612499999464 秒, 结果 16326 位,前5位为 42285
6000! : 用时 3.79700000000594 秒, 结果 20066 位,前5位为 26839
7000! : 用时 4.65625 秒, 结果 23878 位,前5位为 88420
8000! : 用时 6.21899999999732 秒, 结果 27753 位,前5位为 51841
9000! : 用时 8.375 秒, 结果 31682 位,前5位为 80995
10000! : 用时 9.98512500000652 秒, 结果 35660 位,前5位为 28462
11000! : 用时 12.2351250000065 秒, 结果 39681 位,前5位为 31624
12000! : 用时 14.6882500000065 秒, 结果 43742 位,前5位为 12018
13000! : 用时 17.4696249999979 秒, 结果 47838 位,前5位为 77871
14000! : 用时 20.4071249999979 秒, 结果 51969 位,前5位为 13864
15000! : 用时 23.625 秒, 结果 56130 位,前5位为 27465
16000! : 用时 27.0783749999973 秒, 结果 60320 位,前5位为 51187
17000! : 用时 30.875 秒, 结果 64538 位,前5位为 13797
18000! : 用时 34.8131250000006 秒, 结果 68781 位,前5位为 13525
19000! : 用时 39.0320000000065 秒, 结果 73048 位,前5位为 18269
20000! : 用时 43.5783749999973 秒, 结果 77338 位,前5位为 18192

 

可以看出,按五位五位的进行计算效率较高。但有一点必须明确,末尾多个“0”参与运算浪费了时间和内存,所以缩短运行时间仍有相当大的空间。


相关文章
对该文的评论
shines ( 2004-06-07)
提升的空间依然很大

你们采用的result都是long的数组,其实可以采用integer,base10000,因为内存块小了,可以对L1, L2Cache要求稍低一些,但由于VB的原因不一样会效率高

如果要使用long数组,就该考虑base1000000000,即一次计算9位,但是由于VB没有处理64位数据的能力,所以。。。只能换VC了,本来嵌入汇编也可以实现,可是VB也不行

位数的0可以在计算的过程中累计出来,然后后面的0跳过不计算
另外,N!的位数(10进制)也是可以通过公式计算出来的:
log(2*pi)*0.5+log(n)*0.5 + n*log(n)-n*log(e)),
这里pi=3.14159265358979,e=2.71828182845904523536028747135266
homezj ( 2004-06-05)
哈哈!想到一起去了,正好看到我们两个贴的代码同时出现。重名了!我的算法与你这个几乎一样,唯一不同之处,在于为防溢出,我对数组每个元素的所取位数是动态的,我试过,你采用的4位或5位法都有溢出的问题,取5位时,在乘到21447时溢出,取4位,我没算,应该是在乘到21万多的时候会溢出,这是由Long型20亿上限决定的。
其实我现在对算法又做了些调整,但收效不大,应该还有更快的方法,因为用Windows计算器算10000!,用时不到1秒。