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

What causes Python's float_repr_style to use legacy?

几乎在每个系统上,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'

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'

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

Conversions between floating-point numbers and strings are now correctly rounded on most platforms. These conversions occur in many different places: str() on floats and complex numbers; the float and complexconstructors; numeric formatting; serializing and deserializing floats and complex numbers using the marshal, pickle and json modules; parsing of float and imaginary literals in Python code; and Decimal-to-float conversion.

Related to this, the repr() of a floating-point number x now returns a result based on the shortest decimal string that’s guaranteed to round back to x under correct rounding (with round-half-to-even rounding mode). Previously it gave a string based on rounding x to 17 decimal digits.

The rounding library responsible for this improvement works on Windows and on Unix platforms using the gcc, icc, or suncc compilers. There may be a small number of platforms where correct operation of this code cannot be guaranteed, so the code is not used on such systems. You can find out which code is being used by checking sys.float_repr_style, which will be short if the new code is in use and legacy if it isn’t.

Implemented by Eric Smith and Mark Dickinson, using David Gay’s dtoa.c library; issue 7117.

他们说有些平台不能保证正确操作(我假设 dtoa.c),但不要说是哪个平台限制导致了这个问题。

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

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

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

/* 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

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

>>> float.__getformat__('double')
'IEEE, little-endian'

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

第二个可能出错的地方是我们确实有 IEEE 754 binary64 格式的双打,但是 Python 的构建机器无法弄清楚如何确保浮点计算的 53 位精度对于这个平台。 dtoa.c 源代码要求我们能够以 53 位的精度执行所有浮点运算(无论是在硬件还是软件中实现)。对于使用 x87 浮点单元进行双精度计算(与较新的 SSE2 指令相反)的英特尔处理器来说,这尤其是一个问题:x87 的默认精度是 64 位,并将其用于双精度计算使用该默认精度设置会导致 double rounding,这打破了 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.