写了个算大数阶乘和四则运算的程序,运行效率真是大问题啊(如"2005!")。 有朋友曾经写过吗?

knock 2005-03-20 08:41:56
加减乘除运算的速度还是特别快,算起“1000!”及以下的只要几秒钟,可当我算“2005!”时却出问题了。 原来用加法来算“2005!”的,占用内存特别少,最多的时候也才占用1M多点,可这样算效率特低,竟然弄了3个多小时!
后来改进了一下程序,用乘法来算,可这时候出了占用内存直线上升的问题,大概算到500的时候(我从2005往下算的),跳出“虚拟内存不足”,就结束程序了。
我怀疑是VC环境在作怪,就不在VC环境中运行程序,可还是这样,后来改成RELEASE方式生成的程序就告别了这个对话框,算“2005!”用了29秒,内存只占用整个内存的一半左右。 但我想我的程序中用到的空间绝对没有这么多啊! 请知道的兄弟指教指教!!
我的机器配置:Duron 850, SD128MB, win2000
...全文
305 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
languagec 2005-03-21
  • 打赏
  • 举报
回复
QunKangLi 2005-03-21
  • 打赏
  • 举报
回复
俺以前看过一个算法,速度还算将就吧:
# include<stdio.h>
# include <stdlib.h>
// 计算
# define N 1000
int cal(unsigned int *s,int n)
{

unsigned long p; // p是对每一位乘法中的值加上进位,如34*5,4*5是20,3*5的加上进位2是17
unsigned long k=0; // k是一次乘法中的进位,如10进制乘法中,34*5,4*5的进位是2,3*5的进位是1
int i;
static int m=1; // m是位数,表示s有总共有多少位数字,注意:是1000进制
static int b=0;
/* b用来记录后面的0,比如213,000,000,000,则b=3,后面的3个000不必再参与计算了 */
//
for(i=b;i<m;i++)
{
p=(long)s[i]*(long)n+k;
k=p/N;
s[i]=p-k*N;
}
// b是低位乘出来的000的数目,增加后加1
while(!s[b])
b++;
// 最高位的进位处理
for(k=p/N;k;)
{
p=k;
k=p/N;
s[i++]=p-k*N;
m++; // 进一次m加一次
}
return m;
}

void main()
{
/* s是用来存计算结果的,以N为进位,这里N=1000,如s[0]=1,s[1]=21,s[2]=213,s[3]以上都为0,
则结果是:213,021,001
*/
unsigned int *s;
int i;
int m; // m是位数,表示s有总共有多少位数字,注意:是1000进制
int n; /* 求n! (0<n<10000)*/
printf( "输入一个整数(0-10000):" );
scanf("%d",&n); // 输入n的值
s=(unsigned int *)malloc(n*sizeof(s)*10); // 数组开足够大,其实要不了这么大
// 附初值,S=1,即s[0]=1,以上都为0
for(i=1;i<n;i++)
s[i]=0;
s[0]=1;

// 循环,s乘以2、3、4,……,n
for(i=2;i<=n;i++)
m=cal(s,i);
// 输出:n!=
printf("\n%d!=",n);
m=n-1;

// 滤掉前面的0,前面说了,其实
while(!s[m])
m--;
// 输出第一位
printf("%d",s[m--]);
// 输出后面的位数
for(i=m;i>=0;i--)
printf(",%03d",s[i]);
printf("\n");
// 释放内存空间
free(s);
}
GeminiXXXCC 2005-03-21
  • 打赏
  • 举报
回复
哇赛!
原来算东西还这么有学问!!!
都怪我做控制太多,一般都是发些指令,逻辑对就行。
对算法是一点没感觉了。
郁闷。
chogo 2005-03-20
  • 打赏
  • 举报
回复
// 3000!.cpp : 定义控制台应用程序的入口点。
// 语言版本:VC++.NET(7.0)

