大數相乘(支持浮點數)

// $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;
}
相關文章
相關標籤/搜索