最多支持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.youkuaiyun.com/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.youkuaiyun.com/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.youkuaiyun.com/antter
Email: jmiwork@yahoo.com