#include "stdafx.h"
#include <fstream>
#include <sys/timeb.h>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
timeb start_time, end_time;
long last_time;
ftime(&start_time);
int a[9200],digit=1;
for(int n=0;++n<9200;)a[n]=0;
for(int i=0;++i<=3000;)
{
a[0]*=i;
for(int j=0;++j<=digit;)
{
a[j]=a[j]*i+a[j-1]/10;
a[j-1]%=10;
if(a[digit]>9)digit++;
}
}
ofstream outfile("3000!.txt");
outfile<<"3000!=";
for(int n=digit-1;--n>=0;)outfile<<a[n];
ftime(&end_time);
last_time = (end_time.time - start_time.time)*1000 + (end_time.millitm - start_time.millitm);
cout<<"运行时间:"<<last_time<<"毫秒"<<endl;
outfile.close();
system("pause");
return 0;
}

以前写的一个程序,运行时间780多毫秒
nodummy 2005-03-20
  • 打赏
  • 举报
回复
分治不是最终解决方法……
pcboyxhy 2005-03-20
  • 打赏
  • 举报
回复
大数乘法可以通过分治提高效率的。

以二进制为例。
假设XY都是n位的二进制整数。
将他们都分为2段,AB, CD

XY = AC*2^n + (AD+CB)*2^(n/2) + BD
XY = AC*2^n +((A-B)(D-C) + AC + BD)*2^(n/2) + BD

时间复杂度可以从O(n*n)降到 O(n^1.6)

10进制的也是类似的。
nodummy 2005-03-20
  • 打赏
  • 举报
回复
回复人: idcsdn(飞沙走石) ( ) 信誉:100 2005-03-20 21:10:00 得分: 0


pcboyxhy(-273.15℃) 的确很快,能不能分析一下,本人另开问题给分。


======================================================
那个东西只能用来做阶乘,而你做的是大数乘法,不是一个东西……要想写高效的大数乘法看离散数学去……

pcboyxhy的代码算不了10^20*10^20这样的东西,但是你的可以……
redleaves 2005-03-20
  • 打赏
  • 举报
回复
楼主的程序的确太慢了......
大数运算的算法的问题已经出现过无数次了,楼主还是去查一查吧.第一次出现的时候我就给出的10000进制的实现方式,就是楼上pcboyxhy(-273.15℃)的那个算法.当时自以为很快了,后来经有位数学高人改进快了很多.
我的算法算10000的阶乘在P4 1.7上要1.7s,他改进的算法只要0.015s....当然,所有的算法最基本的目标就是渐少不必要的运算,加大每一次的运算效果.
idcsdn 2005-03-20
  • 打赏
  • 举报
回复
pcboyxhy(-273.15℃) 的确很快,能不能分析一下,本人另开问题给分。
nodummy 2005-03-20
  • 打赏
  • 举报
回复
乘法运算的时间(CPU里面的数学乘法)是常数,所以一个数组单个元素里面存贮的数值越大,运算速度越快,我当时实现的时候用的是每个int存贮1位,而楼上的是4位,所以快很多(不做算法分析了,麻烦……)
pcboyxhy 2005-03-20
  • 打赏
  • 举报
回复
#include <memory.h>
#include <stdlib.h>
#include <stdio.h>

int main( int argc, char * argv[] )
{
int n, i, j, len, g, t, zero;
unsigned int *a=0;
a=new unsigned int[10000];
if(!a)
return 0;
while(1)
{
memset(a, 0, 40000); a[0]=1; len=1;
system("CLS"); zero=0;
printf("Input the n. -1 to exit.\n");
scanf("%d", &n);
if(n==-1) return 0;
printf("\n");
for(i=2; i<=n; i++)
{
g=0;
for(j=zero; j<len; j++)
{
t=a[j]*i+g;
g=t/10000;
t=t%10000;
a[j]=t;
if((!t)&&(j-zero==1)) ++zero;
}
while(g)
{
a[len++]=g%10000;
g/=10000;
}
}
while(!a[len]) len--;
printf("%d", a[len--]);
while(len>=0) printf("%04d", a[len--]);
system("PAUSE");
}
delete [ ]a;
return 0;
}

