# 在 Python 中计算有效数字？

[英]Counting significant figures in Python?

Is there a way in Python to count the significant figures in a double/float/etc? Python中有没有办法计算双/浮点/等中的有效数字？ I'm not seeing an easy way to do this, but I'd expect it to be in the library.我没有看到一个简单的方法来做到这一点，但我希望它会在图书馆里。

No. Significant digits are just not that big a deal and get little support in computer languages. 没有。重要的数字只是没什么大不了的，并且得不到计算机语言的支持。 People doing real computations need error bars, which have far more precision — real measurements say very exact things like “this is 0.11 ± 0.03mm“ instead of saying either of the less exact statements “this is 0.1 mm” or “this is 0.11 mm” which makes you choose a power of ten even if your inexactness does not actually fall at a power of ten. 进行实际计算的人需要误差棒，这些误差棒具有更高的精度 - 实际测量表明非常精确的事情，例如“这是0.11±0.03mm”而不是说不太精确的陈述“这是0.1毫米”或“这是0.11毫米” “即使你的不精确实际上并没有达到10的幂，你也会选择10的幂。

The built-inDecimal library can help out pretty well with this since it gets around concerns with using hardware-based floating point numbers.内置的Decimal 库可以很好地解决这个问题，因为它解决了使用基于硬件的浮点数的问题。 It has an internal representation that just contains the significant digits and the exponent.它有一个内部表示，只包含有效数字和指数。 So you can use that to count significant figures like this:所以你可以用它来计算这样的有效数字：

``````from decimal import Decimal
def count_sigfigs(numstr):
return len(Decimal(numstr).normalize().as_tuple().digits)

``````

This works pretty well for lots of examples, like these ones (from this related question ).这适用于很多例子，比如这些例子（来自这个相关问题）。 Note that you do have to input the numbers as strings for it to work right.请注意，您必须将数字作为字符串输入才能正常工作。 Using floats would mess it up because of their hardware representation.由于它们的硬件表示，使用浮点数会搞砸。

``````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)
``````

Which gives:这使：

``````True
True
True
True
True
True
True
True
``````

Unfortunately this does not quite work on numbers like "1.000" which have 4 sigfigs.不幸的是，这不适用于像“1.000”这样有 4 个 sigfigs 的数字。 This just gives 1. So it'd need improvement to cover all cases.这只是给出 1。所以它需要改进以涵盖所有情况。 Also it gives 1 for "0" though that typically should give 0.它也为“0”给出 1，尽管通常应该给出 0。

If you take out the `normalize` then it works for `1.000` but not for 3000 (it says 4 rather than 1).如果您取出`normalize` ，那么它适用于`1.000`但不适用于 3000（它说 4 而不是 1）。

You may be interested in an arbitrary precision floating point library such as this one: 您可能对任意精度浮点库感兴趣，例如：

I found a solution to this post in another question: 我在另一个问题中找到了这篇文章的解决方案：

The idea here is that you pass the float as a String to the methods, and then the method uses regular expressions to count the number of significant digits by splitting strings where `"e"` is (for float string in scientific format) and where the dot is (for normal float strings). 这里的想法是你将float作为String传递给方法，然后该方法使用正则表达式通过分割字符串来计算有效数字的位数，其中`"e"`是（对于科学格式的浮点字符串）和点的位置是（对于普通的浮点字符串）。

It seems to work well up to 8 significant digits, but the behavior is not guaranteed after the 9th. 它似乎可以很好地工作到8位有效数字，但在9日之后不能保证这种行为。

Still, I believe this is better than the 不过，我相信这比这更好

"Significant digits are just not that big a deal and get little support in computer languages" “重要的数字并不是那么大，在计算机语言中得不到什么支持”

response. 响应。 It may not be easy, but you can definitely do it, even if not perfectly. 这可能并不容易，但你绝对可以做到，即使不是很完美。

