是什么导致Python的float_repr_style使用旧版?

Cal*_*pau 5 python floating-point

在几乎每个系统上,Python都可以为您提供人类可读的浮点的简短表示形式,而不是17位的机器精度:

Python 3.3.0 (default, Dec 20 2014, 13:28:01) 
[GCC 4.8.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 0.1
0.1
>>> import sys; sys.float_repr_style
'short'
Run Code Online (Sandbox Code Playgroud)

ARM926EJ-S上,您没有简短的表示形式:

Python 3.3.0 (default, Jun  3 2014, 12:11:19) 
[GCC 4.7.3] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 0.1
0.10000000000000001
>>> import sys; sys.float_repr_style
'legacy'
Run Code Online (Sandbox Code Playgroud)

对于大多数系统Python 2.7显然将此简短表示形式添加到repr():

现在,在大多数平台上都可以正确舍入浮点数和字符串之间的转换。这些转换发生在许多不同的地方:str()代表浮点数和复数;浮动和复杂构造函数;数字格式;使用marshal,pickle和json模块对浮点数和复数进行序列化和反序列化;在Python代码中解析float和虚数文字;和十进制到浮点转换。

与此相关的是,浮点数x的repr()现在基于最短的十进制字符串返回一个结果,该字符串保证在正确的舍入(使用“从一半到一半到四舍五入的舍入模式”下)可以四舍五入为x。以前,它根据x舍入到17个十进制数字给出了一个字符串。

负责此改进的舍入库可在Windows和使用gcc,icc或suncc编译器的Unix平台上工作。可能在少数平台上无法保证此代码的正确操作,因此在此类系统上不使用该代码。您可以通过检查sys.float_repr_style来确定正在使用的代码,如果正在使用新代码,则将简短显示,而如果未使用,则将使用旧代码。

由Eric Smith和Mark Dickinson使用David Gay的dtoa.c库实现;问题7117

他们说某些平台不能保证( dtoa.c我想是),但没有说是哪个平台限制导致了这一点。

关于ARM926EJ-S,这意味着不能使用短浮点repr()是什么?

Mar*_*son 5

简短回答:这可能不是平台的限制,而是 Python 构建机制的限制:它没有为浮点计算设置 53 位精度的通用方法。

有关更多详细信息,请查看Include/pyport.hPython 源代码分发中的文件。这是摘录:

/* If we can't guarantee 53-bit precision, don't use the code
   in Python/dtoa.c, but fall back to standard code.  This
   means that repr of a float will be long (17 sig digits).

   Realistically, there are two things that could go wrong:

   (1) doubles aren't IEEE 754 doubles, or
   (2) we're on x86 with the rounding precision set to 64-bits
       (extended precision), and we don't know how to change
       the rounding precision.
 */

#if !defined(DOUBLE_IS_LITTLE_ENDIAN_IEEE754) && \
    !defined(DOUBLE_IS_BIG_ENDIAN_IEEE754) && \
    !defined(DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754)
#define PY_NO_SHORT_FLOAT_REPR
#endif

/* double rounding is symptomatic of use of extended precision on x86.  If
   we're seeing double rounding, and we don't have any mechanism available for
   changing the FPU rounding precision, then don't use Python/dtoa.c. */
#if defined(X87_DOUBLE_ROUNDING) && !defined(HAVE_PY_SET_53BIT_PRECISION)
#define PY_NO_SHORT_FLOAT_REPR
#endif
Run Code Online (Sandbox Code Playgroud)

从本质上讲,有两件事可能会出错。一是 Python 配置无法识别 C double 的浮点格式。该格式几乎总是 IEEE 754 binary64,但有时配置脚本无法弄清楚。这是#if上面代码片段中的第一个预处理器检查。查看pyconfig.h编译时生成的文件,看看是否至少有一个DOUBLE_IS_...宏是#defined。或者,在 Python 提示符下试试这个:

>>> float.__getformat__('double')
'IEEE, little-endian'
Run Code Online (Sandbox Code Playgroud)

如果你看到类似上面的内容,这部分应该没问题。如果您看到类似 的内容'unknown',则 Python 无法识别浮点格式。

可能出错的第二件事是我们确实有 IEEE 754 binary64 格式的双精度数,但是 Python 的构建机制无法弄清楚如何确保该平台浮点计算的 53 位精度。该dtoa.c源需要我们能够做的所有浮点运算(硬件或软件是否实施)在53位精度。这在使用 x87 浮点单元进行双精度计算(与较新的 SSE2 指令相反)的英特尔处理器上尤其成问题:x87 的默认精度为 64 位,并将其用于双精度计算使用该默认精度设置会导致双舍入,从而破坏dtoa.c假设。因此,在配置时,构建机制会运行检查以查看 (1) 双舍入是否是潜在问题,以及 (2) 如果是,是否有办法将 FPU 设置为 53 位精度。所以,现在你想看看pyconfig.hX87_DOUBLE_ROUNDINGHAVE_PY_SET_53BIT_PRECISION宏。

所以它可能是上面的任何一个。如果我不得不猜测,我会猜测在该平台上,双舍入被检测为问题,并且不知道如何解决它。在这种情况下的解决方案是适应pyport.h_Py_SET_53BIT_PRECISION_*任何特定于平台的方式定义宏以获得 53 位精度模式,然后定义HAVE_PY_SET_53BIT_PRECISION.