是什么导致Python的float_repr_style使用遗产?

时间:2015-04-28 13:01:23

标签: 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'

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(),适用于大多数系统

  

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

     

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

     

负责此改进的舍入库可在Windows和Unix平台上使用gcc,icc或suncc编译器。 可能会有少量平台无法保证正确操作此代码,因此代码不会在此类系统上使用。您可以通过检查sys.float_repr_style找出正在使用的代码,如果新代码正在使用,它将很短,如果不是,则会遗留下来。

     

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

他们说某些平台无法保证正确的操作(我假设为dtoa.c),但是没有说明造成这种情况的平台限制。

ARM926EJ-S的含义是什么意思是不能使用短浮点数repr()?

1 个答案:

答案 0 :(得分:3)

简短回答:它可能不是平台的限制,而是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_...个宏中是否至少有一个是#define d。或者,在Python提示符下尝试:

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

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

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

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