「PAT乙级真题解析」Basic Level 1024 科学计数法 (问题分析+完整步骤+伪代码描述+提交通过代码)
由于科学计数法表示形式中含有字符, 所以输入数据需要存储成字符串。 由于题设提示长度不会超过9999字节, 所以数值位数大概在1万位。所以为了避免数值溢出, 结果也要存储为字符串(或者直接输出) 我们需要把科学计数法转成普通数字表示法的步骤明确好, 然后用编程语言翻译即可。
#算法#数据结构#c语言#需求分析#pat考试
Table of Contents
乙级的题目训练主要用来熟悉编程语言的语法和形成良好的编码习惯和编码规范。从小白开始逐步掌握用编程解决问题。
问题分析
由于科学计数法表示形式中含有字符, 所以输入数据需要存储成字符串。 由于题设提示长度不会超过9999字节, 所以数值位数大概在1万位。所以为了避免数值溢出, 结果也要存储为字符串(或者直接输出)
我们需要把科学计数法转成普通数字表示法的步骤明确好, 然后用编程语言翻译即可。
科学计数法转普通数字表示法
回顾我们人工转换的过程, 其实就是找到各个部分(实属部分, 指数部分, 小数点) 然后实数部分不变, 把小数点往后移动与指数值相同的位数即可.
如何找到实数部分、指数部分
实数部分和指数部分以'E'分隔, 只要找到'E', 其前面的部分就是实数部分, 后面的部分就是指数部分
如何实现小数点的移动
以"+1.23400E-03"为例.
原本小数点在索引为2的位置(从0开始计数). 指数部分是-3, 小数点位置应该变为 (2-3) = -1 而我们预期的输出结果是"0.00123400". 二者的关系是:
- 考虑到输入中包含正负号, 而输出中如果是正数不会输出正号, 所以小数点位置实际应该是(2-3-1) = -2 如果小数点位置是负数, 则先输出"0.", 然后输出2个"0", 然后输出原数值.
以"+1.23400E+03"为例.
预期输出结果为"1234.00", 根据指数, 小数点位置应该是(2+3-1) = 4 如果小数点位置是正数, 则先输出实数部分, 同时记录已经输出的数字个数, 如果输出的数字个数等于小数点位置数值, 输出小数点后继续输出实数部分的数值(跳过小数点)
【需要额外考虑的情况】
- "+1.23400E+05" -> 123400 这种情况不需要输出小数点
- "+1.23400E+10" -> 12340000000 这种情况不需要输出小数点, 而且需要在末尾补0
完整描述步骤
- 获取输入 number (作为字符串存储)
- 对于字符串每个字符: 检查是否是'.', 如果是, 记录小数点位置 检查是否是'E', 如果是, 记录分隔符'E'的位置
- 获取指数部分, 转为数值类型
- 计算小数点在结果中的位置
- 如果小数点位置x是负数, 则先输出"0.", 然后输出对应绝对值个数的"0", 然后输出原数值(跳过小数点)
- 如果小数点位置x是正数, 则输出原数值并统计已经输出的数字个数, 在已经输出x个数字后输出小数点, 然后输出剩余的实数部分
伪代码描述
1. get input number (as string)
2. init variable:
- number_length = 0
- dot_position = -1
- E_position = -1
3. for char in number:
if char == '.': dot_position == index of current char
if char == 'E': E_position == index of current char
number_length++
4. exponent = int(number[E_position+1: end])
5. calculate new_dot_position = dot_position + exponent - 1
6. print as requirements:
if number[0] == '-': print("-")
if new_dot_position <= 0:
print("0.")
for (int i = 0; i < abs(new_dot_position); i++): print("0")
for (int i = 1; i < E_position; i++):
if number[i] != '.': print(number[i])
else:
init has_printed_digit_amount = 0
for (int i = 1; i < E_position; i++):
if number[i] != '.':
print(number[i])
has_printed_digit_amount++
if has_printed_digit_amount == new_dot_position:
print(".")
if (new_dot_position >= E_position):
for (int i = 0; i <= new_dot_position-E_position+1; i++)
print("0");
完整提交代码
/*
# 问题分析
我们需要把科学计数法转成普通数字表示法的步骤明确好, 然后用编程语言翻译即可。
## 科学计数法转普通数字表示法
回顾我们人工转换的过程, 其实就是找到各个部分(实属部分, 指数部分, 小数点)
然后实数部分不变, 把小数点往后移动与指数值相同的位数即可.
## 如何找到实数部分、指数部分
实数部分和指数部分以'E'分隔, 只要找到'E', 其前面的部分就是实数部分, 后面的部分就是指数部分
## 如何实现小数点的移动
以"+1.23400E-03"为例.
原本小数点在索引为2的位置(从0开始计数).
指数部分是-3, 小数点位置应该变为 (2-3) = -1
而我们预期的输出结果是"0.00123400". 二者的关系是:
- 考虑到输入中包含正负号, 而输出中如果是正数不会输出正号,
所以小数点位置实际应该是(2-3-1) = -2
如果小数点位置是负数, 则先输出"0.", 然后输出2个"0", 然后输出原数值.
以"+1.23400E+03"为例.
预期输出结果为"1234.00",
根据指数, 小数点位置应该是(2+3-1) = 4
如果小数点位置是正数, 则先输出实数部分, 同时记录已经输出的数字个数,
如果输出的数字个数等于小数点位置数值, 输出小数点后继续输出实数部分的数值(跳过小数点)
【需要额外考虑的情况】
1. +1.23400E+05 -> 123400 这种情况不需要输出小数点
2. +1.23400E+10 -> 12340000000 这种情况不需要输出小数点, 而且需要在末尾补0
# 完整描述步骤
1. 获取输入 number (作为字符串存储)
2. 对于字符串每个字符:
检查是否是'.', 如果是, 记录小数点位置
检查是否是'E', 如果是, 记录分隔符'E'的位置
3. 获取指数部分, 转为数值类型
4. 计算小数点在结果中的位置
5. 如果小数点位置x是负数, 则先输出"0.", 然后输出对应绝对值个数的"0", 然后输出原数值(跳过小数点)
6. 如果小数点位置x是正数, 则输出原数值并统计已经输出的数字个数, 在已经输出x个数字后输出小数点, 然后输出剩余的实数部分
# 伪代码描述
1. get input number (as string)
2. init variable:
- number_length = 0
- dot_position = -1
- E_position = -1
3. for char in number:
if char == '.': dot_position == index of current char
if char == 'E': E_position == index of current char
number_length++
4. exponent = int(number[E_position+1: end])
5. calculate new_dot_position = dot_position + exponent - 1
6. print as requirements:
if number[0] == '-': print("-")
if new_dot_position <= 0:
print("0.")
for (int i = 0; i < abs(new_dot_position); i++): print("0")
for (int i = 1; i < E_position; i++):
if number[i] != '.': print(number[i])
else:
init has_printed_digit_amount = 0
for (int i = 1; i < E_position; i++):
if number[i] != '.':
print(number[i])
has_printed_digit_amount++
if has_printed_digit_amount == new_dot_position:
print(".")
if (new_dot_position >= E_position):
for (int i = 0; i <= new_dot_position-E_position+1; i++)
print("0");
*/
#include <stdio.h>
int extract_exponent(char *number, int start, int end)
{
char result[10000];
for (int i = start; i < end; i++)
{
result[i - start] = number[i];
}
result[end] = "\0";
return atoi(result);
}
void print_number_in_normal_format(char *number, int number_length, int new_dot_position, int E_position)
{
if (number[0] == '-')
{
printf("-");
}
if (new_dot_position <= 0)
{
printf("0.");
for (int i = 0; i < -new_dot_position; i++)
{
printf("0");
}
for (int i = 1; i < E_position; i++)
{
if (number[i] != '.')
printf("%c", number[i]);
}
}
else
{
int has_printed_digit_amount = 0;
for (int i = 1; i < E_position; i++)
{
if (number[i] != '.')
{
printf("%c", number[i]);
has_printed_digit_amount++;
}
if (has_printed_digit_amount == new_dot_position && i != E_position-1)
{
printf(".");
}
}
if (new_dot_position >= E_position)
{
int size = new_dot_position - E_position + 1;
for (int i = 0; i <= size; i++)
{
printf("0");
}
}
}
}
int main()
{
char number[10000];
scanf("%s", number);
int number_length = 0;
int dot_position = -1;
int E_position = -1;
for (int i = 0; number[i]; i++)
{
if (number[i] == '.')
dot_position = i;
if (number[i] == 'E')
E_position = i;
number_length++;
}
int exponent = extract_exponent(number, E_position + 1, number_length);
int new_dot_position = dot_position + exponent - 1;
print_number_in_normal_format(number, number_length, new_dot_position, E_position);
return 0;
}