f为float时repr(f), str(f), print(f)的精度

Precision of repr(f), str(f), print(f) when f is float

如果我运行:

>>> import math
>>> print(math.pi)
3.141592653589793

然后pi打印出16位数字,

然而,根据:

>>> import sys
>>> sys.float_info.dig 
15

我的精度是15位。

那么,我是否应该依赖该值的最后一位(即 π 的值确实是 3.141592653589793nnnnnn)。

TL;DR

str(float)repr(float)的最后一位可以是"wrong",因为小数表示似乎没有正确四舍五入。

>>> 0.100000000000000040123456
0.10000000000000003

但该值仍然比 0.1000000000000000(少 1 位)更接近原始值。

math.pi的情况下,pi的十进制近似为3.141592653589793238463...,在这个的情况下最后一位数字是正确的。

sys.float_info.dig 表示保证 始终 精确的小数位数。


Python 3.1+ 中 str(float)repr(float) 的默认输出(以及 repr 中的 2.7)是转换为 [=23 时的最短字符串=] 将 return 原值;在出现歧义的情况下,最后一位数字四舍五入为最接近的值。浮点数提供约 15.9 位十进制数字的精度;但实际上需要高达 17 位十进制数字的精度才能明确表示 53 位二进制数字,

例如0.10000000000000004介于0x1.999999999999dp-40x1.999999999999cp-4之间,但后者更接近;这 2 个有十进制扩展

0.10000000000000004718447854656915296800434589385986328125

0.100000000000000033306690738754696212708950042724609375

分别。显然后者更接近,因此选择二进制表示。

现在,当使用 str()repr() 将它们转换回字符串时,会选择产生完全相同值的最短字符串;对于这 2 个值,它们分别是 0.100000000000000050.10000000000000003


IEEE-754中double的精度为53位二进制数;在十进制中,您可以通过取 2^53 的基于 10 的对数来计算精度,

>>> math.log(2 ** 53, 10)
15.954589770191001

意思是差不多16位精度。 float_info 精度表示您始终可以期望多少像样,这个数字是 15,因为有些数字的 16 位小数无法区分。


但这还不是全部。 Python 3.2+ 内部发生的事情是 float.__str__float.__repr__ 最终调用相同的 C 方法 float_repr:

float_repr(PyFloatObject *v)
{
    PyObject *result;
    char *buf;

    buf = PyOS_double_to_string(PyFloat_AS_DOUBLE(v),
                                'r', 0,
                                Py_DTSF_ADD_DOT_0,
                                NULL);
    if (!buf)
        return PyErr_NoMemory();
    result = _PyUnicode_FromASCII(buf, strlen(buf));
    PyMem_Free(buf);
    return result;
}

PyOS_double_to_string 然后,对于 'r' 模式(代表 repr),调用模式 0 的 _Py_dg_dtoa,这是将双精度转换为 a 的内部例程字符串,或者 snprintf%17g 对于那些 _Py_dg_dtoa 不起作用的平台。

snprintf 的行为完全依赖于平台,但如果使用 _Py_dg_dtoa(据我了解,它应该在大多数机器上使用),它应该是可预测的。

_Py_dg_dtoa mode 0指定如下:

0 ==> shortest string that yields d when read in and rounded to nearest.

所以,这就是发生的事情 - 产生的字符串在读入时必须准确地再现 double 值,并且它必须是可能的最短表示,并且在将被读入的多个十进制表示中,它将是最接近二进制值的那个。现在,这也可能意味着十进制扩展的最后一位 匹配以该长度四舍五入的原始值,只是十进制表示尽可能接近原始二进制表示。因此 YMMV.