闲2

/*********************************************************************************************************
文件名称 : bignum.c
建立时间 : 2006-2-11 14:28
版权所有 : 东软股份大连分公司电信事业开发部
Author   : 中介部.吴喆喆
文件描述 :
  程序功能:大数之间的加减运算
    接口函数:
     char *Add(char *str1,char *str2); //大数str1加上大数str2
          char *dec(char *str1,char *str2); //大数str1减去大数str2
     说    明:
     1. 这里所谓的大数是指大于2的31次方幂的正整数,用字符串表示
             2. 测试减法的时候被减数大于减数
             3. 例如  "78952584131420"+ "144897874655487"
                   = "223850458786907";
                     "144897874655487" - "78952584131420"
                   = "65945290524067";
             4. 接口函数中原字符串不发生改变,返回值是计算结果
                   (字符串)的头指针

 
修改记录 :
========================================================================================================
序号 修改日期    修改人 修改原因
1. 2006-2-11 15:17  优化
*********************************************************************************************************/
#include <stdlib.h>
#include <string.h>

void reverse(char *);
void reverse(char *cret)
{
 char ch;
 int i;
 int len;
 
 i = 0;
 len = strlen(cret);
 while (i < strlen(cret)/2)
 {
  --len;
  ch = cret[i];
  cret[i] = cret[len];
  cret[len] = ch;  
  ++i;
 }
}


char *Add(char *cstr1,char *cstr2)
{
 char *bp1, *bp2;
 char *ep1, *ep2;
 int i1, i2, i3;
 int flag = 0;  /*flag表示进位*/
 static char *ret;
 char tmp[3];
 char temp[100];
 char str1[100];  /*cstr1的副本*/ /*创建副本的目的是为了有足够的空间进行交换, cstr1和cstr2长度不同所致*/
 char str2[100];  /*cstr2的副本*/
 
 strcpy(str1, cstr1);
 strcpy(str2, cstr2);
 /*为了下面的简化, 保持str1的长度始终小于等于str2的长度, 执行str1和str2的交换*/
 if (strlen(str1) > strlen(str2))
 {
  strcpy(temp, str1);
  strcpy(str1, str2);
  strcpy(str2, temp);
 }
 
 bp1 = str1;
 bp2 = str2;
 ep1 = str1 + strlen(str1);
 ep2 = str2 + strlen(str2);
 ret = (char *)malloc(20);
 memset(ret, 0, 20);
 
 do
 {
  --ep1;
  --ep2;
  
  i1 = (*ep1) ^ '0';
  i2 = (*ep2) ^ '0';
  i3 = i1 + i2 + flag; /*flag表示进位*/
  flag = 0;  /*进位完后重置flag为0*/ 
  sprintf(tmp, "%d", i3);
   
  if (i3 < 10)  /*无进位直接写入数组中*/
   strcat(ret, tmp);
  else   /*有进位*/
  {
   ++flag;  /*表示有进位*/
   memcpy(ret+strlen(ret), &tmp[1], 1);
  }
  
  
 } while (ep1 != bp1);
 
 if (ep2 == bp2)  /*必须要有, 这说明str2经过上面的已经到了最后一位, 可以返回了*/
 {
  if (flag != 0)
   memcpy(ret+strlen(ret), &tmp[0], 1);
  
  reverse(ret);
  return ret; 
 }
 else   /*str2还有数字没拷贝完*/
 {
  do
  {
   --ep2;
   if (flag != 0) /*有进位, 前面导致的*/
   {
    i2 = (*ep2) ^ '0';
    i3 = i2 + flag;
    flag = 0; /*flag重置*/
    sprintf(tmp, "%d", i3);
    
    if (i3 < 10) /*无进位*/
     strcat(ret, tmp);
    else
    {
     flag = 1;
     memcpy(ret+strlen(ret), &tmp[1], 1);
     
     if (ep2 == bp2)  /*如果是最后的, 要加上进位*/
      memcpy(ret+strlen(ret), &tmp[0], 1);
    }
   }
   else   /*没有进位就简单了, 这样就可以了*/
    memcpy(ret+strlen(ret), ep2, 1);
  } while (ep2 != bp2);
  
 }
 
 reverse(ret);
 return ret;
}

