大正数减法(华为2013校园招聘上机笔试题 )

时间:2022-03-31 18:54:49

问题描述:    
两个任意长度的正数相减,这两个正数可以带小数点,也可以是整数,请输出结果。 输入的字符串中,不会出现除了数字与小数点以外的其它字符,不会出现多个小数点以及小数点在第一个字符的位置等非法情况,所以考生的程序中无须考虑输入的数值字符串非法的情况。 
详细要求以及约束:
1.输入均为正数,但输出可能为负数; 
2.输入输出均为字符串形式;
3.如果输出是正数则不需要带符号,如果为负数,则输出的结果字符串需要带负号
例如:2.2-1.1 直接输出为“1.1”,1.1-2.2 则需要输出为“-1.1”
 4.输出的结果字符串需要过滤掉整数位前以及小数位后无效的0,小数位为全0的,直接输出整数位
例如相减结果为11.345,此数值前后均不可以带0,“011.345”或者“0011.34500”等等前后带无效0的均视为错误 输出。例如1.1-1.1结果为0.0,则直接输出0。
要求实现函数:
void Decrease(char *input1, char*input2, char *output)
【输入】 char *iinput1 被减数
char*nput2 减数 
【输出】 char *output 减法结果
【返回】 无
示例
输入:char *input1="2.2" 
char *input2="1.1"
输出:char*output="1.1"
输入:char *input1="1.1" 
char *input2="2.2"
输出:char *output="-1.1"

以上摘自 http://blog.csdn.net/lanyan822/article/details/7983832 ,但是考虑到没有给出这个的源代码,自己随手写了一个,写得不好,仅供娱乐,欢迎大神指点。

 

 

这次的代码很长,我是为了写的可读性更高一点,很多地方比较累赘而且用的方法比较直接,也是我一开始直接想到的。如果有更好的方法希望大家提供哈...

//正数减法
//问题描述:
//两个任意长度的正数相减,这两个正数可以带小数点,也可以是整数,请输出结果。
//输入的字符串中,不会出现除了数字与小数点以外的其它字符,不会出现多个小数点以及小数点在第一个字符的位置等非法情况,所以考生的程序中无须考虑输入的数值字符串非法的情况。
//详细要求以及约束:
//1.输入均为正数,但输出可能为负数;
//2.输入输出均为字符串形式;
//3.如果输出是正数则不需要带符号,如果为负数,则输出的结果字符串需要带负号
//例如:2.2-1.1 直接输出为“1.1”,1.1-2.2 则需要输出为“-1.1”
// 4.输出的结果字符串需要过滤掉整数位前以及小数位后无效的0,小数位为全0的,直接输出整数位
//例如相减结果为11.345,此数值前后均不可以带0,“011.345”或者“0011.34500”等等前后带无效0的均视为错误 输出。例如1.1-1.1结果为0.0,则直接输出0。
//要求实现函数:
//void Decrease(char *input1, char*input2, char *output)
//【输入】 char *iinput1 被减数
//char*nput2 减数
//【输出】 char *output 减法结果
//【返回】 无
//示例
//输入:char *input1="2.2"
//char *input2="1.1"
//输出:char*output="1.1"
//输入:char *input1="1.1"
//char *input2="2.2"
//输出:char *output="-1.1"
#include <algorithm>
#include <assert.h>
//得到小数点的位置
int getDot(char *input1)//小数点计算函数
{
return find(input1,input1+strlen(input1),'.') - input1;
}

void Decrease(char *input1, char*input2, char *output)
{
assert(input1 != NULL && input2 != NULL && output != NULL);//假设三个参数都不为空
//1.小数点对其
int dot1 = getDot(input1),dot2 = getDot(input2);
//2.小数点对其初始化两个char数组,方便之后运算。长度为双方可能的最大位数
int length = ((strlen(input1)-dot1)>(strlen(input2)-dot2)?(strlen(input1)-dot1):(strlen(input2)-dot2))/*小数部分最长的值*/
+(dot1>dot2?dot1:dot2)/*整数部分最长的值*/+1/*可能产生的符号位与小数点*/;
char *str1,*str2,*result;

str1 = (char *)malloc(length+1);//加1为了存结束符
str2 = (char *)malloc(length+1);
result = (char *)malloc(length+1);

memset(str1,'0',length);
memset(str2,'0',length);
memset(result,'0',length);

str1[length] = '\0';
str2[length] = '\0';
result[length] = '\0';

//3.得出每个字符串小数点对其后的位置,但是不拷贝最后一个'\0'结束符
memcpy(&str1[abs(dot1>dot2?dot1:dot2-dot1)+1],input1,strlen(input1));
memcpy(&str2[abs(dot1>dot2?dot1:dot2-dot2)+1],input2,strlen(input2));


//4.得到两数之间较大的数,为了保证始终大数减小数,省的借位情况复杂
int isPlus = true;//如果被减数更大则为真
char *max = str1,*min = str2;
for(int i = 1;i < length;++i)
{
if(str1[i] > str2[i])
{
max = str1;
min = str2;
break;
}
else if(str1[i] < str2[i])
{
isPlus = false;
max = str2;
min = str1;
break;
}
else if(i == length - 1)
{//两个字符串数字相等
output[0] = '0';
output[1] = '\0';
return ;
}
}
//把没有小数点的全部补齐
result[dot1>dot2?dot1:dot2 + 1] = '.';
max[dot1>dot2?dot1:dot2 + 1] = '.';
min[dot1>dot2?dot1:dot2 + 1] = '.';
//5.开始运算
for(int i = length-1;i > 0;--i)
{//开始从右到左开始减
if(max[i] == '.')
{
result[i] == '.';
continue;
}
int temp;
temp = max[i] - min[i];
if(temp < 0)
{//如果不够减时向高位借数
int j = i;
while(max[j] == '0' || max[j] == '.'/* && j != 0*/)
{//找到可以借位的数为止,因为输入的都是整数,所以不做更多讨论
if(max[j] == '0')
{
max[j] = '9';
}
j--;
}
max[j]--;
temp += 10;
}
result[i] = temp + '0';
}
if(!isPlus)
output[0] = '-';
//6.把结果字符格式化给output字符串
for(unsigned int i = strlen(result);i >= 0;++i)
{//清除末尾0或最后一位是小数点
if(result[i] == '0' || result[i] == '.')
result[i] = '\0';
else
break;
}
unsigned int first = 1;//记录第一位有效位的起始位置
while(result[first] == '0')
{
first++;
}
strcpy(output,&result[first]);
}

int _tmain(int argc, _TCHAR* argv[])
{
char r[10000];
Decrease("2.2", "1.1",r);
cout<<r;
return 0;
}