A + B(Ⅱ)| 2022.8.22

题目描述:

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疯了,细节多到真是没得说。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值