最多支持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
請按任意鍵繼續. . .
*/
// 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]