高精度运算一(两个数的运算)

#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操作实现,必须进行算法上的实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值