- 注册时间
- 2007-5-18
- 最后登录
- 1970-1-1
|
公开并不优秀甚至垃圾的代码实属情非得已,的目的是请手指点,如何才能实现动态内存分配,就是在程序开始运行后根据将要计算的数值大小来分配需要的内存而不用一开始就分配很大的内存,这样在计算比较小的数的阶乘时会比较浪费内存,我也曾考虑过链表,但好像不能用链表来实现,请高手将修改后的代码或修改的思路或别人写的比较优秀的代码发给我,不盛感激。
受论坛限制,这里只发核心代码,附件里有全部代码。
- #define CAPACITY 100000 //宏定义存储容量,可根据需要修改
- #define ACCURACY 30 //宏定义结果显示精度,结果位数超过该值则自动采用科学计数法
- #include "conio.h" //getch函数头文件
- #include "stdlib.h" //system用到的头文件
- void GetFactorial(long *a,long n); //n>12时计算阶乘
- long GetRemainder(long n); //n<=12时的计算阶乘,因为long型最大只能容纳12的阶乘
- void Print(long n); //输出计算结果到屏幕
- long GetPosition(long *a); //结果在数组中的存储起始位置确定函数
- long num; //要求阶乘的数
- long stor=1; //n<=12时存储结果,因为long型最大只能容纳12的阶乘
- long storage[CAPACITY]={0}; //n>12时存储结果
- void main()
- {
- system("cls"); //系统清屏命令
- printf("\n请输入一个数:");
- scanf("%ld",&num);
- if(num<0) //虽然科学家已经将阶乘从自然数扩展到了有理数,但此处不提供负数阶乘的计算
- {
- printf("\n您的输入错误!\n");
- exit(0);
- }
- else
- {
- if(num<=12)
- stor=GetRemainder(num); //<=12的数用GetRemainder函数计算,因为long型最大只能容纳12的阶乘
- else
- GetFactorial(storage,num); //当要计算的数>12时用GetFactorial函数计算
- Print(num); //计算完成后向屏幕输出结果
- }
- system("pause"); //系统命令:提示信息
- getch(); //程序暂停,没有的话整个程序运行一晃而过看不见输出结果
- }
- long GetRemainder(long n) //num<=12时用来计算阶乘
- {
- int i=2;
- long s=1;
- while(i<=n)
- s*=i++;
- return(s);
- }
- void GetFactorial(long *a,long n) //num>12时用来计算阶乘
- {
- register int i; //因为i、j要频繁的用到所以定义为寄存器变量
- register long j;
- long former_address,carry; //former_address用来存储数组每一位与n相乘后的结果,carry用来存储后位给前位的进位
- long m=479001600; //12的阶乘
- int p,s=CAPACITY-9; //s用来记录这次计算后应该比前次向高位多扩展多少位数,p用来记录到底应该向高位扩展多少位
- for(i=CAPACITY-1;i>=CAPACITY-9;i--) //用m也就是479001600来初始化storagr数组,因为任何>12的数的阶乘要以12的阶乘为基础进行计算
- {
- a=m%10; //将m对10求余的第一次结果保存到storage的最后一个元素
- m/=10; //将m除10后仍保存在m
- }
- for(j=13;j<=n;j++) //真正>12的阶乘计算开始了
- {
- p=0;
- carry=j;
- while(carry%10) //通过上次结果的最高位向更高位进位的多少来决定下次遍历要向数组低位移动多少位
- {
- carry/=10;
- p++;
- }
- s-=(p+1); //以防扩展不够所以多扩展一位
- carry=0; //最低位不能接受进位
- for(i=CAPACITY-1;i>=s;i--)
- {
- a*=j; //用j乘以storage的每一个有效元素(之所以说“有效”是因为自始至终都有元素没有参加到计算中来)结果仍存储在原位置
- former_address=a+carry; //本位的数加上低位的进位赋给former_address,作为向高位进位和本位保留的依据
- carry=former_address/10; //将former_address中个位以上的部分交给carry,让它在下次运算时将这个数进给高位
- a=former_address%10; //将former_address的个位数字交回给原来的位置
- }
- }
- }
- void Print(long n) //打印结果到屏幕
- {
- register int i,j; //凡是频繁用到的变量我们都将它定义为寄存器变量
- int signifcant_digits,decimal_point; //signifcant_digits用来控制小于显示精度的有效位数,即使你将精度位数设的再大程序也不会输出计算结果末尾无意义的0
- decimal_point=0; //decimal_point是小数点的控制开关,为0时将不输出小数点
- printf("\n%ld!=",n);
- if(n<=12)
- printf("%ld\n",stor); //当n<=12时直接打印long型数据stor的值
- else
- {
- i=GetPosition(storage); //再次强调storage数组不是每个元素都保存着计算结果,所以此处要用GetPosition函数来获得结果开始的位置
- if(CAPACITY-i<=ACCURACY) //如果计算结果的位数<=输出精度的时候程序将从结果起始位置开始逐个输出storage中的元素值
- while(i<CAPACITY)
- printf("%ld",storage[i++]);
- else //当输出精度<计算结果位数时输出就没有上面那么简单
- {
- printf("%ld",storage);
- signifcant_digits=i+ACCURACY-1;
- for(j=i+1;j<i+ACCURACY;j++) //获得实际有效位数及小数点开关值
- if(storage[j]!=0)
- {
- signifcant_digits=j;
- decimal_point=1;
- }
- if(decimal_point)
- printf(".");
- for(j=i+1;j<signifcant_digits;j++) //按比控制精度少一位来打印结果,不全打印是因为最后一位要4舍5入
- printf("%ld",storage[j]);
- if(storage[signifcant_digits+1]>4) //根据控制精度的下一位确定控制精度最后一位是否需要进位
- printf("%ld",storage[signifcant_digits]+1);
- else
- printf("%ld",storage[signifcant_digits]);
- printf("e+%d",CAPACITY-i-1); //最后打印科学记数法的指数部分
- }
- }
- printf("\n");
- }
- long GetPosition(long *a) //获得计算结果在数组中的起始位置
- {
- long i=0;
- while(i<=CAPACITY) //遍历数组元素,当发现第一个不为0的数字立即退出循环
- if(a[i++]!=0)
- break;
- return i-1; //将第一个不为0的数字的序号返回
- }
复制代码
[ 本帖最后由 CJJR 于 2008-5-1 19:08 编辑 ] |
|