zoukankan      html  css  js  c++  java
  • 大数相乘(支持浮点数)

    // $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;
    }
  • 相关阅读:
    Linux日志不记录问题
    Centos下yum安装PHP
    centos yum update kernel
    oh-my-zsh主题
    centos 6.6 使用tomcat6部署solr5.3.1
    Nginx manifest 实现 HTML5 Application Cache
    -bash: /bin/rm: Argument list too long
    linux mysql-5.6.26 安装
    LVM 管理减少swap分区空间增加到根分区
    Linux 使用iftop命令查看服务器流量
  • 原文地址:https://www.cnblogs.com/byfei/p/6389830.html
Copyright © 2011-2022 走看看