高精度重载运算符的C++代码
来源:互联网 发布:淘宝lolita店铺 编辑:程序博客网 时间:2024/05/20 18:54
高精度算法(压位存储)!
有的时候,数字会大到连long long都不能承受的程度。这时,我们可以自己模拟大数的各种运算。
所谓压位存储,就是在高精度数内部采用10000进制(即每四位放到一个数中)进行存储。它与10进制(即一个数位对应一个数)相比速度要快一些。
高精度数内部也可以采用100000000进制,但是这样就不能计算乘除法了。
(1) 定义
编程时这样做——假设hp是高精度类型。
先用宏定义:#define hp long long[1],然后集中精力编写算法代码。
最后直接删除这条宏定义,把真正的高精度算法写出来。这样做的好处是无需再修改算法代码,减小了维护代价。
const int MAX=100;struct hp{ int num[MAX]; hp & operator = (const char*); hp & operator = (int); hp(); hp(int); // 以下运算符可以根据实际需要来选择。 bool operator > (const hp &) const; bool operator < (const hp &) const; bool operator <= (const hp &) const; bool operator >= (const hp &) const; bool operator != (const hp &) const; bool operator == (const hp &) const; hp operator + (const hp &) const; hp operator - (const hp &) const; hp operator * (const hp &) const; hp operator / (const hp &) const; hp operator % (const hp &) const; hp & operator += (const hp &); hp & operator -= (const hp &); hp & operator *= (const hp &); hp & operator /= (const hp &); hp & operator %= (const hp &);};
实现运算符的代码最好写到结构体的外面。
“<<”和“>>”由于不是hp的成员,所以必须写到结构体的外面。
(2) 赋值和初始化
// num[0]用来保存数字位数。另外,利用10000进制可以节省空间和时间。hp & hp::operator = (const char* c){memset(num,0,sizeof(num));int n=strlen(c),j=1,k=1;for (int i=1;i<=n;i++){if (k==10000) j++,k=1;// 10000进制,4个数字才算1位。num[j]+=k*(c[n-i]-'0');k*=10;}num[0]=j;return *this;}hp & hp::operator = (int a){char s[MAX];sprintf(s,"%d",a);return *this=s;}hp::hp() {memset(num,0,sizeof(num)); num[0]=1;}// 目的:声明hp时无需显式初始化。hp::hp (int n) {*this = n;} // 目的:支持“hp a=1;”之类的代码。
(3) 比较运算符
小学时候学过怎么比较两个数的大小吧?现在,虽为高中生,小学知识却从未过时……
// 如果位数不等,大小是可以明显看出来的。如果位数相等,就需要逐位比较。
// 如果位数不等,大小是可以明显看出来的。如果位数相等,就需要逐位比较。bool hp::operator > (const hp &b) const{if (num[0]!=b.num[0]) return num[0]>b.num[0];for (int i=num[0];i>=1;i--)if (num[i]!=b.num[i])return (num[i]>b.num[i]);return false;}bool hp::operator < (const hp &b) const {return b>*this;}bool hp::operator <= (const hp &b) const {return !(*this>b);}bool hp::operator >= (const hp &b) const {return !(b>*this);}bool hp::operator != (const hp &b) const {return (b>*this)||(*this>b);}bool hp::operator == (const hp &b) const {return !(b>*this)&&!(*this>b);}
(4) 四则运算
如果没学过竖式,或者忘了怎么用竖式算数,那么你就悲剧了……
1. 加法和减法
// 注意:最高位的位置和位数要匹配。hp hp::operator + (const hp &b) const{hp c;c.num[0] = max(num[0], b.num[0]);for (int i=1;i<=c.num[0];i++){c.num[i]+=num[i]+b.num[i];if (c.num[i]>=10000)// 进位{c.num[i]-=10000;c.num[i+1]++;}}if (c.num[c.num[0]+1]>0) c.num[0]++;// 9999+1,计算完成后多了一位return c;}hp hp::operator - (const hp &b) const{hp c;c.num[0] = num[0];for (int i=1;i<=c.num[0];i++){c.num[i]+=num[i]-b.num[i];if (c.num[i]<0)// 退位{c.num[i]+=10000;c.num[i+1]--;}}while (c.num[c.num[0]]==0&&c.num[0]>1) c.num[0]--;// 100000000-99999999return c;}hp & hp::operator += (const hp &b) {return *this=*this+b;}hp & hp::operator -= (const hp &b) {return *this=*this-b;}
2. 乘法
hp hp::operator * (const hp &b) const{hp c;c.num[0] = num[0]+b.num[0]+1;for (int i=1;i<=num[0];i++){for (int j=1;j<=b.num[0];j++){c.num[i+j-1]+=num[i]*b.num[j];// 和小学竖式的算法一模一样c.num[i+j]+=c.num[i+j-1]/10000;// 进位c.num[i+j-1]%=10000;}}while (c.num[c.num[0]]==0&&c.num[0]>1) c.num[0]--;// 99999999*0return c;}hp & hp::operator *= (const hp &b) {return *this=*this*b;}
3. 除法
高精度除法的使用频率不太高。
以下代码的缺陷是:如果b太大,运算速度会非常慢。该问题可以用二分查找解决。
hp hp::operator / (const hp &b) const{hp c, d;c.num[0] = num[0]+b.num[0]+1;d.num[0] = 0;for (int i=num[0];i>=1;i--){// 以下三行的含义是:d=d*10000+num[i];memmove(d.num+2, d.num+1, sizeof(d.num)-sizeof(int)*2);d.num[0]++;d.num[1]=num[i];// 以下循环的含义是:c.num[i]=d/b; d%=b;while (d >= b){d-=b;c.num[i]++;}}while (c.num[c.num[0]]==0&&c.num[0]>1) c.num[0]--;// 99999999/99999999return c;}hp hp::operator % (const hp &b) const{……// 和除法的代码一样。唯一不同的地方是返回值:return d;}hp & hp::operator /= (const hp &b) {return *this=*this/b;}hp & hp::operator %= (const hp &b) {return *this=*this%b;}
4. 二分优化的除法
高精度除法速度慢,就慢在上面的while (d>=b)处。如果我们用二分法去猜d/b的值,速度就快了。
hp hp::operator / (const hp& b) const{hp c, d;c.num[0] = num[0]+b.num[0]+1;d.num[0] = 0;for (int i=num[0];i>=1;i--){// 以下三行的含义是:d=d*10000+num[i];memmove(d.num+2, d.num+1, sizeof(d.num)-sizeof(int)*2);d.num[0]++;d.num[1]=num[i];// 以下循环的含义是:c.num[i]=d/b; d%=b; 利用二分查找求c.num[i]的上界。// 注意,这里是二分优化后除法和朴素除法的区别!int left=0, right=9999, mid;while (left < right){mid = (left+right)/2;if (b*hp(mid) <= d) left=mid+1;else right=mid;}c.num[i]=right-1;d=d-b*hp(right-1);}while (c.num[c.num[0]]==0&&c.num[0]>1) c.num[0]--;// 99999999/99999999return c;// 求余数就改成return d;}
(5) 输入/输出
有了这两段代码,就可以直接用cout和cin输出、输入高精度数了。
ostream & operator << (ostream & o, hp &n){o<<n.num[n.num[0]];for (int i=n.num[0]-1;i>=1;i--){o.width(4);o.fill('0');o<<n.num[i];}return o;}istream & operator >> (istream & in, hp &n){char s[MAX];in>>s;n=s;return in;}
[1] 不使用宏定义,也可以用typedef long long hp;
0 0
- 高精度重载运算符的C++代码
- [C++]高精度 bign (重载运算符版本)
- 高精度之重载运算符
- 高精度重载运算符模板
- 高精度运算(运算符重载)
- 运算符+-*/的重载代码
- c++-运算符的重载
- C++--运算符的重载
- 高精度加法(重载运算符)
- 重载“+-*/”实现高精度运算
- [C/C++]运算符的重载
- 运算符重载的实现代码
- C++-运算符重载
- [C++]重载运算符
- C#:运算符重载
- c++-++运算符重载
- C++:重载运算符
- 运算符重载(C++)
- 强类型语言和弱类型语言
- Selenium IDE录制测试弹出窗口
- Android开源项目(1)
- Make menuconfig 详解
- Android:Layout_weight的深刻理解
- 高精度重载运算符的C++代码
- CArray,CMap,CList 速度比较
- android加速度,重力传感器监听器传来的数值
- 设置webview 的字体大小,字体颜色和页面背景
- java设计模式基本原则
- Android NDK
- nodejs v8中的回调机制
- Win8安装SQL Server 2008 R2-Express Edition.txt
- ZKFailoverController( zkfc)介绍