// $Id: multi.cpp 7 2006-11-02 06:30:51Z JiangMiao $ // JiangMiao's Blog http://blog.csdn.net/antter #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; system("pause"); 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 请按任意键继续. . . */
http://blog.csdn.net/antter/article/details/1362761
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> using namespace std; #define N 100 //将在数组中保存的字符串转成数字存到int数组中 void getdigits(int *a,char *s) { int i; char digit; int len = strlen(s); for(i = 0; i < len; ++i) { digit = *(s + i); *(a + len - 1 - i) = digit - '0';//字符串s="12345",因此第一个字符应该存在int数组的最后一个位置 } } //将数组a与数组b逐位相乘以后存入数组c void multiply(int *a,int *b,int *c) { /* 数组a中的每位逐位与数组b相乘,并把结果存入数组c 比如,12345*12345,a中的5与12345逐位相乘 对于数组c:*(c+i+j)在i=0,j=0,1,2,3,4时存的是5与各位相乘的结果 而在i=1,j=0,1,2,3,4时不光会存4与各位相乘的结果,还会累加上上次相乘的结果.这一点是需要注意的!!! */ for(int i = 0; i < N; ++i) for(int j = 0; j < N; ++j) *(c + i + j) += *(a + i) * *(b + j); //这里是移位、进位 for(int i = 0; i < 2 * N - 1; ++i) { *(c + i + 1) += *(c + i)/10; //将十位上的数向前进位,并加上原来这个位上的数 *(c + i) = *(c + i)%10; //将剩余的数存原来的位置上 } } int main() { int a[N] = {0},b[N]= {0},c[2*N] = {0}; char s1[N] = "99999999999999999999999999999999999999999999999"; getdigits(a,s1); getdigits(b,s1); multiply(a,b,c); int j = 2*N-1; while(c[j] == 0) j--; for(int i = j;i >= 0; --i) printf("%d",c[i]); printf(" "); system("pause"); return 0; }