我狂郁闷 1万的阶乘如何求?

PrOve 2005-03-21 05:07:49
一次开玩笑 想和朋友解决TC中如何求10000的阶乘问题
想了很久都没有结果
后来朋友提出一个想法 :用数组存放数字再参与直接运算
可是到具体落实到程序中时却还是无法克服数据范围小的障碍
现在请教各位高手指教 谢谢了!
...全文
2494 105 打赏 收藏 转发到动态 举报
写回复
用AI写文章
105 条回复
切换为时间正序
请发表友善的回复…
发表回复
无心人 2005-09-01
  • 打赏
  • 举报
回复
TC下,最好别用32位运算
在很早我们组织全国计算机等级考试的时候
曾经遇到过TC的某些数字运算错误

最低也要用Borland C++ 3.1
yangfasheng 2005-08-24
  • 打赏
  • 举报
回复
UP
aruo98 2005-08-23
  • 打赏
  • 举报
回复
up~
russule 2005-08-22
  • 打赏
  • 举报
回复
up
liangbch 2005-08-19
  • 打赏
  • 举报
回复
看了上面的程序,发现都不太理想。1是速度太慢。原因是大多数程序使用数组的1个元素表示1位数,也有的表示4位数据,没有充分发挥cpu的能力。2是程序太复杂。3.是预先定义或者分配一块固定大小的内存,当n较太大时,程序不能正常工作。
下面给出我的两个程序,它们用1个long表示9位10进制数,占用空间省,速度快。2个程序的区别是前者代码简练,后者用汇编优化,速度快了1倍以上。

程序1:
#include "stdio.h"
#include "windows.h"
#include "math.h"

#define RADIX 1000000000
#define PI 3.1415926535897932384626433832795
#define E 2.7182818284590452353602874713527
typedef unsigned long DWORD;
typedef unsigned __int64 UINT64;

DWORD rad=RADIX;

int calcResultLen(DWORD n) //use stirling to calc the length of n!
{
if (n<=1)
return 1;
return log10(2*PI*(double)n)/2 + n * log10((double)n/E)+1;
}

DWORD* calc( DWORD n, DWORD *pBuff,int buffLen)
{
DWORD *p; //lowest unit
DWORD *pEnd=pBuff+buffLen-1; //highest unit
UINT64 prod;
DWORD c; //c carry number
//---------------
*pEnd=1;
while (n>1)
{
for (c=0,p=pBuff+buffLen-1;p>=pEnd;p--)
{
prod=c+ (UINT64)(*p) * (UINT64)n;
*p=prod % RADIX;
c= prod / RADIX;
}
if (c>0)
{
pEnd--; *pEnd=c;
}
n--;
}
return pEnd;
}

int main(int argc, char* argv[])
{
DWORD n,buffLen,time;
DWORD *pEnd,*p;
DWORD *pBuff=NULL;
char *pChar;
FILE *fp=NULL;
char fileName[16];
//------------------------
while (true)
{
printf("please In put a number, 0 exit:\nn=?");
scanf("%d",&n);
if (n<1)
goto End;

sprintf(fileName,"%d!.txt",n);
buffLen=(calcResultLen(n)+8) / 9;

pBuff= new DWORD[buffLen];
fp=fopen(fileName,"wb");

if (pBuff==NULL || fp==NULL)
goto Exit;
//---------------------
time=GetTickCount();
pEnd=calc(n,pBuff,buffLen);
time= GetTickCount()-time;
printf("CAL TIME:%d ms\n",time);
//-----------------------------
time=GetTickCount();
fprintf(fp,"%d",*pEnd);
for (p=pEnd+1;p<pBuff+buffLen;p++)
fprintf(fp,"%09d",*p);
time= GetTickCount()-time;
printf("OUT TIME:%d ms\n\n",time);
//---------------------------------
Exit:
if ( pBuff!=NULL)
{ delete[] pBuff; pBuff=NULL; }
if (fp!=NULL)
{ fclose(fp); fp=NULL; }
}
End:
return 0;
}

程序2:
#include "stdio.h"
#include "windows.h"
#include "math.h"

#define RADIX 1000000000
#define PI 3.1415926535897932384626433832795
#define E 2.7182818284590452353602874713527

#ifndef DWORD
typedef unsigned long DWORD;
#endif

DWORD rad=RADIX;

int calcResultLen(DWORD n) //use stirling to calc the length of n!
{
if (n<=1)
return 1;
return log10(2*PI*(double)n)/2 + n * log10((double)n/E)+1;
}

DWORD calcCore(DWORD *p,DWORD n,DWORD c)
{
_asm
{
push ebx
;
mov ebx,p
xor edx,edx
mov eax,[ebx]
mul n
add eax,c
adc edx,0
div rad
mov [ebx],edx
;
pop ebx
}
}

void Num2Str(DWORD n, char *strEnd)
// number convert to string, in order to improve speed
// don't use lib function sprintf
{
char *p;
int i;
for ( i=0,p=strEnd;i<9;i++)
{
*p-- =( n % 10 +'0');
n /=10;
}
}

DWORD* calc( DWORD n, DWORD *pBuff,int buffLen)
{
DWORD *p; //lowest unit
DWORD *pEnd=pBuff+buffLen-1; //highest unit
DWORD c; //c carry number
//---------------
*pEnd=1;
while (n>1)
{
for (c=0,p=pBuff+buffLen-1;p>=pEnd;p--)
c=calcCore(p,n,c);

if (c>0)
{
pEnd--; *pEnd=c;
}
n--;
}
return pEnd;
}

