大數相乘 - 整型數(二)

 不再以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: [email protected]

QQ: 185500511

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章