char *Dec(char *cstr1,char *cstr2)
{
 char *bp1, *bp2;
 char *ep1, *ep2;
 int i, i1, i2, i3;
 int flag = 0, ch = 0;  /*flag表示借位, ch表示是否借位*/
 static char *ret;
 char temp[100];
 char str1[100];  /*cstr1的副本*/ /*创建副本的目的是为了有足够的空间进行交换, cstr1和cstr2长度不同所致*/
 char str2[100];  /*cstr2的副本*/
 
 strcpy(str1, cstr1);
 strcpy(str2, cstr2);
 /*为了下面的简化, 保持str1的长度始终小于等于str2的长度, 执行str1和str2的交换*/
 if (strlen(str1) >= strlen(str2))
 {
  if (strlen(str1) == strlen(str2)) /*要使str2是较大的数, 如果有这样两个数9和6也是要交换的*/
  {
   for (i = 0; i < strlen(str1); ++i)
   {
    if (str1[i] > str2[i]) /*要使str2是较大的数, 如果有这样两个数19和16也是要交换的*/
    {
     strcpy(temp, str1);
     strcpy(str1, str2);
     strcpy(str2, temp);
     ch = 1;  /*表示交换过, 前面要有负号的*/
     break;
    }
   
   }
  }
  else   /*说明str1是大于str2的, 交换*/
  {
   strcpy(temp, str1);
   strcpy(str1, str2);
   strcpy(str2, temp);
   ch = 1;
  }
 }
 
 bp1 = str1;
 bp2 = str2;
 ep1 = str1 + strlen(str1);
 ep2 = str2 + strlen(str2);
 ret = (char *)malloc(20);
 memset(ret, 0, 20);
 
 do
 {
  --ep1;
  --ep2;
  
  i1 = (*ep1) ^ '0'; /*较小者*/
  i2 = (*ep2) ^ '0'; /*较大者*/
  if (i2 >= i1)
  {
   if ((i2 == i1) && flag)  /*要借位*/
   {
    i2 += 10;
    i3 = i2  - flag - i1;
   }
   else
   {
    i3 = i2 - flag - i1; /*flag表示借位*/
    flag = 0;
   }
  }
  else
  { if (flag && i2 == 0)  //特殊情况, 100-99这种
   {
    i2 = 9;   //借位减1后就是9了, 就是10-1
    i3 = i2 - i1;
   }
   else
   {
    if (flag)  //1010-999这种情况
     --i2;
    flag = 1;
    i2 += 10;
    i3 = i2 - i1;
   }
  }
  
  sprintf(ret+strlen(ret), "%d", i3);
  
  
 } while (ep1 != bp1);
 
 --ep2;
 while (ep2 >= bp2)
 {
  i2 = *ep2 ^ '0';
  if (flag)
  {
   if (i2 >= flag)
   {
    sprintf(ret+strlen(ret), "%d", i2-flag);
    flag = 0; 
   }
   else
   {
    flag = 1;
    i2 += 10;
    i3 = i2 - flag;
    sprintf(ret+strlen(ret), "%d", i3);
   }
  }
  else
   sprintf(ret+strlen(ret), "%d", i2);
  --ep2;
 }
 
 if (ch)
  sprintf(ret+strlen(ret), "%s", "-");
 reverse(ret);
 
 return ret;
}


int main(void)
{
 
 //char str1[] = "144897874655487";
 //char str2[] = "78952584131420";
 char str1[] = "99";
 char str2[] = "1000";
 char *p;
 p = Dec(str1, str2);
 
 printf("%s/n", p);
 
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值