相信很多编程新手都上google,baidu搜过这类东西。 我也是因为这样才终于下决心自己动手完善一个大整数类,虽然C++效率不如C,不过只是关键算法明白就好,写成类只是心理痛快点。
先看头文件代码:
基本的C++类什么的就不详细讲了,主要说一下设计思路。
用C++主要是因为运算符重载比较爽。#define MAXLEN 1000 #define POSITIVE 1 #define NEGATIVE -1 #define ZERO 0 class HugeInt { friend ostream& operator<<(ostream& output,const HugeInt& n); public: /* 构造函数 */ HugeInt(int=0); HugeInt(char *str); HugeInt(const HugeInt& other); HugeInt& operator=(const HugeInt& other); /* 关系运算符 */ bool operator==(const HugeInt &other)const; bool operator==(const int &x)const; bool operator!=(const HugeInt &other)const; bool operator!=(const int &x)const; bool operator>(const HugeInt &other)const; bool operator>(const int &x)const; bool operator>=(const HugeInt &other)const; bool operator>=(const int &x)const; bool operator<(const HugeInt &other)const; bool operator<(const int &x)const; bool operator<=(const HugeInt &other)const; bool operator<=(const int &x)const; /* 加法运算 */ HugeInt operator+(const HugeInt &other)const; HugeInt operator+(const int &x)const; HugeInt operator+=(const HugeInt &other); HugeInt operator+=(const int &x); HugeInt& operator++();//前置 HugeInt operator++(int);//后置 /* 减法运算 */ HugeInt operator-();//负号 HugeInt operator-(const HugeInt &other)const; HugeInt operator-(const int &x)const; HugeInt operator-=(const HugeInt &other); HugeInt operator-=(const int &x); HugeInt& operator--();//前置 HugeInt operator--(int);//后置 /* 乘法运算 */ HugeInt operator*(const HugeInt &other)const; HugeInt operator*(const int &x)const; HugeInt operator*=(const HugeInt &other); HugeInt operator*=(const int &x); /* 除法运算 */ HugeInt operator/(const HugeInt &other)const; HugeInt operator/(const int &x)const; HugeInt operator/=(const HugeInt &other); HugeInt operator/=(const int &x); /* 求模运算 */ HugeInt operator%(const HugeInt &other)const;//to do:debug int operator%(const int &x)const; HugeInt operator%=(const HugeInt &other); int operator%=(const int &x); private: char num[MAXLEN]; int length; int sign; bool isZero()const; };
成员里用一个char类型数组存数,length表示长度,int类型的sign表示负号,定义了仨宏,看着方便点,用int类型也是因为比较大小的时候很方便,单独存符号比掺合到数组里方便不少!
全部的头文件代码都在这了,cpp里的不会贴这么多,像+=这样的符号都是直接引用+号的。
下面是cpp:
HugeInt::HugeInt(int x) //构造函数 { memset(num,0,sizeof(num)); if(x == 0) { sign=ZERO; length=1; } else { if(x > 0) sign=POSITIVE; else { sign=NEGATIVE; x = -x; } int i=0; while(x != 0) { num[i++] = x%10; x /= 10; } length = i; } }
HugeInt::HugeInt(char *str)//构造函数 { memset(num,0,sizeof(num)); if(str[0]=='-') sign=NEGATIVE; else sign=POSITIVE; int i,j,k,n=strlen(str); for(i=0;i<n;i++) if(str[i]>'0' && str[i]<='9')break; if(i==n) { sign=ZERO; length=1; num[0]=0; } else { for(k=n-1,j=0;k>=i;--k,++j) num[j]=str[k]-'0'; length=j; } }
bool HugeInt::operator>(const HugeInt &other)const//大于号 { if(this->sign == other.sign) { bool flag=(sign == POSITIVE); if(this->length != other.length) return flag&(this->length > other.length); else { int i; for(i=length-1;i>=0;--i) if(this->num[i] > other.num[i]) return (flag?true:false); else if(this->num[i] < other.num[i]) return (flag?false:true); return false; } } else return (this->sign > other.sign);//int 类型的sign方便就方便在这了 }
HugeInt HugeInt::operator+(const HugeInt &other)const//加法 { if(this->isZero()) return other; if(other.isZero()) return *this; HugeInt temp(0); if(this->sign == other.sign) { int maxlength=max(length,other.length); int i; for(i=0;i<maxlength;++i) { temp.num[i] += (num[i]+other.num[i]); temp.num[i+1] += temp.num[i]/10; temp.num[i] = temp.num[i]%10; } temp.sign=sign; temp.length=maxlength; if(temp.num[temp.length]) temp.length++; return temp; } else if(this->sign == NEGATIVE) { temp=(*this); temp.sign=POSITIVE; return (other-temp); } else { temp=other; temp.sign=POSITIVE; return ((*this)-temp); } }
HugeInt HugeInt::operator-(const HugeInt &other)const//减法 { if((*this) < other) return -(other - (*this)); else if((*this) == other) return HugeInt(0); else { HugeInt temp(*this); int i; for(i=0;i<temp.length;++i) if(temp.num[i] < other.num[i]) { --temp.num[i+1]; temp.num[i] = temp.num[i]+10-other.num[i]; } else temp.num[i] -= other.num[i]; for(i=temp.length;i>=0;--i) if(temp.num[i]) { temp.length = i+1; break; } return temp; } }
HugeInt HugeInt::operator*(const HugeInt &other)const//乘法 { if(this->isZero() || other.isZero()) return HugeInt(0); else { int i,j; HugeInt temp(0); for(i=0;i < this->length;++i) for(j=0;j < other.length;++j) { temp.num[i+j] += (num[i]*other.num[j]); temp.num[i+j+1] += temp.num[i+j]/10; temp.num[i+j] %= 10; } temp.length=(i-1)+(j-1)+1; if(temp.num[temp.length]) ++temp.length; temp.sign = this->sign * other.sign; return temp; } }
HugeInt HugeInt::operator/(const HugeInt &other)const//除法,另需一个函数,在下面 { if(this->length < other.length)return HugeInt(0); int i,t,z; HugeInt result(0),n1(*this),n2(other); result.sign = n1.sign * n2.sign; t=n1.length - n2.length; if(t > 0) for(i=length;i>=0;--i) if(i-t >= 0)n2.num[i] = n2.num[i-t]; else n2.num[i] = 0; n2.length = n1.length; for(i=0;i<=t;++i) while((z=subtract(n1.num,(n2.num)+i,n1.length,n2.length-i))>=0) { n1.length = z; result.num[t-i]++; } for(i=MAXLEN-1;i>=0;--i) if(result.num[i])break; if(i>=0)result.length = i+1; else return HugeInt(0); return result; }
int subtract(char *p1,char *p2,int len1,int len2) { int i; if(len1 < len2)return -1; else if(len1 == len2) { for(i=len1-1;i>=0;--i) if(p1[i] < p2[i]) return -1; else if(p1[i] > p2[i]) break; if(i < 0)return 0; } for(i=0;i<len1;++i) if(p1[i] < p2[i]) { p1[i+1]--; p1[i] = p1[i]+10-p2[i]; } else p1[i] -= p2[i]; for(i=len1-1;i>=0;--i) if(p1[i]) return i+1; return 0; }
HugeInt HugeInt::operator%(const HugeInt &other)const//模运算,跟除法一样,就是返回的不同 { if(this->length < other.length)return *this; int i,t,z; HugeInt n1(*this),n2(other); t=n1.length - n2.length; if(t > 0) for(i=length;i>=0;--i) if(i-t >= 0)n2.num[i] = n2.num[i-t]; else n2.num[i] = 0; n2.length = n1.length; for(i=0;i<=t;++i) while((z=subtract(n1.num,(n2.num)+i,n1.length,n2.length-i))>=0) { if(z == 0)return HugeInt(0); n1.length = z; } return n1; }
上面是几种运算的核心代码,加减法主要是分类讨论,互相“推卸责任”,加法不同号推给减法等等。。int HugeInt::operator%(const int &x)const//大数模小数,不需要大整数除法 { int i,exp10[this->length+1],k=0; exp10[0]=1%x; exp10[1]=10%x; for(i=2;i<=this->length;++i) exp10[i] = exp10[i-1]*exp10[1]%x; for(i=0;i<this->length;++i) k = (k+(this->num[i])%x*exp10[i])%x; return k; }
乘法就是模拟手算,第i位乘以另一个数的第j位结果加到第i+j位就好,原理跟手算一样,拿笔画画就明白了,符号非常好处理。
除法也基本上是模拟手算,只不过试商的过程改成了减法,比如100除以3,商33,就需要算3次100减30和3次10减3,时间复杂度我也琢磨不清楚。大数模大数的运算和除法一样,返回余数。大数模小数的运算有一个公式推出来的,不太容易讲,是在百度知道上搜到的。
上面这些算法都是最思路上最简单的,没有任何优化,是因为我能力还很有限啊~说起来我只不过干了个体力活而已。原理我也没有详细说,网上都搜的到。
完整的代码我另写一篇日志贴上去把,头一次用 csdn博客,请多指教。