classification
Title: str(float) failure
Type: Stage:
Components: Interpreter Core, Windows Versions: Python 3.1, Python 2.7
process
Status: closed Resolution: wont fix
Dependencies: Superseder:
Assigned To: mark.dickinson Nosy List: Kiriakos.Vlahos, Muhammad.Alkarouri, brian.curtin, eric.smith, loewis, malkarouri, mark.dickinson, pitrou, sjmachin, skrah, tim.peters
Priority: normal Keywords:

Created on 2010-09-29 03:11 by Kiriakos.Vlahos, last changed 2011-10-23 19:11 by mark.dickinson. This issue is now closed.

Files
File name Uploaded Description Edit
fpuspeed.c skrah, 2010-09-30 09:54
Messages (42)
msg117574 - (view) Author: Kiriakos Vlahos (Kiriakos.Vlahos) Date: 2010-09-29 03:11
I am the author of PyScripter a popular python IDE (pyscripter.googlecode.com).  Following a user report I found out that str(float) occasionally produces wrong results with Python 2.7 and 3.1.

eg.
>>> str(38210.0)  //wrong
'3820:.0'
>>> str(37210.0) // correct
'37210.0'
>>> str(36210.0)  //wrong
'3620:.0'

This only happens with the embedded python engine which uses the pythonxx.dll of the official distribution.  It does not happen using the stand alone interpreter of the PyScripter remote engine.

The recent changes in Python 3.2a2 fix this issue.
Any ideas why the embedded Python would give different results from the stand alone interpreter?
msg117579 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2010-09-29 07:16
This sounds similar to issue 9215, which was due to a compiler optimization bug.  Certainly it points to something going wrong in _Py_dg_dtoa.

What platform are these results from?

Do you have minimal code that can be used to reproduce?

I'm surprised that 3.2 fixes this:  the float-to-string conversion code is pretty much identical in both 3.1 and 3.2.
msg117580 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2010-09-29 07:27
> I'm surprised that 3.2 fixes this:  the float-to-string conversion code > is pretty much identical in both 3.1 and 3.2.

Whoops---not quite.  The conversion code *is* pretty much identical, but 3.2 now uses a different algorithm for str (it's equal to repr now).  So I'd expect that you'll see the issue in 3.2 too if you try something like

    '%.12g' % 38210.0

Kiriakos, can you explain a bit more what the difference is between the 'remote engine' and the 'stand along interpreter'?  Is the core Python library compiled using different compilers for these two?

Eric, are you able to reproduce this at all?  I don't have access to Windows at the moment.
msg117583 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2010-09-29 08:56
From their web page, it looks like PyScripter only runs on Windows, so I assume these results are generated there.

I won't be able to test on Windows until tonight.

Kiriakos: Does this only happen within PyScripter, or does it also happen when you use the python.exe using the same pythonxx.dll?
msg117584 - (view) Author: Kiriakos Vlahos (Kiriakos.Vlahos) Date: 2010-09-29 08:58
PyScripter is a Windows only IDE.  I am using the official release 
*** Python 2.7 (r27:82525, Jul  4 2010, 09:01:59) [MSC v.1500 32 bit (Intel)] on win32. ***

Python 3.2a2 fixes this since, according to SVN, str is now using the same code (or at least the same parameters to the _Py_dg_dtoa call) as repr.

I am afraid I do not have a minimal code to reproduce this, since the error only occurs with the python.dll embedded to PyScripter.  To reproduce with PyScripter you need to

a) Download and install the latest version of PyScripter from pyscripter.googlecode.com
b) Set the python engine to the internal (embedded python) using the menu (Run, Python Engine, Internal)
c) Execute in the interpreter window str(38210.0) etc.

The puzzling thing is that the same Python.dll when used by python.exe and not PyScripter produces correct results.  PyScripter does not mess up with built-ins in any way or set any special flags and I see no reason why results would differ.
msg117585 - (view) Author: Kiriakos Vlahos (Kiriakos.Vlahos) Date: 2010-09-29 09:07
Answer to Mark's question:

*** Python 3.2a2 (r32a2:84522, Sep  5 2010, 22:35:34) [MSC v.1500 32 bit (Intel)] on win32. ***
>>> '%.12g' % 38210.0
'3820:'

So indeed the error still exists in _Py_dg_dtoa.

