问题描述:
在计算机中,由于处理器位宽限制,只能处理有限精度的十进制整数加减法,比如在32位宽处理器计算机中,参与运算的操作数和结果必须在-231~231-1之间。如果需要进行更大范围的十进制整数加法,需要使用特殊的方式实现,比如使用字符串保存操作数和结果,采取逐位运算的方式。如下:
9876543210 + 1234567890 = ?
让字符串 num1="9876543210",字符串 num2="1234567890",结果保存在字符串 result = "11111111100"。
-9876543210 + (-1234567890) = ?
让字符串 num1="-9876543210",字符串 num2="-1234567890",结果保存在字符串 result = "-11111111100"。
要求编程实现上述高精度的十进制加法。
要求实现函数:
void add (const char *num1, const char *num2, char *result)
【输入】num1:字符串形式操作数1,如果操作数为负,则num1[0]为符号位'-'
num2:字符串形式操作数2,如果操作数为负,则num2[0]为符号位'-'
【输出】result:保存加法计算结果字符串,如果结果为负,则result[0]为符号位。
注:
I、 当输入为正数时,'+'不会出现在输入字符串中;当输入为负数时,'-'会出现在输入字符串中,且一定在输入字符串最左边位置;
II、输入字符串所有位均代表有效数字,即不存在由'0'开始的输入字符串,比如"0012", "-0012"不会出现;
III、要求输出字符串所有位均为有效数字,结果为正或0时'+'不出现在输出字符串,结果为负时输出字符串最左边位置为'-'。
示例
输入:num1 = "580"
num2 = "-50"
输出:result = "530"
输入:num1 = "580"
num2 = "-600"
输出:result = "-20"
/*
* 将字符串倒置,去除尾部的零
*/
void reverse(char *result )
{
char temp ;
unsigned int size = strlen(result) ;
unsigned int i ;
char *p = result + size - 1;
// cout << "before reverse : "<< result <<endl ;
while(*p == '0')
{
size -- ;
p -- ;
}
result[size] = '\0' ;
for(i = 0; i < size / 2; i++)
{
temp = result[i] ;
result[i] = result[size - i - 1];
result[size - i- 1] = temp ;
}
}
/*
*将num1 与num2字符串 代数相加,结果存储在result中,两个字符串必须为长
*整数字符串,不可以夹杂非数字字母;
*分四种情况讨论 ++;--;+-;-+
*操作时,从字符串的尾部开始,即从长整数的最低位开始操作;
*完成以后,通过reverse函数将字符串倒置即可
*/
void add (const char *num1, const char *num2, char *result)
{ //商 余数
char consult = 0 ,residue = 0 ;
//分别存储商和余数,余数为相加后相应位的结果,商为进位值
const char *p1, *p2;
char *pres ;
unsigned int strLen1 = strlen(num1);
unsigned int strLen2 = strlen(num2) ;
p1 = num1 + strLen1 - 1; //point to the last one
p2 = num2 + strLen2 - 1; //point to the last one
pres = result ; //need reverse at the end of corperation
// unsigned int index = 0;
//第一种情况:两个均为正数
if(num1[0] != '-' && num2[0] != '-') // two positive num
{
while (p1 >= num1 && p2 >= num2) // add to last one num
{ //*p1 - 0x30 ;;*p2 - 0x30为数字值
residue = ( *p1 + *p2 + consult - 0x30 - 0x30) % 10 ; //余数
*pres = residue + 0x30 ;//更新和 为 字符
pres ++ ;
consult = ( *p1 + *p2 + consult - 0x30 - 0x30) / 10 ;//进位
p1 -- ;
p2 -- ;
}
while(p1 >= num1) // num1 not over
{
residue = (*p1 + consult - 0x30) % 10 ;
*pres = residue + 0x30 ;
pres ++ ;
consult = (*p1 + consult - 0x30) / 10 ;
p1 -- ;
}
while(p2 >= num2) // num2 not over
{
residue = (*p2 + consult - 0x30) % 10 ;
*pres = residue + 0x30 ;
pres ++ ;
consult = (*p2 + consult - 0x30) / 10 ;
p2 -- ;
}
//最后,根据进位值进行判断
if(consult != 0)
{
*pres = consult + 0x30 ;
pres ++ ;
}
pres = '\0' ;
}//一正一负,此种情况最为复杂
else if(num1[0] == '-' && num2[0] != '-')//first negtive second positive
{
while(p1 > num1 && p2 >= num2)
{ //两数相减,并减去错位
residue = *p2 - *p1 - consult ;//还需要减去错位consult
if(residue >= 0)//结果无错位
{
*pres = residue + 0x30 ;//更新和为 字符
pres ++ ;
consult = 0 ; //无错位
}
else //需要借位
{
residue += 10 ;//更新结果为正数
*pres = residue + 0x30 ;//更新和为 字符
pres ++ ;
consult = 1 ; //需要借位
}
p1 -- ;
p2 -- ;
}
while (p2 >= num2) //正数大于负数,结果为正
{
residue = *p2 - 0x30 - consult ;
if(residue >= 0)
{
*pres = residue + 0x30 ;//更新和为 字符
pres ++ ;
consult = 0 ; //无错位
}
else
{
residue += 10 ;//更新结果
*pres = residue + 0x30 ;//更新和为 字符
pres ++ ;
consult = 1 ; //需要借位
}
p2 -- ;
}
while(p1 > num1) //负数大于正数,结果为负
{//结果为负时,需要特殊处理
residue = 0x30 - *p1 - consult ;//持续借位相减
if(residue >= 0)
{
*pres = residue + 0x30 ;
pres ++ ;
consult = 0 ;
}
else
{
residue += 10 ;//将值更新为正数
*pres = residue + 0x30 ;
pres ++ ;
consult = 1 ;
}
p1 -- ;
}
//最终结果正还是负?
if(consult == 1) //最终的错位值为1,结果为负的
{ //对得到的结果进行求补操作
consult = 0 ;
*pres = '\0' ; //end of num
pres = result ;
//cout << result << endl ;
while(*pres == '0')//stay unchanged 当尾部为零时,保持不变
{
pres ++ ;
}
//第一次遇到非零值时,先计算该位的值,然后将借位值置一
while(*pres != '\0')
{
residue = 0x30 - *pres - consult;
*pres = residue + 10 + 0x30 ;
pres ++ ;
consult = 1 ;
}
*pres = '-' ;
*(++pres) = '\0';
}
else //positive
{
*pres = '\0' ;
}
}
else if(num1[0] != '-' && num2[0] == '-')//first positive second negtive
{
while(p1 >= num1 && p2 > num2)
{ //两数相减,并减去错位
residue = *p1 - *p2 - consult ;
if(residue >= 0)//结果无错位
{
*pres = residue + 0x30 ;//更新和为 字符
pres ++ ;
consult = 0 ; //无错位
}
else //需要借位
{
residue += 10 ;//更新结果
*pres = residue + 0x30 ;//更新和为 字符
pres ++ ;
consult = 1 ; //需要借位
}
p1 -- ;
p2 -- ;
}
while (p2 > num2) //负数大于正数,结果为负
{
residue = 0x30 - *p2 - consult ;
if(residue >= 0)
{
*pres = residue + 0x30 + 10;
pres ++ ;
consult = 0 ;
}
else
{
residue += 10 ;
*pres = residue + 0x30 ;
pres ++ ;
consult = 1 ;
}
p2 -- ;
}
while(p1 >= num1) //正数大于负数,结果为正
{
residue = *p1 - 0x30 - consult ;
if(residue >= 0)
{
*pres = residue + 0x30 ;//更新和为 字符
pres ++ ;
consult = 0 ; //无错位
}
else
{
residue += 10 ;//更新结果
*pres = residue + 0x30 ;//更新和为 字符
pres ++ ;
consult = 1 ; //需要借位
}
p1 -- ;
}
//最终结果正还是负?
if(consult == 1) //negtive
{
consult = 0 ;
*pres = '\0' ; //end of num
pres = result ;
cout << result << endl ;
while(*pres == '0')//stay unchanged
{
pres ++ ;
}
while(*pres != '\0')
{
residue = 0x30 - *pres - consult;
*pres = residue + 10 + 0x30 ;
pres ++ ;
consult = 1 ;
}
*pres = '-' ;
*(++pres) = '\0';
}
else //positive
{
*pres = '\0' ;
}
}
else //two negtive ,最低位为符号位
{
while (p1 > num1 && p2 > num2) // add to last one num,ont include sign num
{ //*p1 - 0x30 为数字值
residue = ( *p1 + *p2 + consult - 0x30 - 0x30) % 10 ; //余数
*pres = residue + 0x30 ;//更新和为 字符
pres ++ ;
consult = ( *p1 + *p2 + consult - 0x30 - 0x30) / 10 ;//进位
p1 -- ;
p2 -- ;
}
while(p1 > num1) // num1 not end
{
residue = (*p1 + consult - 0x30) % 10 ;
*pres = residue + 0x30 ;
pres ++ ;
consult = (*p1 + consult - 0x30) / 10 ;
p1 -- ;
}
while(p2 > num2) // num2 not end
{
residue = (*p2 + consult - 0x30) % 10 ;
*pres = residue + 0x30 ;
pres ++ ;
consult = (*p2 + consult - 0x30) / 10 ;
p2 -- ;
}
if(consult != 0)
{
*pres = consult + 0x30 ;
pres ++ ;
*pres = '-' ;
pres ++ ;
}
else
{
*pres = '-' ;
pres ++ ;
}
*pres = '\0' ;
}
reverse(result) ;
}