大数相乘 - 整型数(二)

 不再以10进制为单位
目前是10000进制

性能有极大的提升

//  $Id: multi.cpp 8 2006-11-03 05:54:04Z JiangMiao $ 
//  JiangMiao's Blog  http://blog.csdn.net/antter
#include  " stdafx.h "
#include 
< iostream >
#include 
< string >
#include 
< list >
using   namespace  std;

#define  SAFE_DELETE(p) if((p)!=NULL){delete p;p=NULL;}
#define  SAFE_DELETE_ARRAY(p) if((p)!=NULL){delete[] p;p=NULL;}
typedef unsigned 
long  DWORD;
#define  OK 0
#define  FAIL (DWORD)-1
#define  BLOCK 4  // 块位数
#define  BLOCKS 10000  // 1e+4 即10000进制
#define  BLOCKNUM(size) size/BLOCK+(size%BLOCK>0) // 由size得到最大块数

class  bignumFunc
    {
    
    
public :
    
///  转换字符串为
    inline  static  DWORD strToInt( const   string &  inold,DWORD *&  rt,size_t &  length,size_t &  point) 
        {
        
string   in ;
        size_t insize
= inold.size();
        
in .reserve(insize);
        
// point=insize;
        point = FAIL;
        
for (size_t i = 0 ;i < insize;i ++ )
            {
            
if (inold[insize - i - 1 ] == ' . '
                {
                point
= i;
                
continue ;
                }
            
in .append( 1 ,inold[insize - i - 1 ]);
            }
        SAFE_DELETE_ARRAY(rt);
        size_t size
= in .size();
        size_t num
= BLOCKNUM(size);
        rt
= new  DWORD[num];
        
for (size_t i = 0 ;i < num;i ++
            {
            DWORD s
= 0 ;
            size_t pos
= 0 ;
            
for (size_t j = 0 ;j < BLOCK;j ++ )
                {
                pos
= i * BLOCK + BLOCK - 1 - j;
                
if (pos >= in .size())
                    {
                    
continue ;
                    }
                s
= s * 10 + in [pos] - ' 0 ' ;

                }
            rt[i]
= s;
            
if (pos >= in .size())
                
break ;
            }
        
if (point == FAIL)
            {
            length
= BLOCKNUM(size);
            point
= size;
            }
        
else
            {
            length
= BLOCKNUM(size - 1 );
            }
        
return  OK;
        }

    };
class  bignum
    {

    DWORD
*  str;
    size_t length;
    size_t point;

    
public :
    bignum():str(NULL),length(
0 ),point( 0 )
        {
        }
    
~ bignum()
        {
        }
    bignum(
const  bignum &  b)
        {
        init(b.length);
        length
= b.length;
        point
= b.point;
        memcpy(str,b.str,length);
        }
    size_t size()
        {
        
return  length;
        }
    DWORD reset()
        {        
        SAFE_DELETE_ARRAY(str);
        length 
=   0 ;
        point 
=   0 ;
        
return  OK;
        }

    
//  分配空间
    DWORD init(size_t length)
        {
        reset();
        str
= new  DWORD[length];
        memset(str,
0 ,length * sizeof (DWORD));
        
return  OK;
        }

    
//  读入string
    DWORD read( const   string &   in )
        {
        
return  bignumFunc::strToInt( in ,str,length,point);
        }
    DWORD read(
const  DWORD *   in ,size_t length)
        {
        
return  OK;
        }

    
// 输出到string
     string  toString()
        {
        
string  rt;
        rt.reserve(length
* sizeof (DWORD));
        size_t i;
        
for (i = 0 ;i < length;i ++ // 进位
            {
            DWORD num
= str[i];
            DWORD o
= num % BLOCKS;
            DWORD c
= num / BLOCKS;
            str[i
+ 1 ] += c;
            str[i]
= o;
            }
        
for (i = length - 1 ;i >= 0 ;i -- // 去头零
            {
            
if (str[i] != 0 )
                
break ;

            }

        
for (;i != FAIL;i --
            {
            
char  buf[ 16 ];
            _ultoa_s(str[i],buf,
16 , 10 );
            
for (size_t k = 0 ;k < 4 - strlen(buf);k ++
                {
                
if (rt.size() == 0 // 补足4位
                     break ;
                rt
+= ' 0 ' ;
                }
            rt
+= buf;
            }
        
return  rt;
        }

    
    
/* *
     * 大数相乘,任意位数
     
*/
    
static  bignum *  mul(bignum *  rt,bignum *  sa,bignum *  sb)
        {
        size_t la
= sa -> length;
        size_t lb
= sb -> length;
        size_t xs
= sa -> point + sb -> point; // 小数位数
        size_t lr = la + lb;  // 最大可能位数
        DWORD *  a = sa -> str;
        DWORD
*  b = sb -> str;
        rt
-> init(lr);
        DWORD
*  r = rt -> str;
        size_t ia,ib,ir;
        size_t k
= 1 ;
        
for (ia = 0 ;ia < la;ia ++ // 相乘
            {
            
for (ib = 0 ;ib < lb;ib ++ )
                {
                k
++ ;
                ir
= ib + ia;
                r[ir]
+= a[ia] * b[ib];
                
if (r[ir] >= BLOCKS)  // 进位
                    {
                    
                    DWORD num
= r[ir];
                    DWORD o
= num % BLOCKS;
                    DWORD c
= num / BLOCKS;
                    r[ir
+ 1 ] += c;
                    r[ir]
= o;
                    }
                }
            }
        
if (r[lr - 1 ] == 0 )
            lr
-- ;

        rt
-> length = lr;
        rt
-> point = xs;
        
return  rt;
        }
    };

class  bignumBuilder
    {
    
public :
        
static  bignum *  build( const   string &  str)
            {
            bignum
*  bn = new  bignum();
            bn
-> read(str);
            
return  bn;
            }
    };

/*

Revision: 6
2006-11-2 5:30
提升性能的改进设想:
1. 使用char* 代替string
2. 多数相乘返回非string,最后由intToStr进行字串输出,可极大地节省预处理和生成的时间

实现以上两点性能提升至少45%,乱猜的 :)
-------------------------------------------

Revision: 6.1
2006-11-3
修改
1. 不再以单个字符为单位
2. 位数不在受到限制

提升性能的改进设想:
使用16进制.对取余和进位采取位操作


性能提升 1300%
-------------------------------------------
*/


///  以下为测试文件
#include  " windows.h "
int  main( int  argc, char **  argv)
    {
    
string  rt;
    bignum
*  an = new  bignum();
    bignum
*  bn = new  bignum();
    bignum
*  cn = new  bignum();
    LARGE_INTEGER fre,begin,end;
    QueryPerformanceFrequency(
& fre);
    QueryPerformanceCounter(
& begin);

//     100000阶乘测试
    cn -> read( " 1 " );
    
for ( int  i = 1 ;i <= 10000 ;i ++ )
        {
        bignum
*  tmp = an;
        an
= cn;
        cn
= tmp;
        
char  b[ 6 ];
        _itoa_s(i,b,
10 );
        bn
-> read(b);
        bignum::mul(cn,an,bn);
        }

    QueryPerformanceCounter(
& end);
    cout
<< " Spend  " << (end.QuadPart - begin.QuadPart) * 1000000 / fre.QuadPart << " ns " << endl;
    cout
<< cn -> toString().size() << endl;
    
return   0 ;
    }


/*  测试10000!的结果
 * C4 2.66MHZ

revision: 6
Spend 16911238ns //17s
35660.

------------------------
revision: 7
10000阶乘
Spend 8441291ns (8.5秒)提升100%
35660

//1000位大浮点数相乘
Spend 3147ns
2001
------------------------
revision: 8
Spend 593560ns (0.6秒)提升1300%
35660
请按任意键继续. . .
 
*/

 

欢迎探讨,

我的Blog是http://blog.csdn.net/antter

Email: jmiwork@yahoo.com

QQ: 185500511

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值