int main(int argc, char* argv[])
{
DWORD n,buffLen,time;
DWORD *pEnd,*p;
DWORD *pBuff=NULL;

char *pRes=NULL;
char *pChar;

FILE *fp=NULL;
char fileName[16];
//------------------------

while (true)
{
printf("please In put a number, 0 exit:\nn=?");
scanf("%d",&n);
if (n<1)
goto End;

sprintf(fileName,"%d!.txt",n);
buffLen=(calcResultLen(n)+8) / 9;

pBuff= new DWORD[buffLen];
pRes= new char[buffLen * 9];
fp=fopen(fileName,"wb");

if (pBuff==NULL || pRes==NULL || fp==NULL)
goto Exit;

//---------------------
time=GetTickCount();
pEnd=calc(n,pBuff,buffLen);
time= GetTickCount()-time;
printf("CAL TIME:%d ms\n",time);
//-----------------------------

time=GetTickCount();
for (p=pEnd,pChar=pRes+8;p<pBuff+buffLen;p++)
{
Num2Str(*p,pChar);
pChar+=9;
}
pChar=pRes;
while ( *pChar=='0' ) pChar++; //skip the pre zero

fwrite(pChar,1,pRes+buffLen*9-pChar,fp); // write whole of result

time= GetTickCount()-time;
printf("OUT TIME:%d ms\n\n",time);

Exit:
if ( pBuff!=NULL)
{ delete[] pBuff; pBuff=NULL; }
if (pRes!=NULL)
{ delete[] pRes; pRes=NULL; }
if (fp!=NULL)
{ fclose(fp); fp=NULL; }
}
End:
return 0;
}


liangbch 2005-08-19
  • 打赏
  • 举报
回复
看看我的这个贴子: 201 字节的dos 平台的可执行文件可以计算到31999 的阶乘http://community.csdn.net/Expert/topic/4154/4154011.xml
ilelf 2005-08-19
  • 打赏
  • 举报
回复
找个算n!的算法就解决了嘛
觉得还是书上写的代码好一些。
去年研的时候见到这个题暴喜,以为很简单。只是n!=n*((n-1)!)了事。
结果回去一看书结果才发现晕死啊.
searoom 2005-08-16
  • 打赏
  • 举报
回复
一般原理可以用数组保存数字的各个位,
不能使用 int 类型(在 long 也不可能够的)
nicholasfor 2005-08-16
  • 打赏
  • 举报
回复
先恕罪,要说句恶毒的话了,
搞笑,拜托发贴之前先看看人家的贴。
xiaocai0001 2005-08-16
  • 打赏
  • 举报
回复
不止这个问题
你的那个递归函数根本就没有中止条件!!!!!
xiaocai0001 2005-08-16
  • 打赏
  • 举报
回复
问题大了,楼上的,按你那样写,fan(15)的结果就已经不正确了。
你不知道机器内计算数据还有个“溢出”的问题么?
fujike029 2005-08-16
  • 打赏
  • 举报
回复
#include<iostream.h>
fan(n)
int n;
{
int sum;
sum = fan(n-1)*n;
return(sum);
}

main()
{
fan(10000);
}

有什么问题?
GuaChon 2005-08-14
  • 打赏
  • 举报
回复
无聊话题```用减治法```这种题目没有什么使用价值啊``纯属无聊
布学无数 2005-08-14
  • 打赏
  • 举报
回复
哈,概念弄错了,让各位见笑啦:)
更正更正,当我回过这帖子~```
notruiyi 2005-08-14
  • 打赏
  • 举报
回复
10万个长度的字符串
xiaocai0001 2005-08-14
  • 打赏
  • 举报
回复

其实算阶乘有个很简单的办法,这个是我最近研究排序算法时碰巧发现的:
求 1-N 的阶乘:N 的平方除以 2,加上 N 除以 2。
即:(N * N) / 2 + N / 2
不信大家可以拿任意数求证:)
如果这样的话,10000 的阶乘就是:
= 10000 * 10000 / 2 + 10000 / 2
= 100000000 / 2 + 5000
= 50000000 + 5000
= 50005000

-----------------------------------
楼上说笑了!算阶乘有那么简单么。
你自己拿个简单的数计算一下5!= 120,你看看你给的工式算出来的是多少!
是阶乘,你给的那个公式是求和的公式!!
布学无数 2005-08-14
  • 打赏
  • 举报
回复
呵呵,干脆记下来,做个留念吧:
http://blog.csdn.net/lonely001/services/trackbacks/454265.aspx
布学无数 2005-08-14
  • 打赏
  • 举报
回复
其实算阶乘有个很简单的办法,这个是我最近研究排序算法时碰巧发现的:
求 1-N 的阶乘:N 的平方除以 2,加上 N 除以 2。
即:(N * N) / 2 + N / 2
不信大家可以拿任意数求证:)
如果这样的话,10000 的阶乘就是:
= 10000 * 10000 / 2 + 10000 / 2
= 100000000 / 2 + 5000
= 50000000 + 5000
= 50005000
lvbinandylau 2005-08-14
  • 打赏
  • 举报
回复
今天算开了眼界了,把这个帖子下载下来看个几个月
magic_laubj2008 2005-08-13
  • 打赏
  • 举报
回复
mark
加载更多回复(84)

33,311

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 新手乐园
社区管理员
  • 新手乐园社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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