// $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/1362761ios
#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("\n"); system("pause"); return 0; }