高精度运算一(两个数的运算)
#include <iostream>
#include <string>
#include <sstream>
#include <algorithm>
using namespace std;
#define MAX 20
//两个整数一个为m位,一个为n位,那么它们的和最多为max{m,n}+1位。
//两个高精度整数相加
void Add(char* str1,char* str2,char* res)
{
int i,len1,len2,len;
len1 = strlen(str1);
len2 = strlen(str2);
len = (len1 > len2 ? len1 + 1 : len2 + 1);//将结果设置为可能的最高位数
reverse(str1,str1 + len1);
reverse(str2,str2 + len2);
for(i = 0;i < len;++i)//初始化为0
res[i] = 0;
for(i = 0;i < len;++i)
{
if(i < len1 && i < len2)
{
res[i] += str1[i] - '0' + str2[i] - '0';//采用+=主要是为了避免引入进位变量c,如果某位产生进位直接加到高一位,此时高位不为0
if(res[i] > 9)
{
res[i+1] += 1;
res[i] -= 10;
}
}
else if(i < len1 || i < len2)//i可能取到比len1和len2都大的数,所以要采取这种判断
{
if(i < len1)
{
res[i] += str1[i] - '0';
if(res[i] > 9)
{
res[i+1] += 1;
res[i] -= 10;
}
}
else
{
res[i] += str2[i] - '0';
if(res[i] > 9)
{
res[i+1] += 1;
res[i] -= 10;
}
}
}
}
//去掉结果中的前导0,考虑999-999等自身减自身的情况,只处理到len==1处,不管len==0处是否为0都保存
while(len > 1 && res[len-1] == 0)
--len;
//将res调整为可间字符,并加上结束符
for(i = 0;i < len;++i)
res[i] += '0';
res[len] = '/0';
reverse(res,res + len);
reverse(str1,str1 + len1);
reverse(str2,str2 + len2);
}
//一个高精度加上一个非高精度
void Add(char* str1,int op,char* res)
{
//考虑到最大整型数不会超过15位,开辟一个15个字符的空间,将非高精度整数转换成对应的字符串,以便调用上一个函数
char* str2 = new char[15];
stringstream ss;
ss << op;
ss >> str2;
Add(str1,str2,res);
delete []str2;
}
//比较两个高精度整数的大小
int Cmp(char* str1,char* str2)
{
int i,len1,len2;
len1 = strlen(str1);
len2 = strlen(str2);
if(len1 < len2)
return -1;
else if(len1 > len2)
return 1;
else
{
for(i = 0;i < len1 && str1[i] == str2[i];++i);
if(i == len1)
return 0;
else if(str1[i] > str2[i])
return 1;
else
return -1;
}
}
//
//两个整数一个为m位,一个为n位,那么它们的差最多为max{m,n}位。
//两个高精度整数相减
版本一
void Sub(char* str1,char* str2,char* res)
{
int flag = Cmp(str1,str2);
if(flag == 0)
{
res[0] = '0';
res[1] = '/0';
}
else
{
int i,len1,len2,len;
len1 = strlen(str1);
len2 = strlen(str2);
len = (len1 > len2 ? len1 : len2);//将结果设置成可能的最高位数
reverse(str1,str1 + len1);
reverse(str2,str2 + len2);
if(flag > 0)//str1大于str2时,str2的长度不大于str1的长度
{
for(i = 0;i < len;++i)
res[i] = 0;
for(i = 0;i < len;++i)
{
if(i < len2)
{
res[i] += str1[i] - str2[i];//当前位可能被借走一位而成为负数,所以要用+=
if(res[i] < 0)
{
res[i] += 10;
res[i+1] -= 1;
}
}
else
{
res[i] += str1[i] - '0';
if(res[i] < 0)
{
res[i] += 10;
res[i+1] -= 1;
}
}
}
//去掉前倒0
while(len > 1 && res[len-1] == 0)
--len;
//将res中的内容调整为可见字符,并加上结尾
for(i = 0;i < len;++i)
res[i] += '0';
res[len] = '/0';
reverse(res,res + len);
}
else
{
res[0] = '-';
char* tmp = res + 1;//借助辅助指针,使操作统一
for(i = 0;i < len;++i)
tmp[i] = 0;
for(i = 0;i < len;++i)
{
if(i < len1)
{
tmp[i] += str2[i] - str1[i];
if(tmp[i] < 0)
{
tmp[i] += 10;
tmp[i+1] -= 1;
}
}
else
{
tmp[i] += str2[i] - '0';
if(tmp[i] < 0)
{
tmp[i] += 10;
tmp[i+1] -= 1;
}
}
}
//去掉前导0
while(len > 1 && tmp[len - 1] == 0)
--len;
//将tmp中的字符调整为可见字符,并加上结尾
for(i = 0;i < len;++i)
tmp[i] += '0';
tmp[len] = '/0';
reverse(tmp,tmp + len);
}
reverse(str1,str1 + len1);
reverse(str2,str2 + len2);
}
}
//版本二
void Sub(char* str1,char* str2,char* res)
{
char* tmp = NULL;
int flag = Cmp(str1,str2);
if(flag == 0)
{
res[0] = '0';
res[1] = '/0';
}
else if(flag > 0)
tmp = res;
else
{
tmp = str1;//始终让str1指向较大的数,最终tmp指向res中第一个要填入结果的位置
str1 = str2;
str2 = tmp;
res[0] = '-';
tmp = res + 1;
}
if(tmp != NULL)
{
int i,len1,len2,len;
len1 = strlen(str1);
len2 = strlen(str2);
len = len1;
reverse(str1,str1 + len1);
reverse(str2,str2 + len2);
for(i = 0;i < len;++i)
tmp[i] = 0;
for(i = 0;i < len;++i)
{
if(i < len2)
{
tmp[i] += str1[i] - str2[i];
if(tmp[i] < 0)
{
tmp[i] += 10;
tmp[i+1] -= 1;
}
}
else
{
tmp[i] += str1[i] - '0';
if(tmp[i] < 0)
{
tmp[i] += 10;
tmp[i+1] -= 1;
}
}
}
while(len > 1 && tmp[len-1] == 0)
--len;
for(i = 0;i < len;++i)
tmp[i] += '0';
tmp[len] = '/0';
reverse(tmp,tmp + len);
reverse(str1,str1 + len1);
reverse(str2,str2 + len2);
}
}
//高精度减去非高精度,主要用到转换然后调用前一个实现
void Sub(char* str1,int op,char* res)
{
char* str2 = new char[15];
stringstream ss;
ss << op;
ss >> str2;
Sub(str1,str2,res);
delete []str2;
}
//两个整数一个为m位,一个为n位,那么它们的积最多为m+n位,最少为m+n-1位。
//证明:A为m位,B为n位
//10^(m-1) <= A < 10^m,10^(n-1) <= B < 10^n
//10^(m+n-2) <= A*B < 10^(m+n)
//左侧为m+n-1位数,右侧为m+n+1位数,但是右侧取不到,所以结论成立
void Mul(char* str1,char* str2,char* res)
{
int i,j,len1,len2,len;
len1 = strlen(str1);
len2 = strlen(str2);
len = len1 + len2;//将结果设置成可能的最大位数
for(i = 0;i < len;++i)//初始化为0
res[i] = 0;
reverse(str1,str1 + len1);
reverse(str2,str2 + len2);
for(i = 0;i < len1;++i)
{
for(j = 0;j < len2;++j)
{
res[i+j] += (str1[i] - '0') * (str2[j] - '0');
if(res[i+j] > 9)
{
res[i+j+1] += res[i+j] / 10;
res[i+j] = res[i+j] % 10;
}
}
}
//去掉前导0
while(len > 1 && res[len-1] == 0)
--len;
//将res变为可见字符,并加上结尾
for(i = 0;i < len;++i)
res[i] += '0';
res[len] = '/0';
reverse(res,res + len);
reverse(str1,str1 + len1);
reverse(str2,str2 + len2);
}
//高精度乘以非高精度,用转换调用上一个函数实现
void Mul(char* str1,int op,char* res)
{
char* str2 = new char[15];
stringstream ss;
ss << op;
ss >> str2;
Mul(str1,str2,res);
delete []str2;
}
int main()
{
char str1[MAX],str2[MAX],res[MAX*2];
int op;
while(cin >> str1 >> str2)
{
Mul(str1,str2,res);
cout << str1 << '*' << str2 << '=' << res << endl;
Add(str1,str2,res);
cout << str1 << '+' << str2 << '=' << res << endl;
Sub(str1,str2,res);
cout << str1 << '-' << str2 << '=' << res << endl;
cin >> str1 >> op;
Mul(str1,op,res);
cout << str1 << '*' << op << '=' << res << endl;
Add(str1,op,res);
cout << str1 << '+' << op << '=' << res << endl;
Sub(str1,op,res);
cout << str1 << '-' << op << '=' << res << endl;
}
return 0;
}
思考:
1,有两个字符串str1和str2,他们之间有一个字典序的比较关系记为r1,将它们逆序后又得到一个字典序的比较关系记为r2,r1与r2相同吗?
如果r1为==关系,那么r1与r2相同
如果r1为>或者<,并且都是由于str1与str2的长度不同导致的,那么r1与r2相同
如果r1为>或者<,并且str1与str2的长度相同,那么r1与r2未必相同
例如假设str1:A1A2A3,str2:B1B2B3,且r1为>,那么可以假设A1>B1,A3<B3,逆序后r2为<显然不同,如果A2A3与B2B3的字典序相同,那么逆序后r1与r2相同
2,比较两个数的大小实际是比较两个数的字典序,但是为了计算上的方便都采用了字符串的逆序存储,所以这时就不能直接比较两个逆序串的字典序来比较原先两个数的大小,也不能通过简单的非strcmp操作实现,必须进行算法上的实现。
高精度运算一(两个数的运算)相关推荐
- 位运算求两个数的平均值
一直不理解位运算求两个数的平均值.参考网上资料后终于明白. 如下: 求两个数的平均值的算法:Avg = (ValueA & ValueB) + (ValueA ^ ValueB) >&g ...
- c语言计算1减2的平方分之一,在数学中必须考虑的运算有两类;加法运算与减法运算-数学位于运算-数学-沙人磕同学...
概述:本道作业题是沙人磕同学的课后练习,分享的知识点是数学位于运算,指导老师为江老师,涉及到的知识点涵盖:在数学中必须考虑的运算有两类;加法运算与减法运算_-数学位于运算-数学,下面是沙人磕作业题的详 ...
- 常用技巧 —— 位运算 —— 异或运算实现两个数的交换
[概述] 交换变量时,通常是借助一临时变量来赋值实现 void exchange(int a,int b) {int temp;temp=a;a=b;b=temp; } 当采用异或运算时,实现两变量交 ...
- 运用异或运算实现两个数不通过中间变量交换值的原理分析
或许对于像我现在这样的初学者很多都没见过这个符号 ^ 这个是个异或运算的符号,好的,我们现在开始分析它的运行原理! 异或运算的知识请点击此连接后了解 http://baike.baidu.com/vi ...
- 微信小程序实现两个数之间的运算
微信小程序实现两个数之间的运算 要求:创建一个微信小程序实现两个数字的比较运算.加法运算.减法运算.乘法运算或者除法运算中的一种,效果如图(这里我写的包含了所有运算,可根据需要自行选择): app.j ...
- C语言中临时变量写在哪里,C语言中不允许创建临时变量,交换两个数的内容
在C语言中可以通过建立临时变量来实现两个变量的交换,当不允许建立临时变量时,应该怎样实现两变量的交换呢? 假设有两个变量num1和num2:下面通过两种方法进行分析. 方法一:利用加减法.具体算法分析 ...
- 常见位操作及运算应用举例:1,C语言中位运算符异或“∧”的作用2,异或运算的作用3,(与运算)、|(或运算)、^(异或运算)
1 C语言中位运算符异或"∧"的作用: 异或运算符∧也称XOR运算符.它的规则是若参加运算的两个二进位同号,则结果为0(假):异号则为1(真).即0∧0=0,0∧1=1,1∧1=0 ...
- 异或交换两个数的原理证明
算法 通过异或运算交换两个数 a ^= b b ^= a a ^= b 证明 由异或定义易得: 异或运算满足结合律, 交换律 x ^ x = 0 x ^ ...
- 利用位运算和指针实现的交换两个数的程序
位运算是C语言的一大特色,利用异或运算可以实现交换两个数,原理是一个整数与另外一个数进行两次异或运算仍然是其本身,基本原理用式子表达如下: (1) A ^ A = 0; (2) A = A ^B; ( ...
- java用流体加减乘除_任意输入两个数,完成加法、减法、乘法、除法运算!(加减乘除运算分别定义四个方法)_学小易找答案...
[简答题]编写程序实现菜单设计 [简答题]一层平面图 [简答题]编写一个程序实现大小写字母转换 [简答题]利用循环语句输出一个五行的等腰三角形,如下图 [简答题]编写一个程序实现交换两个变量的数值. ...
最新文章
- 新建本地仓库,同步远程仓场景,出现git branch --set-upstream-to=origin/master master 解决方法...
- 输入设备配置文件(.idc文件)
- REST 在 Java 中的使用
- 《Java 核心技术卷1 第10版》学习笔记------ 类之间的关系
- FTP和TFTP的区别与介绍
- ASP连接11种数据库的常用语法
- eplan备份时卡顿_EPLAN卡顿了怎么办?
- html读mysql数据_html从数据库中读取数据
- 字符串函数 (strfun)
- [BZOJ1031] [JSOI2007] 字符加密Cipher (后缀数组)
- Linux周立功CAN驱动安装指导
- 动软DBUtility类库DbHelperSQLP实现多数据库连接
- JS定时器原理及案例
- Redis 做网页UV统计
- 极域电子教室师生端连接不上怎么解决
- Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000004
- .NET反编译工具Reflector及插件
- VIT实战总结:非常简单的VIT入门教程,一定不要错过
- flea-db使用之JPA分库分表实现
- 制作帮助文档的好助手- WORD2CHM WORD2HTML
热门文章
- [原创]Linux实现服务延迟启动
- LoadRunner 录制常见错误解决方法
- Linux RPM软件包管理
- mysql查询优化~group by知多少
- dtoj#4258. 铃铛计数问题
- LeetCode算法题-Delete Node in a Linked List(Java实现)
- mysql如何把一个表直接拷贝到一个新的表
- 无人编辑,人工智能编辑,AI编辑机器人-资讯频道编辑
- 在spring-boot中使用@ConfigurationProperties
- Nginx https configuration backed Certbot