-
-
Notifications
You must be signed in to change notification settings - Fork 13
ENH: Support arbitrary-length Python ints in QuadPrecision constructor #213
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -76,14 +76,39 @@ QuadPrecision_from_object(PyObject *value, QuadBackendType backend) | |
| Py_DECREF(self); | ||
| return NULL; | ||
| } | ||
| long long lval = PyLong_AsLongLong(py_int); | ||
| Py_DECREF(py_int); | ||
|
|
||
| if (backend == BACKEND_SLEEF) { | ||
| self->value.sleef_value = Sleef_cast_from_int64q1(lval); | ||
| int overflow = 0; | ||
| long long lval = PyLong_AsLongLongAndOverflow(py_int, &overflow); | ||
|
|
||
| if (overflow != 0) | ||
| { | ||
| // Integer is too large, convert to string and recursively call this function | ||
| PyObject *str_obj = PyObject_Str(py_int); | ||
| Py_DECREF(py_int); | ||
| if (str_obj == NULL) { | ||
| Py_DECREF(self); | ||
| return NULL; | ||
| } | ||
|
|
||
| // Recursively convert from string | ||
| QuadPrecisionObject *result = QuadPrecision_from_object(str_obj, backend); | ||
| Py_DECREF(str_obj); | ||
| Py_DECREF(self); // discard the default one | ||
| return result; | ||
| } | ||
| else if (lval == -1 && PyErr_Occurred()) { | ||
| Py_DECREF(py_int); | ||
| Py_DECREF(self); | ||
| return NULL; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you can test this error case by defining a class with an |
||
| } | ||
| else { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. both of the two if and else if blocks above return unconditionally, so you can delete this |
||
| self->value.longdouble_value = (long double)lval; | ||
| Py_DECREF(py_int); | ||
| if (backend == BACKEND_SLEEF) { | ||
| self->value.sleef_value = Sleef_cast_from_int64q1(lval); | ||
| } | ||
| else { | ||
| self->value.longdouble_value = (long double)lval; | ||
| } | ||
| } | ||
| return self; | ||
| } | ||
|
|
@@ -94,9 +119,16 @@ QuadPrecision_from_object(PyObject *value, QuadBackendType backend) | |
| Py_DECREF(self); | ||
| return NULL; | ||
| } | ||
|
|
||
| // Booleans are always 0 or 1, so no overflow check needed | ||
| long long lval = PyLong_AsLongLong(py_int); | ||
| Py_DECREF(py_int); | ||
|
|
||
| if (lval == -1 && PyErr_Occurred()) { | ||
| Py_DECREF(self); | ||
| return NULL; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good catch There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That said, I don't think it's feasible to hit this error case in practice because for whatever reason it's not possible to subclass Still, always check for errors in C 😄 |
||
| } | ||
|
|
||
| if (backend == BACKEND_SLEEF) { | ||
| self->value.sleef_value = Sleef_cast_from_int64q1(lval); | ||
| } | ||
|
|
@@ -145,7 +177,7 @@ QuadPrecision_from_object(PyObject *value, QuadBackendType backend) | |
| self->value.longdouble_value = (long double)dval; | ||
| } | ||
| } | ||
| else if (PyUnicode_CheckExact(value)) { | ||
| else if (PyUnicode_Check(value)) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. super minor nit: can you add a test passing a string subclass in to test this change? |
||
| const char *s = PyUnicode_AsUTF8(value); | ||
| char *endptr = NULL; | ||
| if (backend == BACKEND_SLEEF) { | ||
|
|
@@ -161,17 +193,35 @@ QuadPrecision_from_object(PyObject *value, QuadBackendType backend) | |
| } | ||
| } | ||
| else if (PyLong_Check(value)) { | ||
| long long val = PyLong_AsLongLong(value); | ||
| if (val == -1 && PyErr_Occurred()) { | ||
| PyErr_SetString(PyExc_OverflowError, "Overflow Error, value out of range"); | ||
| int overflow = 0; | ||
| long long val = PyLong_AsLongLongAndOverflow(value, &overflow); | ||
|
|
||
| if (overflow != 0) { | ||
| // Integer is too large, convert to string and recursively call this function | ||
| PyObject *str_obj = PyObject_Str(value); | ||
| if (str_obj == NULL) { | ||
| Py_DECREF(self); | ||
| return NULL; | ||
| } | ||
|
|
||
| // Recursively convert from string | ||
| QuadPrecisionObject *result = QuadPrecision_from_object(str_obj, backend); | ||
| Py_DECREF(str_obj); | ||
| Py_DECREF(self); // discard the default one | ||
| return result; | ||
| } | ||
| else if (val == -1 && PyErr_Occurred()) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This code is identical to code added above. Can you add a |
||
| Py_DECREF(self); | ||
| return NULL; | ||
| } | ||
| if (backend == BACKEND_SLEEF) { | ||
| self->value.sleef_value = Sleef_cast_from_int64q1(val); | ||
| } | ||
| else { | ||
| self->value.longdouble_value = (long double)val; | ||
| // No overflow, use the integer value directly | ||
| if (backend == BACKEND_SLEEF) { | ||
| self->value.sleef_value = Sleef_cast_from_int64q1(val); | ||
| } | ||
| else { | ||
| self->value.longdouble_value = (long double)val; | ||
| } | ||
| } | ||
| } | ||
| else if (Py_TYPE(value) == &QuadPrecision_Type) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can test this error case by subclassing e.g.
np.int64with a__str__implementation that raises