-
-
Notifications
You must be signed in to change notification settings - Fork 30.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
_Py_c_pow() should adjust errno on error conditions #119771
Comments
It makes sense to me. You can add tests to |
I'm working on this. Things are worse than I expect: algorithm for small integer exponents produces a patchdiff --git a/Objects/complexobject.c b/Objects/complexobject.c
index 59c84f1359..951a161fb5 100644
--- a/Objects/complexobject.c
+++ b/Objects/complexobject.c
@@ -152,6 +152,8 @@ _Py_c_pow(Py_complex a, Py_complex b)
}
r.real = len*cos(phase);
r.imag = len*sin(phase);
+
+ _Py_ADJUST_ERANGE2(r.real, r.imag);
}
return r;
}
@@ -175,11 +177,16 @@ c_powu(Py_complex x, long n)
static Py_complex
c_powi(Py_complex x, long n)
{
- if (n > 0)
- return c_powu(x,n);
- else
- return _Py_c_quot(c_1, c_powu(x,-n));
+ Py_complex r;
+ if (n > 0) {
+ r = c_powu(x, n);
+ }
+ else {
+ r = _Py_c_quot(c_1, c_powu(x,-n));
+ }
+ _Py_ADJUST_ERANGE2(r.real, r.imag);
+ return r;
}
double
@@ -551,7 +558,6 @@ complex_pow(PyObject *v, PyObject *w, PyObject *z)
p = _Py_c_pow(a, b);
}
- _Py_ADJUST_ERANGE2(p.real, p.imag);
if (errno == EDOM) {
PyErr_SetString(PyExc_ZeroDivisionError,
"0.0 to a negative or complex power"); >>> pow(1e300+1j, 90.1)
Traceback (most recent call last):
File "<python-input-0>", line 1, in <module>
pow(1e300+1j, 90.1)
~~~^^^^^^^^^^^^^^^^
OverflowError: complex exponentiation
>>> pow(1e300+1j, 90)
(nan+nanj) |
Usually for numbers in Python, in case of doubt, correctness matters more than performance. |
Well, do you suggest to wipe out
|
You can catch the overflow using something like that: diff --git a/Objects/complexobject.c b/Objects/complexobject.c
index 59c84f1359..c90c6805b7 100644
--- a/Objects/complexobject.c
+++ b/Objects/complexobject.c
@@ -164,10 +164,19 @@ c_powu(Py_complex x, long n)
r = c_1;
p = x;
while (mask > 0 && n >= mask) {
- if (n & mask)
+ if (n & mask) {
r = _Py_c_prod(r,p);
+ if (!isfinite(p.real) || !isfinite(p.imag)) {
+ errno = ERANGE;
+ break;
+ }
+ }
mask <<= 1;
p = _Py_c_prod(p,p);
+ if (!isfinite(p.real) || !isfinite(p.imag)) {
+ errno = ERANGE;
+ break;
+ }
}
return r;
}
@@ -551,7 +560,9 @@ complex_pow(PyObject *v, PyObject *w, PyObject *z)
p = _Py_c_pow(a, b);
}
- _Py_ADJUST_ERANGE2(p.real, p.imag);
+ if (errno == 0) {
+ _Py_ADJUST_ERANGE2(p.real, p.imag);
+ }
if (errno == EDOM) {
PyErr_SetString(PyExc_ZeroDivisionError,
"0.0 to a negative or complex power"); |
Hmm, shouldn't errno set |
See #120010 |
Before we did this in complex_pow() and behaviour of the public C API function ``_Py_c_pow()`` was different from the pure-python pow().
PR is ready for review: #120256 |
Before we did this in complex_pow() and behavior of the public C API function _Py_c_pow() was different from the pure-python pow().
Implemented by the change 8a284e1. |
Before we did this in complex_pow() and behavior of the public C API function _Py_c_pow() was different from the pure-python pow().
Bug report
Bug description:
Right now we do this after invocation of the function or it's optimized alternative (for small integers). That has advantage as - IIUC - both algorithms may trigger error condition. On another hand, behaviour of the public C API function
_Py_c_pow()
(used in the CPython codebase only forcomplex_pow()
) will differ from the pure-python pow()...Other similar functions (
complex_div()
andcomplex_abs()
) leave settingerrno
to corresponding C-API function.My proposal: move
_Py_ADJUST_ERANGE2()
call to_Py_c_pow()
andc_powi()
. If that does make sense I'll provide a patch.CPython versions tested on:
CPython main branch
Operating systems tested on:
No response
Linked PRs
The text was updated successfully, but these errors were encountered: