PAT 乙级练习 1024 科学计数法 - 超级详细的思路讲解
PAT 乙级练习 题解合集
题目
科学计数法是科学家用来表示很大或很小的数字的一种方便的方法,其满足正则表达式 [±][1-9].[0-9]+E[±][0-9]+,即数字的整数部分只有 1 位,小数部分至少有 1 位,该数字及其指数部分的正负号即使对正数也必定明确给出。
现以科学计数法的格式给出实数 A,请编写程序按普通数字表示法输出 A,并保证所有有效位都被保留。
输入格式:
每个输入包含 1 个测试用例,即一个以科学计数法表示的实数 A。该数字的存储长度不超过 9999 字节,且其指数的绝对值不超过 9999。
输出格式:
对每个测试用例,在一行中按普通数字表示法输出 A,并保证所有有效位都被保留,包括末尾的 0。
输入样例 1:
+1.23400E-03
输出样例 1:
0.00123400
输入样例 2:
-1.2E+10
输出样例 2:
-12000000000
思路
输入长啥样?
首先分解一下输入是由哪几部分组成的:
- 正负号(整个数字的);
- 数字,分为整数和小数部分;
- 正负号(指数部分的);
- 指数的绝对值。
我们要干嘛?
回答一个大局观的问题:我们写这个题到底是在干什么?本质上其实是根据指数的正负以及绝对值让数字中的小数点.
进行正确的移动。
例如样例1
,输入+1.23400E-03
,那么就让小数点向左移动 3 次,输出是0.00123400
。
根据这个观点我们就有了分类讨论的基础:小数点怎么动?把指数拆解为符号和绝对值dot_move
,有以下几种情况:
dot_move == 0
(不移动):最简单的情况,直接输出原本的数字即可;- 指数的符号是
-
(向左移动):因为我们已经排除了小数点不移动的情况,且数字的整数部分有且仅有 1 位,所以一旦小数点向左移动,输出的最开始一定是0.
,紧跟着的是dot_move - 1
个0
(可以纸笔画一下),最后把原先的数字去掉小数点并输出即可; - 指数的符号是
+
(向右移动):假设数字的小数部分有n
位(例如3.14159
有 5 位小数),此时又分成两种情况
a.dot_move < n
:小数点没有移动到超出数字的范围,最终结果依然存在小数点;
b.dot_move >= n
:小数点已经移动到数字“外面”去了,此时最终结果是不带小数点的,而且如果dot_move > n
,还要在末尾输出dot_move - n
个0
。
代码
#include <stdio.h>
#include <string.h>
int main() {
char plus1; // 整个数的正负号
char input[10010]; // 从正负号后面读入剩余字符
scanf("%c", &plus1);
scanf("%s", input);
char *pdot = strchr(input, '.'); // 找小数点的位置
char *pe = strchr(input, 'E'); // 找 E 的位置
char plus2 = *(pe + 1); // 指数部分的正负号
int dot_move; // 小数点移动位数
sscanf(pe + 2, "%d", &dot_move);
// 开始输出
if (plus1 == '-')
putchar(plus1); // 若有负号,输出
*pe = '\0'; // 从 E 的位置截断字符串,方便输出
char *p = input;
if (!dot_move) { // 指数部分为 0
printf("%s", input);
} else if (plus2 == '-') { // 指数符号为 -
printf("0.");
--dot_move;
while (dot_move--)
putchar('0');
putchar(*p);
p += 2;
printf("%s", p);
} else if (plus2 == '+') { // 指数符号为 +
while (pdot + 1 != pe && (dot_move--))
++pdot;
if (pdot + 1 == pe) {
putchar(*p);
p += 2;
printf("%s", p);
while (dot_move--)
putchar('0');
} else {
putchar(*p);
p += 2;
while (p != pdot) {
putchar(*p);
p++;
}
putchar(*p);
putchar('.');
p++;
printf("%s", p);
}
}
return 0;
}