1024 科学计数法 (20 分)
题意描述:
科学计数法是科学家用来表示很大或很小的数字的一种方便的方法,其满足正则表达式 [±][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
解题思路:
Alice: 有什么想法吗 ?
Bob: 有一点,还没想清楚,有点乱。
Alice: 先说来听听嘛。
Bob: 如果输入的数字的指数是负数,小数点向左移动。题目中要求保留所有的有效数字,就是要把所有数字都保留下来,在左边添一些0,然后在第一位数字后面加一个小数点就好了。
Alice: 恩,这种情况我也想到了,然后呢 ?
Bob: 我有一个问题,就是有效数字的定义我不太确定。
Alice: 那还不简单,查一查不得了。
Bob:
有效数字指科学计算中用以表示一个浮点数精度的那些数字。一般地,指一个用小数形式表示的浮点数中,从第一个非零的数字算起的所有数字。如1.24和0.00124的有效数字都有3位。
Alice: 恩,这样啊,原来有效数字要从第一个非零的数字算起啊。那科学计数法的概念呢?
Bob:
Alice: 我明白了,因为题目中给出的是科学计数法的形式,第一位一定不是零的。所以题目中的有效数字就是所有的尾数,所以我们得保留所有的尾数。那这样子,你刚才对指数小于0 的情况的处理就是正确的了。
Bob: 本来就是正确的好吗 ;- }
Alice: 右移的时候,指数大于零的时候怎么办呢 ?
Bob: 像样例2那样的,-1.2E+10
, 小数直接变成了整数了。要在尾数后面添一些零,然后让小数点出现在正确的位置。
Alice: 还有另一种情况,像-1.200001E+2
这样,不需要在尾数后面添零的,不过也要让小数点出现在正确的位置。
Bob: 对对对,就是这样的~
Alice: 我来总结一下,一共有三种情况:
- 一种是小数点向左移动;
- 一种是小数点向右移动,移动了很多以至于“走丢了”;
- 最后一种是小数点向右移动,只移动很少最后的数字还是一个小数。
Bob: 恩恩,那么程序怎么来写呢 ?
Alice: 这样,我们先:
- 在尾数的左边或者右边补上恰当数量的零
- 然后我们再把小数点加上去
Bob: 哈哈哈哈,妙啊。
Alice: 哈哈哈哈。
代码:
def main():
string = input()
# 接收输入的待“格式化”的字符串
prefix = -1 if string[0] == '-' else 1
# 如果字符串的首位是 '-' prefix 就是 -1,否则就是 1,我们使用prefix来记录输入数据的正负。
# 这是Python 提供的语法糖之一,上面的写法和下面这种写法等价。
"""
if string[0] == '-':
prefix = -1
else:
prefix == 1
"""
e_index = string.index('E')
# 找到字符'E'在字符串中第一次出现的位置,由于'E'在string中只出现一次,所以我们找到的就是'E'的下标。
# 如'+1.23400E-03' -> e_index == 8
numbers = string[1] + string[3:e_index]
# string[1]是小数点左边的一位数字, string[3:e_index]就是小数点后的多位数字,string[2] 是小数点,string[0]是正负号。
# 将这个科学计数法形式中小数的 所有数字拼接起来,就是将小数点去除后的数字组成的字符串。
# 如 '+1.23400E-03' -> '1' + '23400' -> '123400'
zhishu = int(string[e_index + 1:])
# 如拼音所示,得到指数。string[e_index] == 'E'
# string[e_index+1:] 就是'E'后面的数字啦。如'+1.23400E-03' -> '-03', 最后转换为整型数喽。
if zhishu < 0:
# 如果指数 < 0,我们只需要向左移动小数点,也就是在原有的数字左边添加足够的0。
numbers = '0' * (-1 * zhishu) + numbers
# 在原有的数字左边上足够的0,如'+1.23400E-03' -> '0' * 3 + '123400' -> '000123400'
dot_position = 1
# 在后面输出答案的时候还要点上小数点,现在我们先记下小数点的位置。
elif zhishu > 0:
# 如果指数 > 0,我们需要向右移动小数点。这时候就需要考虑原来的小数点后的位数了,根据原来的数字小数点后的位数和要移动的位数的大小关系可以分为两类。
numbers_after_dot = e_index - 3
# 计算小数点后的数字有多少位, 实际的公式是 e_index - 1 - 3 + 1 ,其中e_index - 1是小数点后最后一位数字的下标,3是小数点后第一位数字的下标。
# 如'-1.2E+10' -> 4 - 3 , 只有2这一位嘛。
if zhishu >= numbers_after_dot:
# 如果指数大于或等于小数点后的位数,小数点移动的足够多以至于数字从小数变成了一个整数
numbers = numbers + '0' * (zhishu - numbers_after_dot)
# 在原来数字的右边添上足够多的0就好了,如'-1.2E+10' -> '12' + '0' * (10 - 1) -> '12000000000'
dot_position = None
# 此时并没有小数点要点
else:
# 如果指数小于 小数点后的位数,仅仅移动小数点, 如 '-1.200001E+2' -> '-120.0001'
dot_position = 1 + zhishu
# 由于我们把正负号已经剥离了出去,所以小数点的位置从 1 算起(第零位是数字),如'-1.200001E+2' -> '-120.0001' 即 1 -> 1 + 2
else:
#如果指数是0的话, 10^0 == 1,按兵不动。
pass
prefix = '-' if prefix == -1 else ''
# 如果prefix 是 -1 就输出符号,否则,正号不用输出
"""
print("prefix", prefix)
print('numbers', numbers)
print('zhishu', zhishu)
print('dot_position', dot_position)
"""
if dot_position != None:
#如果有小数点要点,输出正负号,小数点左边的数字,小数点,小数点右边的数字
answer = "{}{}.{}".format(
prefix, numbers[:dot_position], numbers[dot_position:])
else:
#如果没有小数点要点,输出正负号,数字
answer = "{}{}".format(prefix, numbers)
print(answer)
pass
if __name__ == '__main__':
main()
易错点:
- 除了题目中给出的两个测试样例,还有第三种情况应当考虑到。即
'-1.200001E+2'
,小数点向右移动但移动的位数较少。
总结:
- 对于题目中逻辑有些复杂的题目,要沉心静气,答案自然会水落石出。正如,
读书破万卷,下笔如有神。
书读百遍 ,其义自见。