Computers simply don't work that way, at least, not unless they are programmed to do so. 计算机根本不能以这种方式工作，至少，除非它们被编程为这样做。 The assumption is the number you give them is exact. 假设你给他们的数字是准确的。 If you create the number 2/3 as 0.6666666666666667, then all operations treat it as exactly that. 如果您将数字2/3创建为0.6666666666666667，则所有操作都将其视为完全相同。 That error in the least significant digit may end up propagating to larger errors in later computations, but this is something that good code should deal with, using algorithms that minimize these issues when possible. 最低有效数字中的该错误可能最终在以后的计算中传播到更大的错误，但这是优秀代码应该处理的事情，使用尽可能最小化这些问题的算法。

As I said however, computers do what they are told to do. 然而，正如我所说，计算机会做他们被告知要做的事情。 So there are packages written that use what is called interval arithmetic. 因此，编写的包使用所谓的区间运算。 A number may then be described as an interval, so we might create 2/3 as the interval [0.6666666666666666,0.6666666666666667]. 然后可以将数字描述为区间，因此我们可以创建2/3作为区间[0.6666666666666666,0.6666666666666667]。 We can operate on intervals, adding, subtracting, multiplying, etc. Those operations will often see interval widths expand as we operate with them. 我们可以按时间间隔，加法，减法，乘法等操作。这些操作通常会在我们操作它们时看到间隔宽度扩大。

The fact is however, even if you use interval arithmetic tools, it is YOU who must know at the beginning the number of significant digits in your numbers. 但事实是，即使你使用区间算术工具，你必须在一开始就知道你的数字中的有效位数。 If you create a number as 2.2, storing it as a double, then the computer will actually try to store the number as 2.200000000000000, and assume that all the digits are exactly correct. 如果您创建一个2.2的数字，将其存储为double，那么计算机实际上会尝试将该数字存储为2.200000000000000，并假设所有数字都完全正确。 In fact of course, because floating point arithmetic is employed, the number will actually be stored internally as a binary number. 实际上，当然，因为采用了浮点运算，所以该数字实际上将作为二进制数存储在内部。 So 2.2 will probably be effectively stored as the number: 所以2.2可能会有效地存储为数字：

2.20000000000000017763568394002504646778106689453125 2.20000000000000017763568394002504646778106689453125

because most decimal fractional numbers are not representable exactly in binary form. 因为大多数小数部分数字不能完全以二进制形式表示。 Again, care must be employed in all software, but also always by the person who is using those tools to understand what their numbers really mean. 同样，必须谨慎使用所有软件，但也必须始终由使用这些工具的人员了解他们的数字的真正含义。

This last point is important. 最后一点很重要。 Many people treat the numbers generated by a computer as truth, as handed down by the computer god on a stone tablet. 许多人将计算机产生的数字视为真理，就像计算机之神在石碑上传下来一样。 If the computer prints out 1.4523656535725, they believe every digit of what they see. 如果计算机打印出1.4523656535725，他们相信他们所看到的每一个数字。 In fact, common sense must be applied here, to know that perhaps this number was generated from data that had only 3 significant digits, so that you may choose to rely on only the first few significant digits of that number. 实际上，必须在这里应用常识，要知道这个数字可能是由只有3位有效数字的数据生成的，因此您可以选择仅依赖该数字的前几位有效数字。 And of course, this is why you are taught about that concept in school, to know what to trust, and what not to trust. 当然，这就是为什么你在学校里学习这个概念，知道应该信任什么，不信任什么。 Remember however - computers will generally be infinitely trusting. 但请记住 - 计算机通常会无限信任。 It is you who must apply the filter. 是您必须应用过滤器。

I used the formatters to do it.我使用格式化程序来做到这一点。 Here's an example with a measurement `a` and an error `a_error` .这是一个带有测量`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)
``````

Will adjust the number of sig figs将调整 sig figs 的数量

``````0.0595 ± 0.0009
``````