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-4
和0x1.999999999999cp-4
之间,但后者更接近;这 2 个有十进制扩展
0.10000000000000004718447854656915296800434589385986328125
和
0.100000000000000033306690738754696212708950042724609375
分别。显然后者更接近,因此选择二进制表示。
现在,当使用 str()
或 repr()
将它们转换回字符串时,会选择产生完全相同值的最短字符串;对于这 2 个值,它们分别是 0.10000000000000005
和 0.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.
如果我运行:
>>> 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-4
和0x1.999999999999cp-4
之间,但后者更接近;这 2 个有十进制扩展
0.10000000000000004718447854656915296800434589385986328125
和
0.100000000000000033306690738754696212708950042724609375
分别。显然后者更接近,因此选择二进制表示。
现在,当使用 str()
或 repr()
将它们转换回字符串时,会选择产生完全相同值的最短字符串;对于这 2 个值,它们分别是 0.10000000000000005
和 0.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.