算10000用2s p4 2.4
knock 2005-03-20
  • 打赏
  • 举报
回复
我是用链表写的,虽然乘法方面还有些地方可以改进,但毕竟效率不会太明显。
knock 2005-03-20
  • 打赏
  • 举报
回复
怎么样才高效呢?
knock 2005-03-20
  • 打赏
  • 举报
回复
执行的结果:
hello
59888069087090039102082014300000000
8800999999979030010991105700000000
877280804495109665811895115161277147611026659759208000000000000000000
1
Now process : 900
Now process : 800
Now process : 700
Now process : 600
Now process : 500
Now process : 400
Now process : 300
Now process : 200
Now process : 100
Length: 2568
40238726007709377354370243392300398571937486421071463254379991042993851239862902
05920442084869694048004799886101971960586316668729948085589013238296699445909974
24504087073759918823627727188732519779505950995276120874975462497043601418278094
64649629105639388743788648733711918104582578364784997701247663288983595573543251
31853239584630755574091142624174743493475534286465766116677973966688202912073791
43853719588249808126867838374559731746136085379534524221586593201928090878297308
43139284440328123155861103697680135730421616874760967587134831202547858932076716
91324484262361314125087802080002616831510273418279777047846358681701643650241536
91398281264810213092761244896359928705114964975419909342221566832572080821333186
11681155361583654698404670897560290095053761647584772842188967964624494516076535
34081989013854424879849599533191017233555566021394503997362807501378376153071277
61926849034352625200015888535147331611702103968175921510907788019393178114194545
25722386554146106289218796022383897147608850627686296714667469756291123408243920
81601537808898939645182632436716167621791689097799119037540312746222899880051954
44414282012187361745992642956581746628302955570299024324153181617210465832036786
90611726015878352075151628422554026517048330422614397428693306169089796848259012
54583271682264580665267699586526822728070757813918581788896522081643483448259932
66043367660176999612831860788386150279465955131156552036093988180612138558600301
43569452722420634463179746059468257310379008402443243846565724501440282188525247
09351906209290231364932734975655139587205596542287497740114133469627154228458623
77387538230483865688976461927383814900140767310446640259899490222221765904339901
88601856652648506179970235619389701786004081188972991831102117122984590164192106
88843871218556461249607987229085192968193723886426148396573822911231250241866493
53143970137428531926649875337218940694281434118520158014123344828015051399694290
15348307764456909907315243327828826986460278986432113908350621709500259738986355
42771967428222487575867657523442202075736305694988250879689281627538488633969099
59826280956121450994871701244516461260379029309120889086942028510640182154399457
15680594187274899809425474217358240106367740459574178516082923013535808184009699
63725242305608559037006242712434169090041536901059339838357779394109700277534720
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000
any key to exit...
nodummy 2005-03-20
  • 打赏
  • 举报
回复
这样玩当然不行,效率当然低……

我以前写的一个算10000!的也只要31s(P4 2.8G),虽然也很低效……
nodummy 2005-03-20
  • 打赏
  • 举报
回复
不对,还要*4才行……
knock 2005-03-20
  • 打赏
  • 举报
回复
例如主程序是
void main()
{
cout<<"hello"<<endl;
big a;
char *p1="34344534543534534556536560000000000",
*p2="25543534543555504545545454300000000",
*p3="1000";
cout<<a.Add(p1, p2)<<endl;
cout<<a.Sub(p1, p2)<<endl;
cout<<a.Mul(p1, p2)<<endl;
cout<<a.Div(p1, p2)<<endl;
char *p;
p = a.Step(p3);
cout<<"Length: "<<strlen(p)<<endl;
cout<<p<<endl;

cout<<"any key to exit..."<<endl;
getch();
}
nodummy 2005-03-20
  • 打赏
  • 举报
回复
不会吧?10000的阶乘也就只要4*10000个字节不到的空间,你怎么写的?
zengwujun 2005-03-20
  • 打赏
  • 举报
回复
学习

64,641

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