This issue tracker has been migrated to GitHub ,
and is currently read-only.
For more information,
see the GitHub FAQs in the Python's Developer Guide.
Created on 2012年01月27日 14:58 by samuel.iseli, last changed 2022年04月11日 14:57 by admin. This issue is now closed.
| Files | ||||
|---|---|---|---|---|
| File name | Uploaded | Description | Edit | |
| 120127_float_dtoa_fix_py2.7.2.diff | samuel.iseli, 2012年01月27日 14:58 | review | ||
| 74745.patch | samuel.iseli, 2012年02月03日 13:51 | review | ||
| 74747.patch | samuel.iseli, 2012年02月03日 15:36 | |||
| 120206_set_53bit_precision.patch | samuel.iseli, 2012年02月06日 23:25 | review | ||
| issue13889.diff | skrah, 2012年03月13日 11:47 | based on patch by samuel.iseli | review | |
| issue13889_2.diff | mark.dickinson, 2012年04月15日 12:03 | review | ||
| Messages (24) | |||
|---|---|---|---|
| msg152099 - (view) | Author: Samuel Iseli (samuel.iseli) | Date: 2012年01月27日 14:58 | |
We are using python as an embedded scripting environment in our ERP-product. Since upgrading to python2.7 we have serious issues with floats: >>> 28710.0 '2870:.0' >>> round(28710.0) 2870.0 We are embedding Python in a Delphi-application. The problem was already discussed in issue9980 and has to do with Delphi setting the FPU precision to 64bit (and relying on this setting) while the standard with Microsoft Tools is 53bits. The routines _Py_dg_dtoa and _Py_dg_strtod in dtoa.c rely on the FPU precision set to 53bits. Issue9980 was closed as "won't fix" but I propose to reconsider this decision for the following reasons: - Delphi is still an important development environment for native win32 applications and has excellent Python embedding support through PythonForDelphi (http://code.google.com/p/python4delphi). - Ensuring 53bit before calling python code is not practical in an embedded python environment with extensions in delphi (python may also call code that is implemented in delphi). - The changes needed in pythoncore are minimal. Tests documented in issue9980 found no measurable performance impact. - FPU precision switching is needed and already (partially) implemented for linx, where 64bit prec is standard. Fixing this issues is absolutely vital for us, so we needed to compile a custom version of pythoncore. I appended a .diff file detailling the patch. Changes are needed in 2 places: - pyport.h, defining the _PY_SET_53_BIT_PRECISION macros for MS visual c compiler - floatobject.c, insert precision switching macros in _Py_double_round function. In pystrtod.c the precision switching macros are already used. pystrtod.c and floatobject.c are the only places in CPython where the dtoa.c functions are called. The macros for visual-c are activated by defining HAVE_VC_FUNC_FOR_X87 preprocessor-symbol. Hoping for inclusion of this patch. Cheers Samuel |
|||
| msg152111 - (view) | Author: Mark Dickinson (mark.dickinson) * (Python committer) | Date: 2012年01月27日 19:06 | |
Samuel, can you regenerate your patch? The contents don't look right---I see changes to pyport.h, but none to floatobject.c (and some other spurious-looking changes to the project file). |
|||
| msg152116 - (view) | Author: Mark Dickinson (mark.dickinson) * (Python committer) | Date: 2012年01月27日 20:22 | |
I'm a bit disturbed that we're not using the _Py_SET_53BIT_PRECISION_* macros in _Py_double_round; unless I'm missing something, that seems like a major omission. |
|||
| msg152120 - (view) | Author: Roundup Robot (python-dev) (Python triager) | Date: 2012年01月27日 21:20 | |
New changeset 5b8800004955 by Mark Dickinson in branch '3.2': Issue #13889: Add missing _Py_SET_53BIT_PRECISION_* calls around uses of dtoa.c functions in float round. http://hg.python.org/cpython/rev/5b8800004955 New changeset 265d35e8fe82 by Mark Dickinson in branch 'default': Merge 3.2 -> default (issue 13889) http://hg.python.org/cpython/rev/265d35e8fe82 New changeset eaf553b063a7 by Mark Dickinson in branch '2.7': Issue #13889: Add missing _Py_SET_53BIT_PRECISION_* calls around uses of dtoa.c functions in float round. http://hg.python.org/cpython/rev/eaf553b063a7 |
|||
| msg152122 - (view) | Author: Mark Dickinson (mark.dickinson) * (Python committer) | Date: 2012年01月27日 21:29 | |
> but none to floatobject.c Bah, reading comprehension fail. Now that I look at your patch again, the floatobject.c changes are there (and pretty much match what I just committed). I assume that the changes to pythoncore.vcproj can be disregarded, though? |
|||
| msg152265 - (view) | Author: Samuel Iseli (samuel.iseli) | Date: 2012年01月29日 21:57 | |
Hi Marc, the changes to the pythoncore.vcproj Visual-Studio file define the HAVE_VC_FUNC_FOR_X87 symbol. I use this symbol to enable the precision-setting macros in pyport.h. I made this similar to the existing code for gcc (linux). You can change this but currently this symbol has to be defined somewhere for the macros to have an effect. |
|||
| msg152439 - (view) | Author: Jesús Cea Avión (jcea) * (Python committer) | Date: 2012年02月01日 20:33 | |
Should this bug be marked as "closed+committed"? |
|||
| msg152449 - (view) | Author: Mark Dickinson (mark.dickinson) * (Python committer) | Date: 2012年02月02日 00:33 | |
> Should this bug be marked as "closed+committed"? No, the main issue is still under consideration. There were two issues here: (1) a clear bug, namely that the Py_SET_53BIT_PRECISION_* macros weren't being used for the dtoa calls when rounding, and (2) a proposal to alter the way that the FPU settings are treated on Windows; this is still open. I'll change the type from behaviour, though. |
|||
| msg152458 - (view) | Author: Mark Dickinson (mark.dickinson) * (Python committer) | Date: 2012年02月02日 14:40 | |
> Hi Marc, the changes to the pythoncore.vcproj Visual-Studio file define > the HAVE_VC_FUNC_FOR_X87 symbol. Okay, makes sense. I was distracted by the spurious reordering of in the diff for pythoncore.vcproj. Just to be clear, the intent of the patch is that the FPU state is *always* switched on Windows prior to calling the dtoa.c functions; is that right? Things to think about: - can we avoid *writing* to the x87 / SSE control word if no change is necessary (as is currently done with the gcc code)? We want to avoid unnecessary FPU pipeline flushes. - we need to make sure that the patch works on 64-bit. There's a bit of text at: http://msdn.microsoft.com/en-us/library/c9676k6h.aspx that suggests that in x64 mode, setting the precision is an error. - what happens if the x87 and SSE2 control words have different precisions? Does the patch restore both those precisions correctly? - in the patch, isn't new387controlword unused? I'm not sure that this part of the patch can go into the maintenance branches (2.7, 3.2); if this is a new feature (and I think it is, but I'm willing to be persuaded otherwise), it can only target 3.3. |
|||
| msg152509 - (view) | Author: Samuel Iseli (samuel.iseli) | Date: 2012年02月03日 13:51 | |
I would definitely classify this as a bug in Python 2.7 as it breaks backwards-compatibility for embedding environments that default to 64bit FPU precision (e.g. Delphi). Additionally the bug is very hard to detect and leads to wrong values with possibly disastrous effects. Appended a patch with a new implementation of the Py_SET_53BIT_PRECISION_* macros for win32: - precision is set only when needed - setting and restoring only the x87 controlword (using __control87_2 function). - macros are not used for WIN64 as there's no x87 there - there's no need for a custom symbol in the vc project anymore, as I'm using the predefined _WIN32 symbol. |
|||
| msg152523 - (view) | Author: Samuel Iseli (samuel.iseli) | Date: 2012年02月03日 15:36 | |
There's an excess space after a line continuation backslash in my last patch, so it doesn't compile (pyport.h, line 567). Here's an additional patch that removes the space. Didn't find out how to combine the 2 revisions in one patch-file... Sorry about that. |
|||
| msg152541 - (view) | Author: Mark Dickinson (mark.dickinson) * (Python committer) | Date: 2012年02月03日 16:50 | |
General shape of the patch looks good. I'd suggest using a mask of _MCW_PC | _MCW_RC instead of just _MCW_PC, so that the rounding mode is also set correctly. Probably rarely an issue in practice, but it's the same thing that we're doing on Linux. If this is going near the maintenance branches (2.7, 3.2), we need to be very careful. Have you had the opportunity to test the patch (e.g., run the complete Python test suite) both on 32-bit and 64-bit Windows? |
|||
| msg152724 - (view) | Author: Samuel Iseli (samuel.iseli) | Date: 2012年02月06日 06:40 | |
I can run the tests on 32bit. Would be nice if somebody else could do this on 64bit (my VS2008 machine is currently on 32bit-Windows). |
|||
| msg152728 - (view) | Author: Stefan Krah (skrah) * (Python committer) | Date: 2012年02月06日 08:35 | |
I can run the tests on win64, but it I think it would be nice to have a patch with exactly the same logic as the gcc-asm version (Mark already mentioned _MCW_PC | _MCW_RC). Another thing: _WIN32 might be defined on MinGW, but I'm not sure. If that's the case, it would be nice to guard the VS specific passage with _MSC_VER. |
|||
| msg152799 - (view) | Author: Samuel Iseli (samuel.iseli) | Date: 2012年02月06日 23:25 | |
Completed the patch by adding the rounding-control bits to the mask (_MCW_RC) and making sure the macros only get defined for MS-VC compiler (#ifdef _MSC_VER). Ran the tests (python_d -m test.autotest) on win32. Seems OK. The tests that were skipped or failed don't seem to be connected to this patch: - test_repr failed on trying to import a very long package and module name - test_popen failed with SyntaxError: unexpected EOF while parsing. Here's the summary: 323 tests OK. 2 tests failed: test_popen test_repr 2 tests altered the execution environment: test_distutils test_site 62 tests skipped: test_aepack test_al test_applesingle test_bsddb test_bsddb185 test_bsddb3 test_bz2 test_cd test_cl test_codecmaps_cn test_codecmaps_hk test_codecmaps_jp test_codecmaps_kr test_codecmaps_tw test_commands test_crypt test_curses test_dbm test_dl test_epoll test_fcntl test_fork1 test_gdb test_gdbm test_gl test_grp test_imgfile test_ioctl test_kqueue test_largefile test_linuxaudiodev test_macos test_macostools test_mhlib test_nis test_openpty test_ossaudiodev test_pipes test_poll test_posix test_pty test_pwd test_py3kwarn test_readline test_resource test_scriptpackages test_smtpnet test_socketserver test_sqlite test_ssl test_sunaudiodev test_tcl test_threadsignals test_timeout test_tk test_ttk_guionly test_ttk_textonly test_urllib2net test_urllibnet test_wait3 test_wait4 test_zipfile64 10 skips unexpected on win32: test_bsddb test_bz2 test_gdb test_readline test_sqlite test_ssl test_tcl test_tk test_ttk_guionly test_ttk_textonly [43048 refs] |
|||
| msg155322 - (view) | Author: Mark Dickinson (mark.dickinson) * (Python committer) | Date: 2012年03月10日 16:41 | |
Patch looks fine to me. A couple of minor points (which I'm happy to fix at commit time if you agree, and don't want to create a new patch): - it looks to me as though the #ifdef _WIN32 isn't necessary any more; it's enough that we're on MSVC and that this isn't a 64-bit build. - I'd suggest replacing _PC_53 with _PC_53 | _RC_NEAR. I know it's technically redundant, since _RC_NEAR happens to be 0, but it makes the intent of the code clearer. I'd still want to see all the tests pass on both x64 and x86 Windows before applying this; I may have an opportunity to test this on x64 in the near future. |
|||
| msg155590 - (view) | Author: Stefan Krah (skrah) * (Python committer) | Date: 2012年03月13日 11:47 | |
I've looked at the latest patch: It seems that new_387controlword is not set if old_387controlword already has the desired precision and rounding mode. Attached is a revised patch that uses the same logic as the Linux version. A couple of remarks: - It would be possible to negate (_PC_53|_RC_NEAR) instead of enumerating (_MCW_DN|_MCW_EM|_MCW_IC). I found it nice to see all possibilities listed. - Technically we might need to use #pragma fenv_access (on). I'm not sure where though: If it is set in pyport.h, VS complains that Py_MATH_PI / 180.0 is not constant. The patch is tested on win32/x64. Additionally, the patch is tested with setting the rounding mode to _PC_64 in main.c. Then, the patch is tested with replacing the 'if' bodies by 'abort()'. This shows that in the regular build (_PC_53 on startup) the bodies of the if statements are never executed. Finally, inserting an #error after #if defined(_MSC_VER) && !defined(_WIN64) on the x64 build shows that !defined(_WIN64) really does its job. |
|||
| msg155610 - (view) | Author: Mark Dickinson (mark.dickinson) * (Python committer) | Date: 2012年03月13日 14:02 | |
BTW, the MSDN documentation at http://msdn.microsoft.com/en-us/library/e9b52ceh(v=vs.100).aspx is a bit confusing. Question 1: when doing __control87_2(new, mask, &old, NULL), does the resulting value in old reflect the *new* FPU state or the old one? Question 2: in the example near the bottom of that page, there's code like: control_word_x87 = __control87_2(_PC_24, MCW_PC, &control_word_x87, 0); This looks very odd: we're assigning to control_word_x87, *and* passing it as an output parameter to the call. Moreover, from the documentation the return value from __control87_2 is always 1 to indicate success, so I'm not sure why it's being assigned to control_word_x87. Am I the only person who's confused by this? |
|||
| msg155617 - (view) | Author: Stefan Krah (skrah) * (Python committer) | Date: 2012年03月13日 14:35 | |
Mark Dickinson <report@bugs.python.org> wrote: > http://msdn.microsoft.com/en-us/library/e9b52ceh(v=vs.100).aspx > Question 1: when doing __control87_2(new, mask, &old, NULL), does the > resulting value in old reflect the *new* FPU state or the old one? The new one, but I had to test that manually (see below). > Question 2: in the example near the bottom of that page, there's code like: > > control_word_x87 = __control87_2(_PC_24, MCW_PC, > &control_word_x87, 0); > > This looks very odd: we're assigning to control_word_x87, *and* passing it as an output parameter to the call. Moreover, from the documentation the return value from __control87_2 is always 1 to indicate success, so I'm not sure why it's being assigned to control_word_x87. > > Am I the only person who's confused by this? I was confused as well. I'm positive that it's a cut-and-paste bug in the docs: Probably they had _control87() in that place before, which *does* return the new control word. As you say, the example above clobbers the value that was set via the pointer reference, so the result is always 1. :) |
|||
| msg155619 - (view) | Author: Stefan Krah (skrah) * (Python committer) | Date: 2012年03月13日 14:48 | |
Stefan Krah <report@bugs.python.org> wrote: > > Stefan Krah <stefan-usenet@bytereef.org> added the comment: > > Mark Dickinson <report@bugs.python.org> wrote: > > http://msdn.microsoft.com/en-us/library/e9b52ceh(v=vs.100).aspx > > Question 1: when doing __control87_2(new, mask, &old, NULL), does the > > resulting value in old reflect the *new* FPU state or the old one? > > The new one, but I had to test that manually (see below). Well of course, unless both new and mask are 0, in which case it's the existing state. |
|||
| msg155646 - (view) | Author: Mark Dickinson (mark.dickinson) * (Python committer) | Date: 2012年03月13日 19:04 | |
Thanks for the responses. As far as I'm concerned, this is good to go into all 3 maintained branches. Having said that, the 2.7 and 3.2 branches are currently at release candidate stage, so I think we should wait until after the releases. |
|||
| msg158322 - (view) | Author: Mark Dickinson (mark.dickinson) * (Python committer) | Date: 2012年04月15日 12:03 | |
Slightly reworked patch. I plan to apply this shortly.
- Use ~(_MCW_PC | _MCW_RC) rather than (_MCW_DN | ...), since this seems more future proof: there's a possibility that more flags could be added later.
- Put the usual do { ... } while (0) around the _Py_SET_53BIT_PRECISION_END
- Make it clear that we don't care about the return value of the second two __control87_2 patches.
- Minor style fixes (e.g., spaces around a "bitwise and" ampersand to help distinguish it from an "address of" ampersand).
I'm not too worried about the fenv_access pragma: it seems that the main thing it would guard against is compile-time folding and evaluation of expressions, where the compiler isn't taking the possibility of control word changes into account. As far as I can tell, we shouldn't really care about this, since at the time that Python itself is compiled, the control word is likely to be what we want.
|
|||
| msg158330 - (view) | Author: Roundup Robot (python-dev) (Python triager) | Date: 2012年04月15日 14:14 | |
New changeset dfc9a98a5fef by Mark Dickinson in branch '3.2': Issue #13889: On MSVC builds, set FPU control word at runtime for all string <-> float conversions. Patch by Samuel Iseli and Stefan Krah. http://hg.python.org/cpython/rev/dfc9a98a5fef New changeset 7eca620feb10 by Mark Dickinson in branch 'default': Issue #13889: Merge fix from 3.2. http://hg.python.org/cpython/rev/7eca620feb10 |
|||
| msg158333 - (view) | Author: Roundup Robot (python-dev) (Python triager) | Date: 2012年04月15日 14:19 | |
New changeset bf3b77722c9f by Mark Dickinson in branch '2.7': Issue #13889: On MSVC builds, set FPU control word at runtime for all string <-> float conversions. Patch by Samuel Iseli and Stefan Krah. http://hg.python.org/cpython/rev/bf3b77722c9f |
|||
| History | |||
|---|---|---|---|
| Date | User | Action | Args |
| 2022年04月11日 14:57:26 | admin | set | github: 58097 |
| 2019年06月11日 11:58:07 | mark.dickinson | set | pull_requests: - pull_request13812 |
| 2019年06月10日 20:42:50 | vstinner | set | pull_requests: + pull_request13812 |
| 2012年04月15日 15:50:57 | mark.dickinson | set | status: open -> closed resolution: fixed |
| 2012年04月15日 14:19:19 | python-dev | set | messages: + msg158333 |
| 2012年04月15日 14:14:43 | python-dev | set | messages: + msg158330 |
| 2012年04月15日 12:03:26 | mark.dickinson | set | files:
+ issue13889_2.diff messages: + msg158322 |
| 2012年03月13日 19:04:17 | mark.dickinson | set | messages: + msg155646 |
| 2012年03月13日 14:48:13 | skrah | set | messages: + msg155619 |
| 2012年03月13日 14:35:05 | skrah | set | messages: + msg155617 |
| 2012年03月13日 14:02:52 | mark.dickinson | set | messages: + msg155610 |
| 2012年03月13日 11:47:31 | skrah | set | files:
+ issue13889.diff messages: + msg155590 |
| 2012年03月10日 16:41:27 | mark.dickinson | set | messages: + msg155322 |
| 2012年02月06日 23:25:02 | samuel.iseli | set | files:
+ 120206_set_53bit_precision.patch messages: + msg152799 |
| 2012年02月06日 08:35:21 | skrah | set | nosy:
+ skrah messages: + msg152728 |
| 2012年02月06日 06:40:53 | samuel.iseli | set | messages: + msg152724 |
| 2012年02月03日 16:54:10 | pitrou | set | components:
+ Windows stage: patch review |
| 2012年02月03日 16:50:20 | mark.dickinson | set | messages: + msg152541 |
| 2012年02月03日 15:36:23 | samuel.iseli | set | files:
+ 74747.patch messages: + msg152523 |
| 2012年02月03日 13:51:40 | samuel.iseli | set | files:
+ 74745.patch messages: + msg152509 |
| 2012年02月02日 14:40:05 | mark.dickinson | set | messages: + msg152458 |
| 2012年02月02日 00:33:23 | mark.dickinson | set | type: behavior -> enhancement messages: + msg152449 |
| 2012年02月02日 00:18:40 | jcea | set | assignee: mark.dickinson type: behavior |
| 2012年02月01日 20:33:36 | jcea | set | messages: + msg152439 |
| 2012年02月01日 20:31:27 | jcea | set | assignee: mark.dickinson -> (no value) type: behavior -> (no value) nosy: + jcea |
| 2012年01月29日 21:57:19 | samuel.iseli | set | messages: + msg152265 |
| 2012年01月27日 21:32:17 | mark.dickinson | set | priority: high -> normal |
| 2012年01月27日 21:29:47 | mark.dickinson | set | messages: + msg152122 |
| 2012年01月27日 21:20:17 | python-dev | set | nosy:
+ python-dev messages: + msg152120 |
| 2012年01月27日 20:29:23 | mark.dickinson | set | type: behavior versions: + Python 3.2, Python 3.3, - Python 3.1 |
| 2012年01月27日 20:28:59 | mark.dickinson | set | priority: normal -> high assignee: mark.dickinson |
| 2012年01月27日 20:22:38 | mark.dickinson | set | messages: + msg152116 |
| 2012年01月27日 19:06:33 | mark.dickinson | set | messages: + msg152111 |
| 2012年01月27日 15:13:04 | eric.smith | set | nosy:
+ mark.dickinson, eric.smith |
| 2012年01月27日 14:58:23 | samuel.iseli | create | |