Conversation
|
Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool. If this change has little impact on Python users, wait for a maintainer to apply the |
|
If this PR is merged, it looks to me like #146402 can (and should) be reverted. |
skirpichev
left a comment
There was a problem hiding this comment.
No, I doubt that this is a right approach. We must handle error in same way for all libm functions.
Perhaps, m_atan2() (like m_log1p() we have currently) could be restored (see #122681) to workaround broken platform functions.
The mathmodule currently has 3 ways of handling 1-argument libm functions:
Maybe it's not so bad to have |
|
Perhaps, we could modify math_2() helper to check that errno!=EDOM, if inputs and output are finite. When domain error occurs - result should be nan. But I think that a little wrapper for libm's atan2 is better, if we are going to add some workaround for the given issue. |
skirpichev
left a comment
There was a problem hiding this comment.
Please revert unrelated changes.
|
@vstinner, can you look at this at your convenience? |
|
You also could use new helper function for copysign. On another hand, I would prefer just remove errno stuff from math_2(), per #156145. It should be possible for all two-argument functions: atan2, atan2pi, copysign, remainder and fmod (which could utilize same wrapper). |
My thinking is only to do what is necessary to fix the bug (the incorrect results when building with Intel or Solaris math libraries). Then, I would recommend applying this fix to Python 3.14 and 3.15. With that in mind, I don't want to make any enhancements that are not necessary to fix the reported bug.
Yes, 156145 can have a more ambitious goal. Can you trigger the buildbots to run this PR? I am not able to check myself that it works on Solaris. (I do think it will work based on what I read in the Solaris bug report.) |
Then we loose chance of using new helper function for copysign().
!buildbot Solaris |
|
!buildbot Solaris |
|
🤖 New build scheduled with the buildbot fleet by @skirpichev for commit 5b6d005 🤖 Results will be shown at: https://buildbot.python.org/all/#/grid?branch=refs%2Fpull%2F153148%2Fmerge The command will test the builders whose names match following regular expression: The builders matched are:
|
OK, I'll add that commit tomorrow. Since it will be a separate commit, it can easily be reverted (or skipped when squashing all the commits before the final merge). The same is true for the comments Victor requested--they're in their own separate commit. |
Python already returns the correct result, This PR changes cmath.phase() behavior on UNDERflow of imag/real (bug observed in #155527 (comment)). The C standard in 7.3.9.1 says:
Note that there's no possibility of overflow--the result is bounded. (The implementation may or may not actually perform a floating-point division of imag/real, but that's an implementation detail, and whether or not some intermediate calculation overflows must not affect what the user observes.) There is the possibility of underflow. The infinitely precise result of The result is too small to be represented in double precision, so it underflows to Python does not raise an exception on underflow, only on overflow. For example: I created the bug report because existing tests were failing when building Python with the Intel math library. I made this PR to ignore errno because I could see no reason for checking it, and I believed that not checking it was always correct. I did not stop to consider that the old code (checking errno) led to more Python bugs. After reading Serhiy's comment, I added tests to this PR and updated the NEWS. |
|
@serhiy-storchaka @skirpichev @picnixz: What is your opinion on changing |
|
FWIW, I don't think there is a change in behavior: atan2() shouldn't overflow. Underflows in Python are silent. |
|
I totally forgot about this PR. Let me read the issue and the history first (and now my speech resembles that of an AI...) |
Well, fixing a bug is a change in behavior. But I know what you mean. Let me walk through an example (using Python 3.13.5 built to use GNU libm). and note that, for both of them, imag/real underflows to zero: The math module's In the first case, the result underflows to DetailsThe wrapper In the second case, the infinitely precise result is very close to Pi, and libm rounds the result to three point something in order to return a double precision result. The result did not underflow to zero (nor did it overflow to infinity), so GNU's libm leaves errno unchanged. Python code had set Now, we get to the bug. Python calls GNU libm's In the second case, GNU's With this PR: |
|
@picnixz: So did you find time to review this change? |
|
No I'm sorry. I am quite busy in my daily job and haven't found time for that. I think I will have time on Sunday as I'm flying (or next thursday as I'm flying back). But the past weeks have been very busy (I can only do simple triaging or review). Now, after a quick glance:
This makes at least Did I catch the issue well? we wouldn't break code though, just fixing things. What I'm worried about however is implementations that really want to raise an EDOM for
In addition, Annex F says what to return when using (0,0). I would have imagined:
But in the second case, we can say it's garbage in-garbage out and it's likely an unsupported compiler (even less supported than icx!) So... I guess we canj ust ignore EDOM? Did I get it right? |
Done.
Yes. Although, technically, it's about the C math library, not the compiler. (It's possible to mix and match, e.g., use the Intel or Solaris math libraries with GCC.) Perhaps the title of my bug report for icx was too informal. Note that a math library might not strictly conform to Annex F for many reasons. Here, we only care about the values it returns for atan2(), which I would venture to guess would be correct even if the compiler and math library as a whole cannot claim to be compliant with the entirety of Annex F. Finally, I would like to suggest that, in my opinion, raising an exception where one should not happen is a serious bug. A Python programmer would not be expected to put My understanding is that bugfixes for Python 3.13 must be merged this month. |
|
Do not click the "Update branch" button without a good reason because it notifies everyone watching the PR that there are new changes, when there are not, and it uses up limited CI resources. |
|
We unfortunately get past 3.13 release and it is not security-only. I am ok with putting it in 3.16 and maybe 3.14/3.15 but I would be interested in having some NumPy's opinion just in case (cc @ngoldbaum). I think fixing the phase/atan2 inconsistency takes precedence over other behavioral change concerns. |
|
Thanks for the ping. NumPy already behaves the way CPython will behave after this PR. The only difference is that NumPy can optionally surface the underflow, and it reports it as an underflow, never as an overflow. |
|
Yeah so this matches what users will expect. I am fine with this PR then! thanks for doing it. |
| * EDOM, which we should ignore, or ERANGE if phi underflows, | ||
| * which is silent on Python. Overflow is not possible. */ |
There was a problem hiding this comment.
| * EDOM, which we should ignore, or ERANGE if phi underflows, | |
| * which is silent on Python. Overflow is not possible. */ | |
| EDOM, which we should ignore, or ERANGE if phi underflows, | |
| which is silent on Python. Overflow is not possible. */ |
Just to match commentaries style in the file.
| /* variant of math_2, to be used when the function being wrapped is known NOT | ||
| to need error checking (i.e., no overflow, invalid, or divide-by-zero). */ |
There was a problem hiding this comment.
I suggest expand this with atan2() example and remove other comments below.
| if (y == -1.0 && PyErr_Occurred()) { | ||
| return NULL; | ||
| } | ||
| r = (*func)(x, y); // Ignore errno on purpose. |
There was a problem hiding this comment.
| r = (*func)(x, y); // Ignore errno on purpose. | |
| r = (*func)(x, y); |
| /* gh-153144: Ignore atan2 and atan2pi errno on purpose since it can optionally | ||
| * be EDOM, which we should ignore, or ERANGE on underflow, which is | ||
| * silent on Python. Overflow is not possible. */ |
There was a problem hiding this comment.
| /* gh-153144: Ignore atan2 and atan2pi errno on purpose since it can optionally | |
| * be EDOM, which we should ignore, or ERANGE on underflow, which is | |
| * silent on Python. Overflow is not possible. */ |
| C89 but for which HUGE_VAL is not an infinity. | ||
|
|
||
| For most two-argument functions (copysign, fmod, hypot, atan2) | ||
| For most two-argument functions (fmod, hypot) |
There was a problem hiding this comment.
Actually, the only remaining math_2()-type function is remainder()...
The C23 standard states that for
atan2andatan2pi:Since Python should not raise ValueError in either of these cases (i.e., when both arguments are zero or when the computation underflows), this PR avoids checking
errnowhen calling these trig functions. As a bonus,math.atan2()is about 4% faster.math.atan2(0.0, 0.0)andcmath.phase(0.0)using icx #153144The statement about range error in the standard should, I think, be interpreted as: