What makes Python float_repr_style use legacy?

On almost every system, Python can give you a human-readable concise understanding of floating point, rather than 17-digit machine precision:

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'

      

On the ARM926EJ-S, you won't get a quick glimpse:

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 seems to have added this short representation to repr (), for most systems :

Conversions between floating point numbers and strings are now correctly rounded on most platforms. These conversions happen in many different places: str () on floats and complex numbers; float and complexconstructors; digital formatting; serializing and deserializing floats and complex numbers using marshall, pickle and json modules; parsing float and imaginary literals in Python code; and decimal floating point conversion.

Due to this, the expression () of a floating point number x now returns a result based on the shortest decimal string, which should be rounded to x when properly rounded (rounding to a semicircle). It used to give a string based on rounding x to 17 decimal numbers.

The rounding library responsible for this improvement works on Windows and Unix platforms using the gcc, icc or suncc compilers. There may be a small number of platforms where this code cannot be guaranteed to work correctly, so the code is not used on such systems . You can find out what code is being used when checking sys.float_repr_style, which will be short if new code is in use and deprecated if not.

Implemented by Eric Smith and Mark Dickinson using the David Gays library dtoa.c

; issue 7117 .

It is said that some platforms cannot guarantee it will work correctly (I dtoa.c

guess), but don't say what platform limitation are the ones causing this.

What is ARM926EJ-S, which means short float repr () cannot be used?

+3


source to share


1 answer


Short answer: This is most likely not a platform limitation, but a limitation of the Python build mechanism: it has no universal way to set 53-bit floating point precision.

See the file Include/pyport.h

in the Python source distribution for details . Here's an excerpt:

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

      

Basically, there are two things that can go wrong. First, the Python config cannot identify the floating point C double format. This format is almost always IEEE 754 binary64, but sometimes the config script cannot figure it out. This first preprocessor #if

checks the above snippet. Take a look at pyconfig.h

the compile-time generated file and see at least one of the macros DOUBLE_IS_...

is #define

d. Alternatively, try this on the Python command line:



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

      

If you see something similar above, this part should be fine. If you see something like 'unknown'

, then Python was unable to identify the floating point format.

The second thing that can go wrong is that we have IEEE 754 dual format, but Python's build mechanisms can't figure out how to provide 53-bit floating point precision for that platform. The source dtoa.c

requires that we perform all floating point operations (whether implemented in hardware or software) with 53 bit precision. This is especially a problem for Intel processors that use the x87 floating point block for double precision computation (as opposed to the new SSE2 instructions): the default precision for x87 is 64-bit and uses it for double precision with this precision setting by default results in double rounding , which violates assumptionsdtoa.c

... So during configuration, the build engine runs a check to see (1) if double rounding is a potential problem, and (2) if so, if there is a way to put the FPU at 53-bit precision. So now you want to look pyconfig.h

for macros X87_DOUBLE_ROUNDING

and HAVE_PY_SET_53BIT_PRECISION

.

So it can be both. If I had to guess, I would guess that on this platform double rounding is showing up as a problem and no one knows how to fix it. The solution in this case is to adapt pyport.h

to define macros in _Py_SET_53BIT_PRECISION_*

any platform-specific way to get that 53-bit precision mode and then define HAVE_PY_SET_53BIT_PRECISION

.

+3


source







All Articles