The internal engine uses an embedded python.dll.  The remote engine uses a stand-alone pythonw.exe in a separate process and communicates with it with rpyc (http://rpyc.wikidot.com/).
msg117619 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2010-09-29 15:15
> The puzzling thing is that the same Python.dll when used by python.exe and not PyScripter produces correct results.

Yes, this is indeed puzzling.  Are you absolutely sure that both python.exe and PyScripter are using the exact same Python.dll file?  E.g., can you check that renaming/deleting/moving the Python.dll file to somewhere else causes both python.exe and PyScripter to fail to execute?

I really can't think of anything in the environment which might affect whether this bug occurs or not.

It's difficult to proceed here without a concrete way to reproduce the error.  I can (and will) add the particular bad values you found as new testcases, so that if the error is present on any of the buildbots it'll show up.
msg117620 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2010-09-29 15:21
It's interesting to note that '9' is ascii 57, and ':' is 58. It's like the code is incrementing the wrong digit. If it's related to that, that indeed sounds like a compiler optimization bug to me, but of course I'm just guessing. And I'm not sure that conclusion matches the rest of the known facts.
msg117622 - (view) Author: Brian Curtin (brian.curtin) * (Python committer) Date: 2010-09-29 15:32
I get different results than Kiriakos' last example.


>PCbuild\amd64\python_d.exe
Python 3.2a2+ (py3k, Sep 29 2010, 09:43:42) [MSC v.1500 64 bit (AMD64)] on win32

Type "help", "copyright", "credits" or "license" for more information.
>>> '%.12g' % 38210.0
'38210'
msg117623 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2010-09-29 15:43
> It's interesting to note that '9' is ascii 57, and ':' is 58.

Right;  it's that part that convinces me that the problem is somewhere deep in _Py_dg_dtoa, in the guts of the float to string conversion, where a xxx999999... result is rounded up to xx(x+1)000000... incorrectly.  And it seems at least possible that there's a compiler bug somewhere, since it's happened before.  It's also possible that there's a bug in _Py_dg_dtoa;  this seems fairly unlikely (but certainly not out of the question), since this bit is pretty much exactly David Gay's original code.
msg117638 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2010-09-29 18:42
Added the extra test cases (for py3k only) in r85119.
msg117646 - (view) Author: Stefan Krah (skrah) * (Python committer) Date: 2010-09-29 19:18
I can reproduce this using the internal (embedded python) of PyScripter
(nice work BTW!).

I can't reproduce it under any other circumstances. The test case
from #9215 runs fine in VS, and also this produces the correct output:


#include <Python.h>

int
main(int argc, char *argv[])
{
  Py_Initialize();
  PyRun_SimpleString("print str(38210.0)");
  Py_Finalize();
  return 0;
}


I ran all tests with the x86 release of 2.7.
msg117655 - (view) Author: Kiriakos Vlahos (Kiriakos.Vlahos) Date: 2010-09-29 21:04
Does _Py_dg_dtoa depend on FPU flags that affect rounding or exceptions?  I failed to mention that python is embedded in a Delphi executable.  Delphi uses the following code at initialization.

procedure       _FpuInit;
asm
        FNINIT
        FWAIT
{$IFDEF PIC}
        CALL    GetGOT
        MOV     EAX,[EAX].OFFSET Default8087CW
        FLDCW   [EAX]
{$ELSE}
        FLDCW   Default8087CW
{$ENDIF}
end;

  Default8087CW: Word = $1332;{ Default 8087 control word.  FPU control
                                register is set to this value.
                                CAUTION:  Setting this to an invalid value
                                could cause unpredictable behavior. }
msg117656 - (view) Author: Kiriakos Vlahos (Kiriakos.Vlahos) Date: 2010-09-29 21:13
Let me that add that it is impossible to fully unit test for the correctness of the str(float).  I only found out by accident, because one of the users bumped into such a case.  I tried to find a pattern in the misbehaved cased and it was rather difficult.  Here is what I got but it is not conclusive

-  If the number has decimal points it prints correctly. Problems only occur with xxxxxx.0
-  More specifically they only occur with xxxxx1.0
-  Small numbers (less than 10000) print OK.
msg117659 - (view) Author: Kiriakos Vlahos (Kiriakos.Vlahos) Date: 2010-09-29 21:45
OK problem solved!
If I set the FPU control word to $00xx I get the correct answers.  Now I think that if _Py_dg_dtoa depends on specific values for the FPU control word that is bad design and likely to lead to such problems.
msg117662 - (view) Author: Kiriakos Vlahos (Kiriakos.Vlahos) Date: 2010-09-29 21:56
If _Py_dg_dtoa requires a specific FPU control word to work correctly, it should save its state, set it to the desired state and restore it after finishing.
msg117665 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2010-09-29 22:05
I agree that in an ideal world there would not be a dependency on global flags.

There's no doubt a performance issue with doing so, although someone would have to measure that. It may well be swamped by the memory allocation, etc. that is going on at the same time and so won't matter.

Mark will no doubt know this better than I do, but I also assume that there's an issue with thread safety when changing such global state.
msg117672 - (view) Author: Kiriakos Vlahos (Kiriakos.Vlahos) Date: 2010-09-29 22:56
Actually with control word $0032 or $3F I still do not get identical results to python.exe.

PyScripter
>>> '%.12g' % 38210.0
'38210.0009918'
>>> str(38210.0)
'38210.0009918'

Python
>>> '%.12g' % 38210.0
'38210'
>>> str(38210.0)
'38210.0'

Does anybody know what is the FPU control word should be to match the results of Python?
msg117674 - (view) Author: Kiriakos Vlahos (Kiriakos.Vlahos) Date: 2010-09-29 23:10
Also note that different compilers initialize the FPU control word with different values.  This creates a problem with embedded python that behaves differently or even produces wrong results depending on which language/compiler is used to embed it.  At least this is a documentation issue.  The expected value of the FPU control word should be documented.
msg117675 - (view) Author: Kiriakos Vlahos (Kiriakos.Vlahos) Date: 2010-09-29 23:26
I found out that $x2xx (test both $12xx and $02xx) gives identical results to python.  Here is what it means.

The PC field (bits 9 and 8) or Precision Control determines to what precision the FPU rounds results after each arithmetic instruction in one of three ways:

00 = 24 bits (REAL4)
01 = Not used
10 = 53 bits (REAL8) <- This is required by _Py_dg_dtoa
11 = 64 bits (REAL10) (this is the initialized state) 

So contrary to my expectation it is not the rounding control bits but the Precision control bits that matter.
msg117701 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2010-09-30 07:09
> Delphi uses the following code at initialization.

Yep.  That would explain the problem.  On x86 machines, Python's string-to-float and float-to-string conversions require that the x87 FPU has precision set to 53 bits rather than 64 bits (and also that the FPU rounding mode is round-half-to-even, but this rarely gets changed).

There's a configure-time check that works out whether resetting the precision is necessary;  if so, the precision is changed before each conversion and reverted again afterwards (see the _Py_SET_53BIT_PRECISION_START and _Py_SET_53BIT_PRECISION_END macros used in Python/pystrtod.c ).  It looks like you may need to override these macros for PyScripter.

Note that this isn't usually a problem on Windows:  the default setting on Windows is 53 bit precision;  I've no idea why Delphi changes it.  The main problem platform is 32-bit Linux, which uses 64-bit precision by default.  (And 64-bit Linux generally uses the appropriate SSE2 instructions instead of the x87; these are always 53-bit precision.)

So in general there's an issue if the runtime FPU settings don't match the configure-time FPU settings.  I'm not sure what the best mechanism for solving this is.  Checking the FPU state before *every* conversion would be possible, I guess, but it most cases that's unnecessary.
msg117702 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2010-09-30 07:15
[Eric]
> There's no doubt a performance issue with doing so, although someone
> would have to measure that. It may well be swamped by the memory
> allocation, etc. that is going on at the same time and so won't matter.

Yes, I think changing the FPU state involves a pipeline flush, with potentially serious performance impact.  But as you say, that may well be insignificant compared with everything else that's going on.

> Mark will no doubt know this better than I do, but I also assume that
> there's an issue with thread safety when changing such global state.

I don't *think* there's an issue here:  wouldn't FPU state be thread-local?
msg117703 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2010-09-30 07:35
> It looks like you may need to override these macros for PyScripter.

Stupid.  Of course, this isn't an option if you're using the existing Python dll directly.

For PyScripter, can you alter your Delphi layer to drop back to the normal default 53-bit precision before calling any Python stuff?  (Isn't there a SetPrecisionMode function?)
msg117714 - (view) Author: Stefan Krah (skrah) * (Python committer) Date: 2010-09-30 09:54
I wonder if calling _Py_SET_53BIT_PRECISION_START/_Py_SET_53BIT_PRECISION_END 
every time will have any measurable effect on performance.  First, string
conversions have a lot of overhead already. Then, for compilers that already
set the correct control word, only fnstcw is called. 


Attached is a quick and dirty benchmark. The correct state is set at
the start of the program. The first loop does not change the FPU state,
the second one uses the macros, the third one always sets/restores. 


time:                   0.000000    result: 1.90013e+122
time (fnstcw):          0.570000    result: 1.90013e+122
time (fnstcw/fldcw):    2.560000    result: 1.90013e+122



I would feel more comfortable if the correct FPU state is guaranteed.
msg117720 - (view) Author: Stefan Krah (skrah) * (Python committer) Date: 2010-09-30 11:07
I benchmarked _PyOS_ascii_strtod without the macros, with the macros
and with always calling both fnstcw/fldcw. There is no real difference:


import timeit

s = "str(38210.0)"
t = timeit.Timer(stmt=s)

t.timeit(number=10000000)
t.timeit(number=10000000)
t.timeit(number=10000000)

# None
>>> t.timeit(number=10000000)
3.7519991397857666
>>> t.timeit(number=10000000)
3.759944200515747
>>> t.timeit(number=10000000)
3.7730538845062256
>>>

# Macros
>>> t.timeit(number=10000000)
3.780745029449463
>>> t.timeit(number=10000000)
3.777444839477539
>>> t.timeit(number=10000000)
3.7622230052948

# fnstcw/fldcw
>>> t.timeit(number=10000000)
3.765655994415283
>>> t.timeit(number=10000000)
3.7517099380493164
>>> t.timeit(number=10000000)
3.749257802963257
msg117721 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2010-09-30 11:11
Thanks for the numbers, Stefan.

What about in the reverse direction (string to float)?  I don't expect any real difference there, either, but it would be good to check.
msg117722 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2010-09-30 11:12
Whoops;  that *was* string to float.  How about float to string?
msg117728 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2010-09-30 12:04
> I would feel more comfortable if the correct FPU state is guaranteed.

I agree, in principle.  In practice there are some thorny issues to deal with, and things to think about:

(1) The method for getting and setting the FPU precision varies from platform to platform

(2) Most modern x86 processors have *two* FPUs that might be used (the SSE unit, and the x87), each with their own control words.

(3) Depending on the platform and compiler flags, a Python executable / shared library might be using the x87 instructions, the SSE2 instructions, or a mixture of both.

(4) We need to bear in mind that an executable created on a modern 32-bit Linux machine (with SSE2) might still need to run on older machines that don't have SSE2.
msg117729 - (view) Author: Stefan Krah (skrah) * (Python committer) Date: 2010-09-30 12:11
Mark Dickinson <report@bugs.python.org> wrote:
> Whoops;  that *was* string to float.  How about float to string?

These are the results for format_float_short. The first one is quite funny:

If the control word is left as is (64-bit prec on Linux), _Py_dg_dtoa
apparently requires more iterations (but still produces the correct
result in this case).

import timeit

s = "str(38210.0)"
t = timeit.Timer(stmt=s)

4.266580820083618
>>> t.timeit(number=10000000)
4.3112568855285645
>>> t.timeit(number=10000000)
4.313380002975464
>>>

3.7413151264190674
>>> t.timeit(number=10000000)
3.7296619415283203
>>> t.timeit(number=10000000)
3.737776041030884

3.756165027618408
>>> t.timeit(number=10000000)
3.775428056716919
>>> t.timeit(number=10000000)
3.775447130203247

In general, execution times for _Py_dg_dtoa vary quite a bit depending on
the number that is converted:

5.097490072250366

2.417008876800537

Judging from these numbers, I think the macros could be called by default without
any real effect on performance. How about setting the rounding mode as well (you
suggested that in #9009)?
msg117730 - (view) Author: Stefan Krah (skrah) * (Python committer) Date: 2010-09-30 12:14
The tracker swallowed some parts of my mail:

In general, execution times for _Py_dg_dtoa vary quite a bit depending on
the number that is converted:

>>> s = "str(1.00000000000000005e300)"
>>> t = timeit.Timer(stmt=s)
>>> t.timeit(number=10000000)
5.097490072250366

>>> s = "str(1.00000000000000005e384)"
>>> t = timeit.Timer(stmt=s)
>>> t.timeit(number=10000000)
2.417008876800537
msg117734 - (view) Author: Stefan Krah (skrah) * (Python committer) Date: 2010-09-30 14:10
On an older Celeron platform the differences are up to 7%, but again,
the number that is converted has a far greater impact:


None:
=====

>>> s = "str(38210.0)"
>>> t = timeit.Timer(stmt=s)
>>> 
>>> t.timeit(number=1000000)
3.277189016342163
>>> t.timeit(number=1000000)
3.293405055999756
>>> t.timeit(number=1000000)
3.302845001220703
>>> 
>>> s = "str(1.31232223e300)"
>>> t = timeit.Timer(stmt=s)
>>> 
>>> t.timeit(number=1000000)
5.678447008132935
>>> t.timeit(number=1000000)
5.695156097412109
>>> t.timeit(number=1000000)
5.690100193023682


fnstcw only:
============

>>> s = "str(38210.0)"
>>> t = timeit.Timer(stmt=s)
>>> 
>>> t.timeit(number=1000000)
3.3676700592041016
>>> t.timeit(number=1000000)
3.339860200881958
>>> t.timeit(number=1000000)
3.365180015563965
>>> 
>>> s = "str(1.31232223e300)"
>>> t = timeit.Timer(stmt=s)
>>> 
>>> t.timeit(number=1000000)
5.869584798812866
>>> t.timeit(number=1000000)
5.8620688915252686
>>> t.timeit(number=1000000)
5.882143020629883
>>> 


fnstcw/fldcw:
=============

>>> s = "str(38210.0)"
>>> t = timeit.Timer(stmt=s)
>>> 
>>> t.timeit(number=1000000)
3.5034677982330322
>>> t.timeit(number=1000000)
3.496767044067383
>>> t.timeit(number=1000000)
3.5118331909179688
>>> 
>>> s = "str(1.31232223e300)"
>>> t = timeit.Timer(stmt=s)
>>> 
>>> t.timeit(number=1000000)
5.808370113372803
>>> t.timeit(number=1000000)
5.80784010887146
>>> t.timeit(number=1000000)
5.837070941925049
>>>
msg117735 - (view) Author: Tim Peters (tim.peters) * (Python committer) Date: 2010-09-30 14:21
About thread state, the C standard is no help.  That's an OS decision.  All OSes I'm aware of do save/restore FPU state across thread switches.  Doesn't mean all OSes do, just that I don't know of an exception.
msg117736 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2010-09-30 14:37
> There's a configure-time check that works out whether resetting the
> precision is necessary;  if so, the precision is changed before each
> conversion and reverted again afterwards

How about doing the check in Py_Initialize() instead? Then it will work for embedders too.
msg117737 - (view) Author: Kiriakos Vlahos (Kiriakos.Vlahos) Date: 2010-09-30 14:40
>>For PyScripter, can you alter your Delphi layer to drop back to the >>normal default 53-bit precision before calling any Python stuff? 

Yes sure. That is how I traced the source of the problem.
msg117739 - (view) Author: Kiriakos Vlahos (Kiriakos.Vlahos) Date: 2010-09-30 14:56
>>How about doing the check in Py_Initialize() instead? Then it will >>work for embedders too.
It is not good practice for DLLs to change the FPU control word when loaded, because the host application may have set it to a specific value for a good reason.  Delphi provides a SafeLoadLibrary function that saves the the control word and restores it after loading the DLL.

If _Py_dg_dtoa can be made to work correctly independently of the value of the FPU control word that should be much better.  If this means setting and restoring the control word, then this sounds like a good way forward.

By the way the reason Delphi sets the precision to 64bits is that by design all floating calculations are done in 64 bit presision and then truncated back if needed.  A native 10 byte floating type called Extended is also provided.
msg117741 - (view) Author: Kiriakos Vlahos (Kiriakos.Vlahos) Date: 2010-09-30 14:56
>>How about doing the check in Py_Initialize() instead? Then it will >>work for embedders too.
It is not good practice for DLLs to change the FPU control word when loaded, because the host application may have set it to a specific value for a good reason.  Delphi provides a SafeLoadLibrary function that saves the the control word and restores it after loading the DLL.

If _Py_dg_dtoa can be made to work correctly independently of the value of the FPU control word that should be much better.  If this means setting and restoring the control word, then this sounds like a good way forward.

By the way the reason Delphi sets the precision to 64bits is that by design all floating calculations are done in 64 bit presision and then truncated back if needed.  A native 10 byte floating type called Extended is also provided.
msg118738 - (view) Author: Muhammad Alkarouri (Muhammad.Alkarouri) Date: 2010-10-15 03:27
I cam across another issue that was triggered by the same problem. I am explaining it here though I am not sure if it is going to affect the solution one way or the other.

The issue is explained in the post http://stackoverflow.com/questions/3933851/nan-giving-an-error-depending-on-python-startup

Namely, running the command

float('nan')

on a Python (tested with version 2.6.4) embedded in a Delphi 2009 application gives a EInvalidOp Delphi exception.

The solution as given in the link is to change the FPY control word (and revert it back when done).

The issue is important because it may break unexpected Python code. In my case, it broke the command

import json

because of the line

NaN, PosInf, NegInf = float('nan'), float('inf'), float('-inf')

in json.decoder. I have no idea what else may break in the standard library.

The reason I bring this up here is because the problem with the mismatch in FPU control world expectations between Delphi and Python is not localised. Given that the behaviour of float('nan') is assumed to be guaranteed by library developers (see PEP 754), this may come up anywhere.
msg118740 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2010-10-15 05:52
Interesting. I'd like to propose than that this is resolved as "won't fix", i.e. embedding Python into Delphi is declared as just not supported (or using floating-point operations in such an environment is not supported).
msg118760 - (view) Author: Kiriakos Vlahos (Kiriakos.Vlahos) Date: 2010-10-15 12:04
I would like to say that these are two separate issues.  One is about the precision flag and the second about the exception masking flags of the FPU control words. Both issues affect a wider number of users than Python embedders using Delphi. For example C# uses 80 bit precision if I understand http://blogs.msdn.com/b/davidnotario/archive/2005/08/08/449092.aspx well.

Also both issues are primarily documentation issues.  If Python libraries make certain assumptions about the state of the FPU control word, these assumptions should be documented and users can then accommodate them.
msg118766 - (view) Author: Muhammad Alkarouri (malkarouri) Date: 2010-10-15 13:07
On 15 October 2010 06:52, Martin v. Löwis <report@bugs.python.org> wrote:
>
> Martin v. Löwis <martin@v.loewis.de> added the comment:
>
> Interesting. I'd like to propose than that this is resolved as "won't fix", i.e. embedding Python into Delphi is declared as just not supported (or using floating-point operations in such an environment is not supported).

The problem is defining what does "such an environment" mean. It is
not necessarily Delphi, as this can happen whenever the FPU control
word is changed by an embedding application.
Kiriakos makes a good point. The underlying issue is that Python make
certain assumptions about the FPU control words, and there are
probably other global assumptions lurking elsewhere.
As I see it, the easiest solution is to document these assumptions as
and when they are found. Then it becomes the responsibility of the
hosting application to satisfy them.
Delphi already has to accomodate Python C heritage, for example by
defining functions used from Python with the C calling convention.
This would be just one more thing to remember, and in fact can be done
inside the Python4Delphi libraries once the Python behaviour is
defined and documented.

Also, banning floating-point operations is not a solution in my
opinion because Python libraries (standard and external) do not have
such a distinction. So an unknown of unexpected libraries (like json)
would break. And large parts of Python functionality wouldn't be
available.

On 15 October 2010 13:04, Kiriakos Vlahos <report@bugs.python.org> wrote:
>
> Kiriakos Vlahos <pyscripter@gmail.com> added the comment:
>
> I would like to say that these are two separate issues.  One is about the precision flag and the second about the exception masking flags of the FPU control words. Both issues affect a wider number of users than Python embedders using Delphi. For example C# uses 80 bit precision if I understand http://blogs.msdn.com/b/davidnotario/archive/2005/08/08/449092.aspx well.

Technically they are, yes. But they are both affected by any solution
that would incorporate preserving or documenting the FPU control word
for embedding applications. May be I should have opened a new issue.
msg118773 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2010-10-15 13:50
> For example C# uses 80 bit precision

No, I don't think that's true.  It uses the x87, with its 64-bit internal precision, but I'm fairly sure that (as is almost always true in a Windows environment, except if you're using Delphi, apparently) the FPU precision is still set to 53-bit precision.

> if I understand http://blogs.msdn.com/b/davidnotario/archive/2005/08/08/449092.aspx well.

And that article explicitly confirms the use of 53-bit precision:

"Precision is set by default in VC++ and CLR apps to ‘double precision’, which means that if you are operating with operands of type float, results of operations done with floats actually exist in the x87 stack as if there were of type double. In fact, it’s even weirder than that. They will have the mantissa of a double, but the range (exponent) of an extended double (80 bit)."

i.e., it's using the x87 FPU with precision set to 53 bits.
msg146249 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2011-10-23 19:11
Closing as "won't fix", for reasons given above.
History
Date User Action Args
2011-10-23 19:11:13mark.dickinsonsetstatus: open -> closed
resolution: wont fix
messages: + msg146249
2010-10-15 13:50:56mark.dickinsonsetmessages: + msg118773
2010-10-15 13:07:54malkarourisetnosy: + malkarouri
messages: + msg118766
2010-10-15 12:04:44Kiriakos.Vlahossetmessages: + msg118760
2010-10-15 05:52:04loewissetmessages: + msg118740
2010-10-15 03:27:04Muhammad.Alkarourisetnosy: + Muhammad.Alkarouri
messages: + msg118738
2010-10-05 07:23:25mark.dickinsonsetassignee: mark.dickinson
2010-09-30 14:56:50Kiriakos.Vlahossetmessages: + msg117741
2010-09-30 14:56:30Kiriakos.Vlahossetmessages: + msg117739
2010-09-30 14:40:26Kiriakos.Vlahossetmessages: + msg117737
2010-09-30 14:37:45pitrousetnosy: + pitrou
messages: + msg117736
2010-09-30 14:21:00tim.peterssetnosy: + tim.peters
messages: + msg117735
2010-09-30 14:10:38skrahsetmessages: + msg117734
2010-09-30 12:14:27skrahsetmessages: + msg117730
2010-09-30 12:11:35skrahsetmessages: + msg117729
2010-09-30 12:04:13mark.dickinsonsetmessages: + msg117728
2010-09-30 11:12:17mark.dickinsonsetmessages: + msg117722
2010-09-30 11:11:51mark.dickinsonsetmessages: + msg117721
2010-09-30 11:07:05skrahsetmessages: + msg117720
2010-09-30 09:54:26skrahsetfiles: + fpuspeed.c

messages: + msg117714
2010-09-30 07:35:04mark.dickinsonsetmessages: + msg117703
2010-09-30 07:15:58mark.dickinsonsetmessages: + msg117702
2010-09-30 07:09:25mark.dickinsonsetmessages: + msg117701
2010-09-29 23:26:39Kiriakos.Vlahossetmessages: + msg117675
2010-09-29 23:10:22Kiriakos.Vlahossetmessages: + msg117674
2010-09-29 22:56:33Kiriakos.Vlahossetmessages: + msg117672
2010-09-29 22:05:30eric.smithsetmessages: + msg117665
2010-09-29 21:56:48Kiriakos.Vlahossetmessages: + msg117662
2010-09-29 21:45:42Kiriakos.Vlahossetmessages: + msg117659
2010-09-29 21:13:04Kiriakos.Vlahossetmessages: + msg117656
2010-09-29 21:04:13Kiriakos.Vlahossetmessages: + msg117655
versions: - Python 3.2
2010-09-29 20:20:51loewissetnosy: + loewis
2010-09-29 19:18:29skrahsetnosy: + skrah
messages: + msg117646
2010-09-29 18:42:34mark.dickinsonsetmessages: + msg117638
2010-09-29 15:43:35mark.dickinsonsetmessages: + msg117623
2010-09-29 15:32:10brian.curtinsetnosy: + brian.curtin
messages: + msg117622
2010-09-29 15:21:56eric.smithsetmessages: + msg117620
2010-09-29 15:17:04mark.dickinsonsetversions: + Python 3.2
2010-09-29 15:15:03mark.dickinsonsetmessages: + msg117619
2010-09-29 09:07:54Kiriakos.Vlahossetmessages: + msg117585
2010-09-29 08:58:01Kiriakos.Vlahossetmessages: + msg117584
2010-09-29 08:56:24eric.smithsetmessages: + msg117583
2010-09-29 07:27:24mark.dickinsonsetmessages: + msg117580
2010-09-29 07:16:57mark.dickinsonsetmessages: + msg117579
2010-09-29 07:04:45r.david.murraysetnosy: + mark.dickinson, eric.smith
2010-09-29 07:02:30sjmachinsetnosy: + sjmachin
2010-09-29 03:11:29Kiriakos.Vlahoscreate