大數相乘 - 浮點數

 最多支持0.04G位的大浮點數相乘算法,提供10000階乘的例子.

昨天,噢不,今日拂曉,雞鳴之時,寫了一大整型數相乘,下午有空,改進了一下,昨天直覺說實現以上幾點能提升45%今天一試,哈準.果然是45%左右

2006-11-2 14:12
修改:
1. 對字符串進行封裝爲bignum
2. 內部由char* 代替string
3. 支持浮點運算.

性能提升50%

提升性能的改進設想:
1. 對於小型的long,int,__int64等,採用非string的處理方式,以減少整型與字串轉換.


實現以上1點,性能大約提升5%~10%,亂猜的 :)

如果可能的話會加上除法

// $Id: multi.cpp 7 2006-11-02 06:30:51Z JiangMiao $ 
// JiangMiao's Blog http://blog.csdn.net/antter
#include "stdafx.h"
#include 
<iostream>
#include 
<string>
using namespace std;

#define SAFE_DELETE(p) if((p)!=NULL){delete p;p=NULL;}
typedef unsigned 
long DWORD;
#define OK 0
#define FAIL (DWORD)-1

class bignumFunc
    {
    
    
public:
    
/// 轉換字符串爲
    inline static char* strToInt(const string& in
        {
        
char* rt=new char[in.size()];
        
for(size_t i=0;i<in.size();i++
            {
            rt[i]
=in[i]-'0';
            }
        
return rt;
        }

    };
class bignum
    {

    
char* 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(str);
        length 
= 0;
        point 
= 0;
        
return OK;
        }

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

    
// 讀入string
    DWORD read(const string& in)
        {
        
return read(in.c_str(),in.size());
        }
    DWORD read(
const char* in,size_t length)
        {
        init(length);
        
char* str=this->str;
        size_t i;
        
for(i=0;i<length;i++)
            {
            (
*str++)=(*in++)-'0';
            
if((*in)=='.'
                {
                i
++;
                
break;
                }
            }
        point
=i;
        
if(i==length) 
            {
            
this->length=i;
            
return OK;
            }
        i
++;            
        
for(;i<length;i++)
            {
            (
*str++)=(*++in)-'0';
            }
        
this->length=i-1;
        
return OK;
        }

    
//輸出到string
    string toString()
        {
        
string rt;
        rt.reserve(length
+1);
        size_t i;
        
for(i=0;i<point;i++)
            {
            rt.append(
1,str[i]+'0');
            }
        
if(length!=point) 
            {
            rt.append(
1,'.');
            
for(;i<length;i++)
                {
                
//這裏可加入小數點後的末尾0不輸出
                rt.append(1,str[i]+'0');
                }
            }
        
return rt;
        }

    
    
/**
     * 大數相乘,最大位數 0.04G 即32位int/(9*9)
     
*/
    
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; //最大可能位數
        char* a=sa->str;
        
char* b=sb->str;
        unsigned  
int* r=new unsigned int[lr];//分配結果空間
        size_t ia,ib,ir;
        rt
->init(lr);
        memset(r,
0,lr*sizeof(int));
        
for(ia=0;ia<la;ia++//相乘
            {
            
for(ib=0;ib<lb;ib++)
                {
                ir
=ib+ia+1;
                r[ir]
+=a[ia]*b[ib];
                }
            }
        
for(ir=lr-1;ir>0;ir--//進位
            {
            
int add=r[ir]/10;
            r[ir
-1]+=add;
            r[ir]
%=10;
            }
        size_t i
=0;
        
for(ir=0;ir<lr;ir++//除去前面多餘的0
            {
            
if(r[ir]!=0)
                
break;
            i
++;
            }
        xs
-=i;
        i
=0;
        
char* dr=rt->str;
        
for(;ir<lr;ir++//生成字串
            {
            dr[i
++]=r[ir];
            }
        
//Reserved: 除去尾部多餘0,如果放入輸出函數可提升效率
        rt->length=i;
        rt
->point=xs;
        delete r;
        
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: 7
2006-11-2 14:12
修改:
1. 對字符串進行封裝爲bignum
2. 內部由char* 代替string
3. 支持浮點運算.

性能提升50%

提升性能的改進設想:
1. 對於小型的long,int,__int64等,採用非string的處理方式,以減少整型與字串轉換.


實現以上1點,性能大約提升5%~10%,亂猜的 :)
-------------------------------------------
*/


/// 以下爲測試文件
#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);

/*    10000階乘測試
    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);
        }
*/
    
/*
    浮點數相乘
*/
    an
->read("3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989");
    bignum::mul(cn,an,an);

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


/* 測試10000!的結果
 * C4 2.66MHZ

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

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

//1000位大浮點數相乘
Spend 3147ns
2001
請按任意鍵繼續. . .
 
*/

 

 歡迎探討.

我的Blog是 http://blog.csdn.net/antter
Email: [email protected]

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