计蒜客题解-T1180实数加法

本文详细介绍了如何实现高精度加法,特别是在处理带有小数的数时的方法。首先,通过查找小数点确定其位置,然后进行补0操作以确保两数长度一致。接着,去除小数点并进行高精度加法运算,同时处理可能的进位。最后,处理结果中的后缀0,并输出到第一个非零小数位。解题过程中涉及高精度算法、小数点处理和后缀0的消除等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目概况

链接: https://nanti.jisuanke.com/t/T1180
难度: 普及/提高-(计蒜客评级普及T3)

题目分析

简化题目: 给定两个实数,相加即可
**涉及知识点:**高精度加高精度算法以及一些玄学操作
解题思路:
私以为,这道题本质上就是考察PJT2难度的 高精度算法另加一些 小数的处理,故我们重点讨论如何处理小数:
1. 关于相加,我们可以考虑 去掉小数点直接当成两个高精度整数相加。但如果数据1.999+0.1会被当做1999+1,结果并不符合我们的预期,所以需要在加之前 在后面补0(倒着存肯定就倒着补呗)
2. 关于小数点,我们在相加时去掉了,但输出还是需要的,所以要 记录一下小数点位置。输出小数点的位置应该满足总长度-i-1 == 小数点位置
3. 处理小数部分多余的0,用while循环从第0位起找到 第一个非0位
4. (这一点是突发奇想的,在本题中不会有这种情况)如果我们出现了999.99900 + 0.001000这种情况,相加得1000,但由于处理多余0会结果会变成1,,我们可以尝试把这种情况给处理一下

代码要点拆解

一、数据准备

const int MAXN = 205; 
//100位整数+小数,加起来就是200位,数组要开到200位以上
int len1, len2; 
//记录去掉小数点后的长度
int dot_idx, dot_idx1, dot_idx2; 
//记录长一点的小数点位置;加数的小数点位置;另一个加数的小数点位置(补0时用得上)
int a[MAXN], b[MAXN];
//两个加数(相加用)
string s1, s2;
//两个加数(输入进来的)
string ss1, ss2;
//两个加数(去掉小数点的)

二、寻找小数点

直接用find函数

  //寻找小数点
    dot_idx1 = s1.find('.');
    dot_idx2 = s2.find('.');
    dot_idx = max(dot_idx1, dot_idx2);

三、补0

//补0
   //n1,n2分别是第一(二)个字符串减去第二(一)的字符串的小数位数得到的差
    int n1 = (s1.size() - dot_idx1 - 1) - (s2.size() - dot_idx2 - 1); 
    int n2 = (s2.size() - dot_idx2 - 1) - (s1.size() - dot_idx1 - 1);
    //如果n1>n2,那就是s2的小数部分要补
    if (n1 > n2) {
    	while (n1--) {
    		s2 += '0';
		}
	} else if (n2 > n1) { //反之就是s1的小数部分要补
		while (n2--) {
			s1 += '0';
		}
	} 
	//如果相等就不用补

四、去除小数点

碰到小数点就continue,否则就加上

  for (int i = 0; i < s1.size(); i++) {
        if (s1[i] == '.') continue; 
        else ss1 += s1[i];
    }
    for (int i = 0; i < s2.size(); i++) {
        if (s2[i] == '.') continue;
        else ss2 += s2[i];
    }

五、常规高精度

相信能做到这道题高精度算法你已经敲得滚瓜烂熟了,至于在处理长度变化时加了dot_idx++,是因为如果我们的长度加了,那么小数点位就得后移
比如:
在出现999.99900 + 0.001000的情况时,本来我们的小数点位是3,但是最后结果是1000,因为进位了,所以我们要把小数点位后移至4

    //常规高精度
    len1 = max(len1, len2);
    //相加
    for (int i = 0; i < len1; i++) {
        a[i] += b[i];
    }
    //进位
    for (int i = 0; i < len1; i++) {
        a[i + 1] += a[i] / 10;
        a[i] %= 10;
    }
    //进位引起的长度变化
    while (a[len1]) {
        a[len1 + 1] += a[len1] / 10;
        a[len1] %= 10;
        len1++;
        dot_idx++;
    }

六、处理后缀0

两个判断条件:
1. 当前位也就是a[ending]还是0
2. 当前位没有越过小数点位

  //处理后缀0
  int ending = 0;
    while (a[ending] == 0 && ending <= len1 - dot_idx - 1) {
        ending++;
    }

七、输出操作

与一般地不同,我们只能输出到小数部分的第一个非零位,也就是ending

  for (int i = len1 - 1; i >= ending; i--) {
        if (len1 - i - 1 == dot_idx) { //解题思路中讲了
            cout << '.';
        }
        cout << a[i];
    }

完整代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int MAXN = 205;
int len1, len2;
int dot_idx, dot_idx1, dot_idx2;
int a[MAXN], b[MAXN];
string s1, s2;
string ss1, ss2;


int main() {
    cin >> s1 >> s2;
    //寻找小数点
    dot_idx1 = s1.find('.');
    dot_idx2 = s2.find('.');
    dot_idx = max(dot_idx1, dot_idx2);
    //补0
    int n1 = (s1.size() - dot_idx1 - 1) - (s2.size() - dot_idx2 - 1);
    int n2 = (s2.size() - dot_idx2 - 1) - (s1.size() - dot_idx1 - 1);
    if (n1 > n2) {
    	while (n1--) {
    		s2 += '0';
		}
	} else if (n2 > n1) {
		while (n2--) {
			s1 += '0';
		}
	} 
    //去除小数点
    for (int i = 0; i < s1.size(); i++) {
        if (s1[i] == '.') continue;
        else ss1 += s1[i];
    }
    for (int i = 0; i < s2.size(); i++) {
        if (s2[i] == '.') continue;
        else ss2 += s2[i];
    }
    //存储
    len1 = ss1.size(), len2 = ss2.size();
    for (int i = 0; i < len1; i++) {
        a[i] = ss1[len1 - i - 1] - '0';
    }
    for (int i = 0; i < len2; i++) {
        b[i] = ss2[len2 - i - 1] - '0';
    }
    //常规高精度
    len1 = max(len1, len2);
    for (int i = 0; i < len1; i++) {
        a[i] += b[i];
    }
    for (int i = 0; i < len1; i++) {
        a[i + 1] += a[i] / 10;
        a[i] %= 10;
    }
    while (a[len1]) {
        a[len1 + 1] += a[len1] / 10;
        a[len1] %= 10;
        len1++;
        dot_idx++;
    }
    //处理后缀0
    int ending = 0;
    while (a[ending] == 0 && ending <= len1 - dot_idx - 1) {
        ending++;
    }
    //输出
    for (int i = len1 - 1; i >= ending; i--) {
        if (len1 - i - 1 == dot_idx) {
            cout << '.';
        }
        cout << a[i];
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

oier_Asad.Chen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值