Python中如何计数有效数字
我把这个问题标记为JavaScript,因为虽然我现在是用Python写的,但如果用JavaScript实现会更简单,我也能轻松做到。
我的任务是为化学系制作一个有效数字计算检查器。这意味着学生在网页应用中输入他们的数据,应用会对这些数据进行预设的操作,并跟踪有效数字,看看他们的答案是否有正确的有效数字个数。
当我把这个问题拆解成一个合理的工作流程时,我意识到我需要一种方法,让Python(因为这是用Django做的网页应用的后端)或者JavaScript(因为可以在前端轻松验证)来确定有效数字的个数。我做了一些研究,发现了这个问题,它告诉我需要处理Python字符串,而不是浮点数。我的Python代码感觉快完成了,但我仍然面临一个主要挑战。
import re
def find_sigfigs(x):
# change the 'E' to lower case if the student typed it in as uppercase
x = x.lower()
if ('e' in x):
myStr = x.split('e')
# this function assumes that the number on the left of the 'e' is
# the number of sigfigs. That would be true for user input but not
# true when python converts a float to scientific notation
return len( (re.search('[0-9]+', myStr[0])).group() )
else:
# put it in e format and return the result of that
### problem: python makes me hard code the number of sigfigs as '2'
### without the 2 there it always defaults to 6
return find_sigfigs('%.*e' %(2,float(x)))
>>> find_sigfigs('1.3e-4')
>>> 2
>>> find_sigfigs('1234')
>>> 3
>>> find_sigfigs('123456')
>>> 3
>>> find_sigfigs('1.2345e3')
>>> 5
然后没有2的情况。
return find_sigfigs('%.e' %(float(x)))
#Because it changes it to 1.234000e3
>>> find_sigfigs('1234')
>>> 7
#Because it changes it to 1.234560e5
>>> find_sigfigs('123456')
>>> 7
简单来说,我的问题是,当学生没有明确声明有效数字时(比如用科学记数法表示),我需要一个简单的方法来计算有效数字。有没有简单的方法可以在'e'之前去掉每一个零,直到找到第一个非零数字?我想,我需要从分割字符串的后面开始,去掉零,直到遇到非零数字?
编辑:经过一些调整后,我希望这能成为解决问题的合适方案。我测试了几次,但没有太严格(也就是说,可能有效,但谁知道呢!我对有效数字不是很在行…)
def find_sigfigs(x):
'''Returns the number of significant digits in a number. This takes into account
strings formatted in 1.23e+3 format and even strings such as 123.450'''
# change all the 'E' to 'e'
x = x.lower()
if ('e' in x):
# return the length of the numbers before the 'e'
myStr = x.split('e')
return len( myStr[0] ) - 1 # to compenstate for the decimal point
else:
# put it in e format and return the result of that
### NOTE: because of the 8 below, it may do crazy things when it parses 9 sigfigs
n = ('%.*e' %(8, float(x))).split('e')
# remove and count the number of removed user added zeroes. (these are sig figs)
if '.' in x:
s = x.replace('.', '')
#number of zeroes to add back in
l = len(s) - len(s.rstrip('0'))
#strip off the python added zeroes and add back in the ones the user added
n[0] = n[0].rstrip('0') + ''.join(['0' for num in xrange(l)])
else:
#the user had no trailing zeroes so just strip them all
n[0] = n[0].rstrip('0')
#pass it back to the beginning to be parsed
return find_sigfigs('e'.join(n))
2 个回答
我觉得有一个更简单的方法,不需要用到递归。而且,上面的解决方案只适用于字符串。让我觉得奇怪的是,要求在字符串中提取有效数字,这样的话,函数应该自己处理这个转换,或者至少能同时支持字符串和数字的输入。
这是我想到的:
def find_sigfigs(number):
"""Returns the number of significant digits in a number"""
# Turn it into a float first to take into account stuff in exponential
# notation and get all inputs on equal footing. Then number of sigfigs is
# the number of non-zeros after stripping extra zeros to left of whole
# number and right of decimal
number = repr(float(number))
tokens = number.split('.')
whole_num = tokens[0].lstrip('0')
if len(tokens) > 2:
raise ValueError('Invalid number "%s" only 1 decimal allowed' % (number))
if len(tokens) == 2:
decimal_num = tokens[1].rstrip('0')
return len(whole_num) + len(decimal_num)
return len(whole_num)
我有没有漏掉什么特殊情况呢?
我觉得在这里用正则表达式有点过于复杂了,不过你说的方法应该是可以的,我相信这不是性能问题。
我觉得你最后描述的思路是对的。我会先用 split('e')
来分开字符串,然后再用 rstrip('0')
来去掉末尾的零。如果你想保留递归调用的话,可以再把字符串拼接起来。