算法笔记练习 5.6 大整数运算 问题 C: 浮点数加法
题目
题目描述
求2个浮点数相加的和
题目中输入输出中出现浮点数都有如下的形式:
P1P2…Pi.Q1Q2…Qj
对于整数部分,P1P2…Pi是一个非负整数
对于小数部分,Qj不等于0
输入
对于每组案例,第1行是测试数据的组数n,每组测试数据占2行,分别是两个加数。
每组测试数据之间有一个空行,每行数据不超过100个字符
输出
每组案例是n行,每组测试数据有一行输出是相应的和。
输出保证一定是一个小数部分不为0的浮点数
样例输入
2
3.756
90.564
4543.5435
43.25
样例输出
94.32
4586.7935
思路
由于比较抽象,在每一个步骤下面以1.86
和3.14159
相加来举例说明,请搭配例子食用。
步骤:
- 首先获得
bign
类型的ia
,fa
,ib
,fb
,分别表示第一个数的整数部分,小数部分,第二个数的整数部分,小数部分;
(例:输入1.86
和3.14159
,则有ia = 1
,fa = 86
,ib = 3
,fb = 14159
) - 令
ians = ia + ib
;
(例:ians
=ia + ib
=1 + 3
=4
) - 对于
fa
和fb
,把长度较短的那个后面加零对齐;
(例:这里fa
比较短,因为fb
有五位,所以把fa
加长到86000
) - 令
fans = fa + fb
,此处分为最高位有进位和无进位两种情况:
a. 无进位,比较理想的情况,无需特殊处理;
b. 有进位,首先ians
要加1
,其次fans
的最高位上的1
要被抹去;
(例:fans
=fa + fb
=86000 + 14159
=100159
,最高位有进位,那么首先ians
要变成5
,其次fans
要变成00159
) - 删去
fans
末尾所有连续的0
;
(例:这个例子中的fans
没有问题,但假设到这一步fans
是003405000
,要修改为003405
) - 输出
ians
+.
+fan
。
(例:即5.00159
)
代码
#include <cstdio>
#include <cstring>
#define MAX 2000
struct bign {
int d[MAX];
int len;
bign() {
memset(d, 0, sizeof(d));
len = 0;
}
};
bign change(char *str) {
bign a;
a.len = strlen(str);
for (int i = 0; i != a.len; ++i)
a.d[i] = str[a.len - i - 1] - '0';
return a;
}
// 高进度加法,若最高位有进位,carry 变为 1
bign add(bign a, bign b, int &carry) {
bign c;
carry = 0;
int len = (a.len > b.len) ? a.len : b.len;
for (int i = 0; i != len; ++i) {
int temp = a.d[i] + b.d[i] + carry;
c.d[c.len++] = temp % 10;
carry = temp / 10;
}
if (carry)
c.d[c.len++] = carry;
return c;
}
void print(bign a) {
for (int i = 0; i != a.len; ++i)
putchar(a.d[a.len-i-1] + '0');
}
int main() {
int n;
char s1[MAX], s2[MAX], s3[MAX], s4[MAX]; // 分别为 a、b 的整数、小数部分
while (scanf("%d", &n) != EOF) {
while (n--) {
char input[MAX];
char *p1 = s1, *p2 = s2, *p3 = s3, *p4 = s4;
scanf("%s", input);
int pointFlag = 0;
for(int i = 0; i != strlen(input); ++i){
if (input[i] == '.') {
pointFlag = 1;
continue;
}
if (pointFlag)
*p2++ = input[i];
else
*p1++ = input[i];
}
*p1 = '\0';
*p2 = '\0';
scanf("%s", input);
pointFlag = 0;
for(int i = 0; i != strlen(input); ++i){
if (input[i] == '.') {
pointFlag = 1;
continue;
}
if (pointFlag)
*p4++ = input[i];
else
*p3++ = input[i];
}
*p3 = '\0';
*p4 = '\0';
// 把读入的字符串转换成 bign
bign ia = change(s1);
bign fa = change(s2);
bign ib = change(s3);
bign fb = change(s4);
// 开始加法
int carry;
bign ians = add(ia, ib, carry); // 整数部分直接相加
// 小数部分加法
if (fa.len < fb.len) { // 保证 fa 的长度不小于 fb
bign temp = fa;
fa = fb;
fb = temp;
}
if (fa.len > fb.len) { // 如果长度不一样,在 fb 后面补 0,以便相加
int offset = fa.len - fb.len;
memmove(fb.d + offset, fb.d, fb.len * sizeof(int));
memset(fb.d, 0, offset * sizeof(int));
fb.len = fa.len;
}
bign fans = add(fa, fb, carry);
// 如果小数部分有进位,让整数部分加一,抹去小数部分最高位
if (carry) {
bign one;
one.len = 1;
one.d[0] = 1;
ians = add(ians, one, carry);
fans.d[fans.len--] = 0;
}
// 删掉所有小数部分低位的 0
int offset = 0;
for ( ; offset != fans.len; ++offset)
if (fans.d[offset] != 0)
break;
memmove(fans.d, fans.d + offset, (fans.len - offset) * sizeof(int));
fans.len -= offset;
// 输出 ians, fans
print(ians);
putchar('.');
print(fans);
putchar('\n');
}
}
return 0;
}