一个帖子引发的思考

有人发了一个帖子问怎么计算20!?

如果没有其他任何深入思考,觉得这个问题实在是很简单。如是下面有这样的回复:

#include   <stdio.h>
main()
{
            int   i;
            int   s=0;

            for(i=1;i <=20;i++)
                    s+=i;
            printf( "s=%d ",s);
}

这个回复当然符合习惯的思维,一个循环不就解决了吗?

这时有人就说了,20!那是一个很大的数,int 类型根本不够,如是有这样的回复:

__int64   Factorial(__int64     n)
{
    if(n   ==   1)
        return   1;
    else
        return   n*Factorial(n-1);
}

这个回复已经认识到问题了,至少思考了一下问题了。但是还是有人说了64位也不够的,如是有人这样回复:

你只是想实现   20!   还是想   进行大数运算,若只是想实现20!可以这样:
#include <iostream>
using   namespace   std;

double   factorial(int   n)
{
if(n <=1)
return   1;
else
return   n*factorial(n-1);
}

void     main(void)
{
cout < < "20!=   " < <factorial(20) < <endl;

system( "pause ");
}

当然大家知道递归的效率比较低,若考虑到效率,可以改为:

#include <iostream>
using   namespace   std;

double   factorial(int   n)
{
double   arr[21]={1,1};

for(int   i=2;i <=20;i++)
arr[i]=arr[i-1]*i;

return   arr[20];
}

void     main(void)
{
cout < < "20!=   " < <factorial(20) < <endl;

system( "pause ");
}

看到这样的回复,我相信lz应该已经很满足了,至少他的问题得到回答了。但是还是有人这样回复:

#include <stdlib.h>

/*-------任意大数阶乘的实现方法,可实现最大积为M-1位数的阶乘---------*/

#define   M   1000
int   data[M];   //第一位存储数的长度,从第二位开始依次从低位向高位存储每位数字
int   carry[M];   //存储每次乘积的进位

void   Inital()   //初始化数组data
{
        int   i;
        for(   i   =   2;   i   <=   M   -   1;   i++   )
                data[i]   =   0;
        data[0]   =   1;   //开始只有1位数
        data[1]   =   1;   //0的阶乘为1
}        

//                                     调整的起始位置     进位值       要调整的数组
void   adj_carry(   int   iStartIndex,   int   iPlus,   int   array[]   )
{
        while(   array[iStartIndex]   +   iPlus   > =   10   )   //向高位进
        {
                array[iStartIndex]   =   (array[iStartIndex]   +   iPlus)   %   10;
                iPlus   =   (array[iStartIndex]   +   iPlus)   /   10;  
                iStartIndex++;
        }        
        array[iStartIndex]   +=   iPlus;
}        

//用当前的数每别乘以data数组里从第二位开始的数,同时完成进位
void   goon(   int   i,   int   iNum   )   //i:当前乘的位数       M-1> =   i   > =1;   iNum:当前的阶乘子
{
        int   iPlus;
        int   iTotal   =   data[i]   *   iNum;   //当前的总数
        data[i]   =   iTotal%10;
        if(   iTotal   > =   10   )
        {
                adj_carry(   i+1,   iTotal/10,   carry   );   //调整进位数组
        }        
}    

//调整阶乘位数
void   adj_total(     )
{
        int   i;
        for(   i   =   M   -   1;   i   > =   data[0];   i--   )
                if(   data[i]   >   0   )
                {
                        data[0]   =   i;   //共有i位
                        break;
                }        
}    

//将进位加至和数数组
void   add_carry_to_data()
{
        int   i;
        int   iTotal;
        for(   i   =   1;   i   <=   M   -   1;   i++   )
        {
                iTotal   =   data[i]   +   carry[i];
                data[i]   =   iTotal   %   10;
                if(   iTotal   > =   10   )   //进位
                {
                        adj_carry(   i+1,   iTotal/10,   data   );   //调整进位数组
                }        
        }        
}            

//进位数组清0
void   clear_carry()
{
        int   i;
        for(   i   =   1;   i   <=   M   -   1;   i++   )
                carry[i]   =   0;
}        
void   Mul(   int   iNum   )   //阶乘
{
        int   i,   j;
        for(   i   =   1;   i   <=   iNum;   i++   )
        {
                for(   j   =   1;   j   <=   data[0];   j++   )
                        goon(   j,   i   );
               
                add_carry_to_data();   //将进位数组加至和数组
                adj_total(   );   //调整总位数
                clear_carry();   //清0进位数组,准备下一次阶乘
        }        
}        

main()
{
        int   i;
        Inital();
        Mul(   100   );
        printf(   "共   %d   位数:/n ",   data[0]   );
        for(   i   =   data[0];   i   > =   1;   i--   )
                printf(   "%d ",   data[i]   );
        printf(   "%/n "   );
               
        system( "pause ");
}        

结果:
共   154   位数:
50030657837459613088140586563373203306192310297549125085554140803486718798911936
93461999118240301448181697299177053424912511152960000000000000000000000000
请按任意键继续.   .   .

这样的回复当然是比较全面的,至少比前面几位的回复要好。

这个帖子给我的思考是如果把lz的问题当做一个需求,下面的回复都是一种设计方案,那么很明显前面两种方案都是没有实现需求,第三种虽然满足了需求,但是扩展性和健壮性都不够,第四种方案在这些方面都有所提高但是还不够。反过来说,当看到这样的需求的时候,我们测试如何去预见可能发生的错误呢?怎么防止像回复1和2那样错误的方案,更如何去预防像方案3那样正确但不完善的方案呢?

我觉得以下几件事情可以去做:

1.分析需求隐藏的需求。针对lz的提问,问一个问题。一个是20!的阶乘的结果是多少位数?另一个是只是算20!还是也可能要算更大的数?当然除了这两个问题以外还可以问,输入的都是数字吗?还是有可能会输入其他字符呢?

2.猜想可能存在的简单设计。按照lz的提问,最可能的设想便是递归或者循环。那么有了这种猜想,可以至少防止1,2方案的发生。

3.挖掘需求潜在的需求。只是算20!还是也可能要算更大的数?当然除了这两个问题以外还可以问,输入的都是数字吗?还是有可能会输入其他字符呢?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值