在Python中是否有一种方法来计算double/float/etc中的有效数字?我没有看到一个简单的方法来做到这一点,但我希望它在库中。
提前感谢。
您可能对任意精度浮点库感兴趣,例如:
http://code.google.com/p/mpmath/
我在另一个问题中找到了这个帖子的解决方案:
Python计数有效数字
这里的想法是,您将float作为字符串传递给方法,然后该方法使用正则表达式通过拆分字符串"e"
所在位置(用于科学格式的float字符串)和点所在位置(用于普通float字符串)来计算有效数字的数量。
似乎在8位有效数字前工作得很好,但在第9位之后的行为就不保证了。
不过,我相信这比
好。"有效数字没什么大不了的,意义不大支持计算机语言"
反应。这可能不容易,但你绝对可以做到,即使不是完美的。
内置Decimal库可以很好地解决这个问题,因为它解决了使用基于硬件的浮点数的问题。它有一个内部表示,只包含有效数字和指数。所以你可以用它来计算像这样的有效数字:
from decimal import Decimal
def count_sigfigs(numstr):
return len(Decimal(numstr).normalize().as_tuple().digits)
这对于很多例子都很有效,比如这些例子(来自这个相关的问题)。注意,您必须将数字作为字符串输入才能正常工作。使用浮点数会把它搞砸,因为它们的硬件表示。
tests = [('2', 1),
('1234', 4),
('2.34', 3),
('3000', 1),
('0.0034', 2),
('120.5e50', 4),
('1120.5e+50', 5),
('120.52e-50', 5)]
for num, expected in tests:
print(count_sigfigs(num) == expected)
给了:
True
True
True
True
True
True
True
True
不幸的是,这并不完全适用于数字"1.000"有4个符号。结果是1。所以它需要改进以涵盖所有情况。它也给出了1表示& 0"尽管这通常应该给出0。
如果您取出normalize
,则它适用于1.000
,但不适用于3000(它显示4而不是1)。
计算机根本不是这样工作的,至少,除非它们被编程为这样做。假设你给他们的数字是准确的。如果将2/3创建为0.66666666666667,那么所有操作都将其视为正确的。最低有效数字的错误可能会在以后的计算中传播成更大的错误,但这是好的代码应该处理的问题,使用尽可能减少这些问题的算法。
然而,正如我所说的,计算机做它们被告知要做的事情。所以有一些程序使用了所谓的区间算术。一个数字可以被描述为一个区间,所以我们可以创建2/3作为区间[0.6666666666666666,0.666666666666666667]。我们可以对区间、加、减、乘等进行运算。当我们操作这些操作时,通常会看到区间宽度扩大。然而,事实是,即使你使用区间算术工具,你也必须在一开始就知道你的数字中有多少位有效数字。如果您创建一个数字2.2,并将其存储为双精度数,那么计算机实际上会尝试将该数字存储为2.200000000000000,并假设所有数字都是完全正确的。当然,事实上,由于使用了浮点运算,该数字实际上将在内部存储为二进制数。因此,2.2可能会有效地存储为数字:
2.20000000000000017763568394002504646778106689453125,因为大多数十进制小数不能精确地用二进制表示。同样,所有的软件都必须小心使用,但也必须由使用这些工具的人来理解这些数字的真正含义。
最后一点很重要。很多人把电脑生成的数字当成真理,就像电脑神在石碑上传下来的一样。如果计算机打印出1.4523656535725,他们相信他们看到的每一个数字。实际上,这里必须运用常识,知道这个数字可能是从只有3位有效数字的数据中生成的,因此您可以选择只依赖该数字的前几位有效数字。当然,这就是为什么你们在学校里被教导这个概念,知道什么该相信,什么不该相信。但是请记住——计算机通常是无限信任的。这是你必须使用过滤器。
我使用格式化器来做。下面是一个测量a
和错误a_error
的示例。
a = 0.0595269489794585
a_error = 0.00089489789798
sig_fig_pos = abs(int(f'{G_err:e}'.split('e')[-1]))
a = float(f'{a:.{sig_fig_pos }f}')
a_error = float(f'{a_error:.{sig_fig_pos }f}')
print(a, '±', a_error)
将调整签名图的数量
0.0595 ± 0.0009