题目描述:
Description
龙龙觉得之前的二进制加法可能对你来说太简单了,正好你也学完了“字符串处理”专题,那么就来考验一下你对大数加法的熟练程度吧?下面举一个实数加法运算的实例:2.01
+ 1.0
-------
3.01
请你模拟这个过程。Input
第一行输入一个实数 a 表示加数,第二行输入一个实数 b 表示被加数,保证输入实数的长度 |a| , |b| ≤1000,而且 a 和 b 非负,可能会有前导零和后导零出现。Output
请模拟实数加法,按题目描述的格式输出正确的运算结果,注意换行,没有多余的空格和换行。Hint
前后导零:略
输出格式:略
前置代码如下:
#include <stdio.h>
#include <string.h>
#define N 1010
char a[N],b[N],result[N];
char a1[N],b1[N],a2[N],b2[N],result1[N],result2[N];
int carry=0; //carry表示进位
int main() {
scanf("%s",&a);
scanf("%s",&b);
int a_dot,b_dot;
//a_dot和b_dot的含义记录小数点在第几位
其中,字符串a和b分别是两个加数,result是两个数相加的结果。
a1、b1、result1是整数部分,a2、b2、result2是小数部分。
整体思路如下:
第一步,读入a和b;
第二步,找到小数点;
第三步,以小数点为分界拆分为整数部分和小数部分,并且分别存储在a1、a2,b1、b2中;
第四步,分别计算两部分的和,并且存储在result1和result2中;
第五步,按格式输出。
使用这个思路,关键就是①判断有无小数点 ②小数点在哪里 ③输出格式
代码的每一步都要围绕“有没有小数点”进行分情况讨论!!
第二步和第三步可以一起写,以a为例:
//判断a是否存在小数点,并且拆分为整数部分a1和小数部分a2
int k;
//k用来遍历字符串a
if ( strstr(a,".") ) {
//有小数点的情况
k=0;
//获得a1
while ( a[k] != '.' ) {
a1[k] = a[k];
k++;
}
a1[k] = '\0';
a_dot = k;
//a_dot表示小数点在第几位
//获得a2
k++;
int i=0;
while ( a[k] != '\0' ) {
a2[i] = a[k];
k++; i++;
} a2[i] = '\0';
//有一种极为特殊的情况,就是a1有前置零或者全为零,需要把前置的零去掉。
k=0;
while ( a1[k] == '0' ) k++;
for (i=0;i<=a_dot-k;i++) {
a1[i]=a1[i+k];
}
if (a1[0]=='\0') {
a1[0]='0'; a1[1]='\0';
}
}
else {
//没有小数点
int i = 0 , len_a = strlen(a);
a_dot = 0; //0表示没有小数点
while ( a[i] == '0' ) i++;
//同样是排除掉前置零或全为零的情况。
if ( i == len_a ) {
a1[0]='0'; a1[1]='\0';
}
else {
int j=0;
while ( i < len_a ) {
a1[j] = a[i];
i++; j++;
}
}
}
//注意,当a没有小数点的时候,a2是一个空的字符串
用几乎一模一样的代码可以将b拆分为两个部分,此处做略。
第四步,计算两部分的和,是代码的核心部分,但我在写的时候也遇到了一些小问题:
一、需要注意的是进位的问题。我建议先处理小数部分,因为小数部分可能向整数部分进位。
二、整数部分最前端要提前预留出一个空位,可能会有进位。
注意这两个小细节,代码不难写出:
//分别计算两部分的和
int flag;
//flag表示结果中小数部分的状态;flag=0表示没有小数,flag=1表示有小数。
//计算小数部分的和
carry = 0;
int len_a2 = a_dot > 0 ? strlen(a2) : 0 ;
int len_b2 = b_dot > 0 ? strlen(b2) : 0 ;
//len_a2和len_b2表示两个子串的长度
//len是a2和b2中的较长者,计算时的精度以这个为准
int len = len_a2 > len_b2 ? len_a2 : len_b2 ;
//如果len=0,表明没有小数,也就是flag=0,且result2为空字符串
if (len==0) {
flag = 0;
}
//否则有小数,flag=1,且逐个字符进行加法计算
else {
flag = 1;
for (int i=len-1;i>=0;i--) {
//有数字就加,没有数字按0算
a2[i] = ( a2[i]>='0' && a2[i]<='9' ) ? a2[i] : '0';
b2[i] = ( b2[i]>='0' && b2[i]<='9' ) ? b2[i] : '0';
result2[i] = a2[i] + b2[i] - '0' + carry;
carry = 0;
//判断是否有进位
if ( result2[i]>'9' ) {
result2[i] = result2[i] - 10;
carry = 1;
}
}
}
result2[len] = '\0';
//计算整数部分的和
int len;
int len_a1=strlen(a1) , len_b1=strlen(b1) ;
len = len_a1 > len_b1 ? len_a1 : len_b1 ;
for (int i=len;i>0;i--) {
//有数字直接相加,没有数字按0来加
a1[i] = i >= len - len_a1 + 1 ? a1[i-(len-len_a1)-1] : '0' ;
b1[i] = i >= len - len_b1 + 1 ? b1[i-(len-len_b1)-1] : '0' ;
result1[i] = a1[i] + b1[i] - '0' + carry;
carry = 0;
//进位
if ( result1[i]>'9' ) {
result1[i] = result1[i] - 10;
carry = 1;
}
}
//不论最高位有没有进位,都把最高位计算出来
result1[0] = carry + '0';
result1[len+1] = '\0';
//如果最高位是0,则去掉最高位(后面的字符依次前移一位)
if (result1[0]=='0') {
for (int i=0;i<=len;i++) {
result1[i] = result1[i+1];
}
}
第五步,输出。
输出之前我们要做一些准备。
int len1 = strlen(result1) , len2 = strlen(result2);
int interger_length;
//len1和len2是result的整数部分和小数部分的长度
//interger_length是小数点前面的部分所占的长度(包括空格和加号)。
//有小数点输出和无小数点输出的两种情况,他们的interger_length的算法是不一样的。
if ( a_dot * b_dot == 0 ) {
if ( flag == 0 ) interger_length = strlen(a) > strlen(b) ? strlen(a) : strlen(b) ;
else if ( a_dot == 0 ) interger_length = strlen(a) > b_dot ? strlen(a) : b_dot ;
else interger_length = a_dot > strlen(b) ? a_dot : strlen(b) ;
}
else interger_length = a_dot > b_dot ? a_dot : b_dot ;
if ( len1 > interger_length ) interger_length = len1 ;
//算上一个加号和两个空格所占的长度
interger_length = interger_length + 3 ;
int output_length = interger_length + len2 + flag ;
//output_length是输出的总长度(包括空格、整数部分、小数点和小数部分)
然后一行一行输出即可:
//输出第一行。同样要分为有小数点和没有小数点的情况。
if (a_dot>0) {
for (int i=0;i<interger_length-a_dot;i++) putchar(' ');
printf("%s",a);
for (int i=0;i<a_dot+len2+flag-strlen(a);i++) putchar(' ');
}
else {
for (int i=0;i<interger_length-strlen(a);i++) putchar(' ');
printf("%s",a);
if (flag==1) for (int i=0;i<len2+1;i++) putchar(' ');
}
putchar('\n');
//输出第二行。同样要分为有小数点和没有小数点的情况。
putchar('+');
if (b_dot>0) {
for (int i=1;i<interger_length-b_dot;i++) putchar(' ');
printf("%s",b);
for (int i=0;i<b_dot+len2+flag-strlen(b);i++) putchar(' ');
}
else {
for (int i=1;i<interger_length-strlen(b);i++) putchar(' ');
printf("%s",b);
if (flag==1) for (int i=0;i<len2+1;i++) putchar(' ');
}
putchar('\n');
//输出横杠
for (int i=0;i<output_length;i++) putchar('-');
putchar('\n');
//输出结果
for (int i=0;i<interger_length-len1;i++) putchar(' ');
printf("%s",result1);
if ( flag == 1 ) {
printf(".%s",result2);
}
putchar('\n');
完整代码如下
#include <stdio.h>
#include <string.h>
#define N 1010
char a[N],b[N],result[N];
char a1[N],b1[N],a2[N],b2[N],result1[N],result2[N];
int carry=0; //carry表示进位
int main() {
scanf("%s",&a);
scanf("%s",&b);
int a_dot,b_dot;
{ int k;
if ( strstr(a,".") ) {
k=0;
while ( a[k] != '.' ) {
a1[k] = a[k];
k++;
}
a1[k] = '\0';
a_dot = k;
k++;
int i=0;
while ( a[k] != '\0' ) {
a2[i] = a[k];
k++; i++;
} a2[i] = '\0';
k=0;
while ( a1[k] == '0' ) k++;
for (i=0;i<=a_dot-k;i++) {
a1[i]=a1[i+k];
}
if (a1[0]=='\0') {
a1[0]='0'; a1[1]='\0';
}
}
else {
int i = 0 , len_a = strlen(a);
a_dot = 0;
while ( a[i] == '0' ) i++;
if ( i == len_a ) {
a1[0]='0'; a1[1]='\0';
}
else {
int j=0;
while ( i < len_a ) {
a1[j] = a[i];
i++; j++;
}
}
}
if ( strstr(b,".") ) {
k=0;
while ( b[k] != '.' ) { b1[k] = b[k]; k++; }
b1[k] = '\0';
b_dot = k;
k++;
int i=0;
while ( b[k] != '\0' ) {
b2[i] = b[k];
k++; i++;
} b2[i] = '\0';
k=0;
while ( b1[k] == '0' ) k++;
for (i=0;i<=b_dot-k;i++) {
b1[i]=b1[i+k];
}
if (b1[0]=='\0') {
b1[0]='0'; b1[1]='\0';
}
}
else {
int i = 0 , len_b = strlen(b);
b_dot = 0;
while ( b[i] == '0' ) i++;
if ( i == len_b ) {
b1[0]='0'; b1[1]='\0';
}
else {
int j=0;
while ( i < len_b ) {
b1[j] = b[i];
i++; j++;
}
}
}
}
//分别计算两部分的和
int flag; //flag表示结果中小数部分的状态;flag=0表示没有小数,flag=1表示有小数。
{ //计算小数部分的和
carry = 0;
int len_a2 = a_dot > 0 ? strlen(a2) : 0 ;
int len_b2 = b_dot > 0 ? strlen(b2) : 0 ;
int len = len_a2 > len_b2 ? len_a2 : len_b2 ;
if (len==0) {
flag = 0;
}
else {
flag = 1;
for (int i=len-1;i>=0;i--) {
a2[i] = ( a2[i]>='0' && a2[i]<='9' ) ? a2[i] : '0';
b2[i] = ( b2[i]>='0' && b2[i]<='9' ) ? b2[i] : '0';
result2[i] = a2[i] + b2[i] - '0' + carry;
carry = 0;
if ( result2[i]>'9' ) {
result2[i] = result2[i] - 10;
carry = 1;
}
}
}
result2[len] = '\0';
}
{ //计算整数部分的和
int len;
int len_a1=strlen(a1) , len_b1=strlen(b1) ;
len = len_a1 > len_b1 ? len_a1 : len_b1 ;
for (int i=len;i>0;i--) {
a1[i] = i >= len - len_a1 + 1 ? a1[i-(len-len_a1)-1] : '0' ;
b1[i] = i >= len - len_b1 + 1 ? b1[i-(len-len_b1)-1] : '0' ;
result1[i] = a1[i] + b1[i] - '0' + carry;
carry = 0;
if ( result1[i]>'9' ) {
result1[i] = result1[i] - 10;
carry = 1;
}
}
result1[0] = carry + '0';
result1[len+1] = '\0';
if (result1[0]=='0') {
for (int i=0;i<=len;i++) {
result1[i] = result1[i+1];
}
}
}
//输出
int len1 = strlen(result1) , len2 = strlen(result2);
int interger_length;
if ( a_dot * b_dot == 0 ) {
if ( flag == 0 ) interger_length = strlen(a) > strlen(b) ? strlen(a) : strlen(b) ;
else if ( a_dot == 0 ) interger_length = strlen(a) > b_dot ? strlen(a) : b_dot ;
else interger_length = a_dot > strlen(b) ? a_dot : strlen(b) ;
}
else interger_length = a_dot > b_dot ? a_dot : b_dot ;
if ( len1 > interger_length ) interger_length = len1 ;
interger_length = interger_length + 3 ;
int output_length = interger_length + len2 + flag ;
if (a_dot>0) {
for (int i=0;i<interger_length-a_dot;i++) putchar(' ');
printf("%s",a);
for (int i=0;i<a_dot+len2+flag-strlen(a);i++) putchar(' ');
}
else {
for (int i=0;i<interger_length-strlen(a);i++) putchar(' ');
printf("%s",a);
if (flag==1) for (int i=0;i<len2+1;i++) putchar(' ');
}
putchar('\n');
putchar('+');
if (b_dot>0) {
for (int i=1;i<interger_length-b_dot;i++) putchar(' ');
printf("%s",b);
for (int i=0;i<b_dot+len2+flag-strlen(b);i++) putchar(' ');
}
else {
for (int i=1;i<interger_length-strlen(b);i++) putchar(' ');
printf("%s",b);
if (flag==1) for (int i=0;i<len2+1;i++) putchar(' ');
}
putchar('\n');
for (int i=0;i<output_length;i++) putchar('-');
putchar('\n');
for (int i=0;i<interger_length-len1;i++) putchar(' ');
printf("%s",result1);
if ( flag == 1 ) {
printf(".%s",result2);
}
putchar('\n');
return 0;
}
总共202行,给我debug疯了,细节多到真是没得说。