python - 为什么 float.__repr__ 与等效的格式化选项相比返回不同的表示?
问题描述
为了了解repr(x)
CPython 中 float 的工作原理,我检查了以下源代码float_repr
:
buf = PyOS_double_to_string(PyFloat_AS_DOUBLE(v),
'r', 0,
Py_DTSF_ADD_DOT_0,
NULL);
PyOS_double_to_string
这使用格式代码调用,该代码'r'
似乎被转换为'g'
精度设置为 17 的格式代码:
precision = 17;
format_code = 'g';
所以我希望repr(x)
并f'{x:.17g}'
返回相同的表示。然而,情况似乎并非如此:
>>> repr(1.1)
'1.1'
>>> f'{1.1:.17g}'
'1.1000000000000001'
>>>
>>> repr(1.225)
'1.225'
>>> f'{1.225:.17g}'
'1.2250000000000001'
我知道repr
只需要返回尽可能多的数字来重建与内存中表示的完全相同的对象,因此'1.1'
显然足以返回1.1
但我想知道这与(内部使用的)有何不同(或为什么) ).17g
格式化选项。
(Python 3.7.3)
解决方案
似乎您正在寻找一种后备方法:
/* The fallback code to use if _Py_dg_dtoa is not available. */
PyAPI_FUNC(char *) PyOS_double_to_string(double val,
char format_code,
int precision,
int flags,
int *type)
{
char format[32];
调节回退方法的预处理器变量是PY_NO_SHORT_FLOAT_REPR
. 如果已设置,则dtoa
不会编译,因为它将失败:
/* 如果定义了 PY_NO_SHORT_FLOAT_REPR,那么甚至不要尝试编译以下代码 */
大多数现代设置可能并非如此。这个问答解释了 Python 何时/为什么选择这两种方法:是什么导致 Python 的 float_repr_style 使用 legacy?
现在在第 947 行,你有 _Py_dg_dtoa 可用的版本
/* _Py_dg_dtoa is available. */
static char *
format_float_short(double d, char format_code,
int mode, int precision,
int always_add_sign, int add_dot_0_if_integer,
int use_alt_formatting, const char * const *float_strings,
int *type)
在那里你可以看到g
并r
有细微的差异(在评论中解释)
我们曾经在 1e17 进行转换,但是当 16 位“最短”repr 用虚假零填充时,某些值的结果看起来很奇怪。
case 'g':
if (decpt <= -4 || decpt >
(add_dot_0_if_integer ? precision-1 : precision))
use_exp = 1;
if (use_alt_formatting)
vdigits_end = precision;
break;
case 'r':
/* convert to exponential format at 1e16. We used to convert
at 1e17, but that gives odd-looking results for some values
when a 16-digit 'shortest' repr is padded with bogus zeros.
For example, repr(2e16+8) would give 20000000000000010.0;
the true value is 20000000000000008.0. */
if (decpt <= -4 || decpt > 16)
use_exp = 1;
break;
似乎它与您描述的行为相匹配。请注意,"{:.16g}".format(1.225)
产量1.225
推荐阅读
- node.js - 如何确保我的终端在 Visual Studio Code 中打开 .firebaserc 和 firebase.json 文件?
- python - 硒饼干处理
- c++ - 类中的常量成员
- reactjs - React:将查询字符串传递到路径中
- python - 如何在 matplotlib 图中突出显示周末?
- git - 如何对 git 客户端挂钩进行版本控制?
- node.js - 动态 GatsbyJS + Node Express 部署
- node.js - Nodejs议程作业调度程序-如何将在同一数据库扫描中运行的多个作业分组为1个批处理作业?
- webrtc - 了解 WebRTC 中的 SFU、TURN 服务器
- python - 类型提示 pandas DataFrame 切片行的索引