为什么 python 十进制库 return 某些输入的指定有效数字位数

Why doesn't python decimal library return the specified number of signficant figures for some inputs

注意:这个问题是关于significant figures的。 不是关于"digits after the decimal point"或类似问题的问题。

编辑:这个问题不是 Significant figures in the decimal module. The two questions are asking about entirely different problems. I want to know why the function about does not return the desired value for a specific input. None of the answers to Significant figures in the decimal module 解决这个问题的副本。


以下函数应该 return 具有指定有效数字位数的浮点数的字符串表示形式:

import decimal

def to_sigfigs(value, sigfigs):
    return str(decimal.Context(prec=sigfigs).create_decimal(value))

乍一看,似乎可行:

print to_sigfigs(0.000003141592653589793, 5)
# 0.0000031416

print to_sigfigs(0.000001, 5)
# 0.0000010000

print to_sigfigs(3.141592653589793, 5)
# 3.1416

...但是

print to_sigfigs(1.0, 5)
# 1

最后一个表达式(IOW,1.0 的 5 位有效数字表示)的期望输出是字符串“1.0000”。实际输出的是字符串 '1'.

我是不是误会了什么,或者这是 decimal 中的错误?

上下文的精度是最大精度;如果一个操作会产生一个数字少于上下文精度的 Decimal,它不会被填充到上下文的精度。

当您调用 to_sigfigs(0.000001, 5) 时,由于从源代码到二进制浮点数的转换,0.000001 已经有一些舍入错误。它实际上是 9.99999999999999954748111825886258685613938723690807819366455078125E-7。四舍五入到 5 位有效数字得到 decimal.Decimal("0.0000010000").

另一方面,1 可以用二进制浮点数表示,所以 1.0 正好是 1。由于只需要 1 个数字来表示十进制,上下文的精度不需要任何舍入, 你会得到一个 1 位数的十进制结果。

这是一个错误吗?我不知道,我认为文档不够严密,无法做出该决定。这当然是一个令人惊讶的结果。

可以用更多的逻辑来修复你自己的函数。

def to_sigfigs(value, sigfigs):
    sign, digits, exponent = decimal.Context(prec=sigfigs).create_decimal(value).as_tuple()
    if len(digits) < sigfigs:
        missing = sigfigs - len(digits)
        digits = digits + (0,) * missing
        exponent -= missing
    return str(decimal.Decimal((sign, digits, exponent)))