Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 41 additions & 14 deletions src/csrc/casts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ extern "C" {
}
#include <cstring>
#include <cstdlib>
#include <new>
#include <type_traits>
#include "sleef.h"
#include "sleefquad.h"
Expand Down Expand Up @@ -240,10 +241,13 @@ unicode_to_quad_resolve_descriptors(PyObject *NPY_UNUSED(self), PyArray_DTypeMet
PyArray_Descr *given_descrs[2], PyArray_Descr *loop_descrs[2],
npy_intp *view_offset)
{
loop_descrs[0] = NULL;
loop_descrs[1] = NULL;

if (!PyArray_ISNBO(given_descrs[0]->byteorder)) {
loop_descrs[0] = PyArray_DescrNewByteorder(given_descrs[0], NPY_NATIVE);
if (loop_descrs[0] == nullptr) {
return (NPY_CASTING)-1;
return quad_resolve_descrs_fail(loop_descrs, 2);
}
}
else {
Expand All @@ -254,8 +258,7 @@ unicode_to_quad_resolve_descriptors(PyObject *NPY_UNUSED(self), PyArray_DTypeMet
if (given_descrs[1] == NULL) {
loop_descrs[1] = (PyArray_Descr *)new_quaddtype_instance(BACKEND_SLEEF);
if (loop_descrs[1] == nullptr) {
Py_DECREF(loop_descrs[0]);
return (NPY_CASTING)-1;
return quad_resolve_descrs_fail(loop_descrs, 2);
}
}
else {
Expand Down Expand Up @@ -350,6 +353,9 @@ quad_to_unicode_resolve_descriptors(PyObject *NPY_UNUSED(self), PyArray_DTypeMet
PyArray_Descr *given_descrs[2], PyArray_Descr *loop_descrs[2],
npy_intp *view_offset)
{
loop_descrs[0] = NULL;
loop_descrs[1] = NULL;

npy_intp required_size_chars = QUAD_STR_WIDTH;
npy_intp required_size_bytes = required_size_chars * 4; // UCS4 = 4 bytes per char

Expand All @@ -360,8 +366,7 @@ quad_to_unicode_resolve_descriptors(PyObject *NPY_UNUSED(self), PyArray_DTypeMet
// Create descriptor with required size
PyArray_Descr *unicode_descr = PyArray_DescrNewFromType(NPY_UNICODE);
if (unicode_descr == nullptr) {
Py_DECREF(loop_descrs[0]);
return (NPY_CASTING)-1;
return quad_resolve_descrs_fail(loop_descrs, 2);
}

unicode_descr->elsize = required_size_bytes;
Expand All @@ -373,8 +378,7 @@ quad_to_unicode_resolve_descriptors(PyObject *NPY_UNUSED(self), PyArray_DTypeMet
if (!PyArray_ISNBO(given_descrs[1]->byteorder)) {
loop_descrs[1] = PyArray_DescrNewByteorder(given_descrs[1], NPY_NATIVE);
if (loop_descrs[1] == nullptr) {
Py_DECREF(loop_descrs[0]);
return (NPY_CASTING)-1;
return quad_resolve_descrs_fail(loop_descrs, 2);
}
}
else {
Expand Down Expand Up @@ -545,15 +549,17 @@ bytes_to_quad_resolve_descriptors(PyObject *NPY_UNUSED(self), PyArray_DTypeMeta
PyArray_Descr *given_descrs[2], PyArray_Descr *loop_descrs[2],
npy_intp *view_offset)
{
loop_descrs[0] = NULL;
loop_descrs[1] = NULL;

// Bytes dtype doesn't have byte order concerns like Unicode
Py_INCREF(given_descrs[0]);
loop_descrs[0] = given_descrs[0];

if (given_descrs[1] == NULL) {
loop_descrs[1] = (PyArray_Descr *)new_quaddtype_instance(BACKEND_SLEEF);
if (loop_descrs[1] == nullptr) {
Py_DECREF(loop_descrs[0]);
return (NPY_CASTING)-1;
return quad_resolve_descrs_fail(loop_descrs, 2);
}
}
else {
Expand Down Expand Up @@ -650,12 +656,15 @@ quad_to_bytes_resolve_descriptors(PyObject *NPY_UNUSED(self), PyArray_DTypeMeta
PyArray_Descr *given_descrs[2], PyArray_Descr *loop_descrs[2],
npy_intp *view_offset)
{
loop_descrs[0] = NULL;
loop_descrs[1] = NULL;

npy_intp required_size_bytes = QUAD_STR_WIDTH;

if (given_descrs[1] == NULL) {
PyArray_Descr *new_descr = PyArray_DescrNewFromType(NPY_STRING);
if (new_descr == NULL) {
return (NPY_CASTING)-1;
return quad_resolve_descrs_fail(loop_descrs, 2);
}
new_descr->elsize = required_size_bytes;
loop_descrs[1] = new_descr;
Expand Down Expand Up @@ -731,10 +740,13 @@ stringdtype_to_quad_resolve_descriptors(PyObject *NPY_UNUSED(self), PyArray_DTyp
PyArray_Descr *given_descrs[2], PyArray_Descr *loop_descrs[2],
npy_intp *view_offset)
{
loop_descrs[0] = NULL;
loop_descrs[1] = NULL;

if (given_descrs[1] == NULL) {
loop_descrs[1] = (PyArray_Descr *)new_quaddtype_instance(BACKEND_SLEEF);
if (loop_descrs[1] == nullptr) {
return (NPY_CASTING)-1;
return quad_resolve_descrs_fail(loop_descrs, 2);
}
}
else {
Expand Down Expand Up @@ -813,12 +825,15 @@ quad_to_stringdtype_resolve_descriptors(PyObject *NPY_UNUSED(self), PyArray_DTyp
PyArray_Descr *given_descrs[2], PyArray_Descr *loop_descrs[2],
npy_intp *view_offset)
{
loop_descrs[0] = NULL;
loop_descrs[1] = NULL;

if (given_descrs[1] == NULL) {
// Default StringDType() already has coerce=True
loop_descrs[1] = (PyArray_Descr *)PyObject_CallNoArgs(
(PyObject *)&PyArray_StringDType);
if (loop_descrs[1] == NULL) {
return (NPY_CASTING)-1;
return quad_resolve_descrs_fail(loop_descrs, 2);
}
}
else {
Expand Down Expand Up @@ -1164,11 +1179,14 @@ numpy_to_quad_resolve_descriptors(PyObject *NPY_UNUSED(self), PyArray_DTypeMeta
PyArray_Descr *given_descrs[2], PyArray_Descr *loop_descrs[2],
npy_intp *view_offset)
{
loop_descrs[0] = NULL;
loop_descrs[1] = NULL;

// todo: here it is converting this to SLEEF, losing data and getting 0
if (given_descrs[1] == NULL) {
loop_descrs[1] = (PyArray_Descr *)new_quaddtype_instance(BACKEND_SLEEF);
if (loop_descrs[1] == nullptr) {
return (NPY_CASTING)-1;
return quad_resolve_descrs_fail(loop_descrs, 2);
}
}
else {
Expand All @@ -1177,6 +1195,9 @@ numpy_to_quad_resolve_descriptors(PyObject *NPY_UNUSED(self), PyArray_DTypeMeta
}

loop_descrs[0] = PyArray_GetDefaultDescr(dtypes[0]);
if (loop_descrs[0] == nullptr) {
return quad_resolve_descrs_fail(loop_descrs, 2);
}
// since QUAD precision is the highest precision, we can always cast to it
return static_cast<NPY_CASTING>(NPY_SAFE_CASTING | NPY_SAME_VALUE_CASTING_FLAG);
}
Expand Down Expand Up @@ -1485,10 +1506,16 @@ quad_to_numpy_resolve_descriptors(PyObject *NPY_UNUSED(self), PyArray_DTypeMeta
PyArray_Descr *given_descrs[2], PyArray_Descr *loop_descrs[2],
npy_intp *view_offset)
{
loop_descrs[0] = NULL;
loop_descrs[1] = NULL;

Py_INCREF(given_descrs[0]);
loop_descrs[0] = given_descrs[0];

loop_descrs[1] = PyArray_GetDefaultDescr(dtypes[1]);
if (loop_descrs[1] == nullptr) {
return quad_resolve_descrs_fail(loop_descrs, 2);
}
// For floating-point types: same_kind casting (precision loss but same kind)
if constexpr (is_float_type<T>::value) {
return static_cast<NPY_CASTING>(NPY_SAME_KIND_CASTING | NPY_SAME_VALUE_CASTING_FLAG);
Expand Down Expand Up @@ -1802,7 +1829,7 @@ init_casts(void)
try {
return init_casts_internal();
}
catch (int e) {
catch (const std::bad_alloc &) {
PyErr_NoMemory();
return nullptr;
}
Expand Down
5 changes: 3 additions & 2 deletions src/csrc/dtype.c
Original file line number Diff line number Diff line change
Expand Up @@ -628,8 +628,7 @@ QuadPrecDType_new(PyTypeObject *NPY_UNUSED(cls), PyObject *args, PyObject *kwds)
return NULL;
}

return (PyObject *)quadprec_discover_descriptor_from_pyobject(
&QuadPrecDType, (PyObject *)QuadPrecision_raw_new(backend));
return (PyObject *)new_quaddtype_instance(backend);
}

static PyObject *
Expand Down Expand Up @@ -707,10 +706,12 @@ init_quadprec_dtype(void)
((PyTypeObject *)&QuadPrecDType)->tp_base = &PyArrayDescr_Type;

if (PyType_Ready((PyTypeObject *)&QuadPrecDType) < 0) {
free_casts();
return -1;
}

if (PyArrayInitDTypeMeta_FromSpec(&QuadPrecDType, &QuadPrecDType_DTypeSpec) < 0) {
free_casts();
return -1;
}

Expand Down
4 changes: 3 additions & 1 deletion src/csrc/lock.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ PyThread_type_lock sleef_lock = NULL;
PyMutex sleef_lock = {0};
#endif

void init_sleef_locks(void)
int init_sleef_locks(void)
{
#if PY_VERSION_HEX < 0x30d00b3
sleef_lock = PyThread_allocate_lock();
if (!sleef_lock) {
PyErr_NoMemory();
return -1;
}
#endif
return 0;
}
7 changes: 4 additions & 3 deletions src/csrc/quaddtype_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,18 +102,19 @@ PyInit__quaddtype_main(void)
PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED);
#endif

init_sleef_locks();
if (init_sleef_locks() < 0)
goto error;

if (init_quadprecision_scalar() < 0)
goto error;

if (PyModule_AddObject(m, "QuadPrecision", (PyObject *)&QuadPrecision_Type) < 0)
if (PyModule_AddObjectRef(m, "QuadPrecision", (PyObject *)&QuadPrecision_Type) < 0)
goto error;

if (init_quadprec_dtype() < 0)
goto error;

if (PyModule_AddObject(m, "QuadPrecDType", (PyObject *)&QuadPrecDType) < 0)
if (PyModule_AddObjectRef(m, "QuadPrecDType", (PyObject *)&QuadPrecDType) < 0)
goto error;

if (init_quad_umath() < 0) {
Expand Down
12 changes: 11 additions & 1 deletion src/csrc/scalar.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,10 @@ QuadPrecision_from_object(PyObject *value, QuadBackendType backend)
}
else if (PyUnicode_Check(value)) {
const char *s = PyUnicode_AsUTF8(value);
if (s == NULL) {
Py_DECREF(self);
return NULL;
}
char *endptr = NULL;
int err = NumPyOS_ascii_strtoq(s, backend, &self->value, &endptr);
if (err < 0) {
Expand Down Expand Up @@ -248,6 +252,9 @@ QuadPrecision_from_object(PyObject *value, QuadBackendType backend)
QuadPrecisionObject *quad_obj = (QuadPrecisionObject *)value;
// create a new one with the same backend
QuadPrecisionObject *self = QuadPrecision_raw_new(quad_obj->backend);
if (self == NULL) {
return NULL;
}
if (quad_obj->backend == BACKEND_SLEEF) {
self->value.sleef_value = quad_obj->value.sleef_value;
}
Expand Down Expand Up @@ -620,7 +627,10 @@ QuadPrecision_as_integer_ratio(QuadPrecisionObject *self, PyObject *Py_UNUSED(ig
}

Py_DECREF(py_exp);
return PyTuple_Pack(2, numerator, denominator);
PyObject *ratio = PyTuple_Pack(2, numerator, denominator);
Py_DECREF(numerator);
Py_DECREF(denominator);
return ratio;
}

static int
Expand Down
1 change: 1 addition & 0 deletions src/csrc/scalar_ops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ quad_binary_func(PyObject *op1, PyObject *op2)
other_quad = (QuadPrecisionObject *)other;
if (other_quad->backend != backend) {
PyErr_SetString(PyExc_TypeError, "Cannot mix QuadPrecision backends");
Py_DECREF(other_quad);
Py_DECREF(other);
return NULL;
}
Expand Down
31 changes: 23 additions & 8 deletions src/csrc/umath/binary_ops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ quad_binary_op_resolve_descriptors(PyObject *self, PyArray_DTypeMeta *const dtyp
PyArray_Descr *const given_descrs[],
PyArray_Descr *loop_descrs[], npy_intp *NPY_UNUSED(view_offset))
{
for (int i = 0; i < 3; i++) {
loop_descrs[i] = NULL;
}

QuadPrecDTypeObject *descr_in1 = (QuadPrecDTypeObject *)given_descrs[0];
QuadPrecDTypeObject *descr_in2 = (QuadPrecDTypeObject *)given_descrs[1];
QuadBackendType target_backend;
Expand All @@ -45,7 +49,7 @@ quad_binary_op_resolve_descriptors(PyObject *self, PyArray_DTypeMeta *const dtyp
if (((QuadPrecDTypeObject *)given_descrs[i])->backend != target_backend) {
loop_descrs[i] = (PyArray_Descr *)new_quaddtype_instance(target_backend);
if (!loop_descrs[i]) {
return (NPY_CASTING)-1;
return quad_resolve_descrs_fail(loop_descrs, 3);
}
}
else {
Expand All @@ -58,15 +62,15 @@ quad_binary_op_resolve_descriptors(PyObject *self, PyArray_DTypeMeta *const dtyp
if (given_descrs[2] == NULL) {
loop_descrs[2] = (PyArray_Descr *)new_quaddtype_instance(target_backend);
if (!loop_descrs[2]) {
return (NPY_CASTING)-1;
return quad_resolve_descrs_fail(loop_descrs, 3);
}
}
else {
QuadPrecDTypeObject *descr_out = (QuadPrecDTypeObject *)given_descrs[2];
if (descr_out->backend != target_backend) {
loop_descrs[2] = (PyArray_Descr *)new_quaddtype_instance(target_backend);
if (!loop_descrs[2]) {
return (NPY_CASTING)-1;
return quad_resolve_descrs_fail(loop_descrs, 3);
}
}
else {
Expand Down Expand Up @@ -151,6 +155,10 @@ quad_binary_op_2out_resolve_descriptors(PyObject *self, PyArray_DTypeMeta *const
PyArray_Descr *const given_descrs[],
PyArray_Descr *loop_descrs[], npy_intp *NPY_UNUSED(view_offset))
{
for (int i = 0; i < 4; i++) {
loop_descrs[i] = NULL;
}

QuadPrecDTypeObject *descr_in1 = (QuadPrecDTypeObject *)given_descrs[0];
QuadPrecDTypeObject *descr_in2 = (QuadPrecDTypeObject *)given_descrs[1];
QuadBackendType target_backend;
Expand All @@ -170,7 +178,7 @@ quad_binary_op_2out_resolve_descriptors(PyObject *self, PyArray_DTypeMeta *const
if (((QuadPrecDTypeObject *)given_descrs[i])->backend != target_backend) {
loop_descrs[i] = (PyArray_Descr *)new_quaddtype_instance(target_backend);
if (!loop_descrs[i]) {
return (NPY_CASTING)-1;
return quad_resolve_descrs_fail(loop_descrs, 4);
}
}
else {
Expand All @@ -184,15 +192,15 @@ quad_binary_op_2out_resolve_descriptors(PyObject *self, PyArray_DTypeMeta *const
if (given_descrs[i] == NULL) {
loop_descrs[i] = (PyArray_Descr *)new_quaddtype_instance(target_backend);
if (!loop_descrs[i]) {
return (NPY_CASTING)-1;
return quad_resolve_descrs_fail(loop_descrs, 4);
}
}
else {
QuadPrecDTypeObject *descr_out = (QuadPrecDTypeObject *)given_descrs[i];
if (descr_out->backend != target_backend) {
loop_descrs[i] = (PyArray_Descr *)new_quaddtype_instance(target_backend);
if (!loop_descrs[i]) {
return (NPY_CASTING)-1;
return quad_resolve_descrs_fail(loop_descrs, 4);
}
}
else {
Expand Down Expand Up @@ -288,6 +296,10 @@ quad_ldexp_resolve_descriptors(PyObject *self, PyArray_DTypeMeta *const dtypes[]
PyArray_Descr *const given_descrs[],
PyArray_Descr *loop_descrs[], npy_intp *NPY_UNUSED(view_offset))
{
for (int i = 0; i < 3; i++) {
loop_descrs[i] = NULL;
}

QuadPrecDTypeObject *descr_in1 = (QuadPrecDTypeObject *)given_descrs[0];
QuadBackendType target_backend = descr_in1->backend;

Expand All @@ -297,19 +309,22 @@ quad_ldexp_resolve_descriptors(PyObject *self, PyArray_DTypeMeta *const dtypes[]

// Input 1: Use NPY_INTP to match the registered PyArray_IntpDType
loop_descrs[1] = PyArray_DescrFromType(NPY_INTP);
if (!loop_descrs[1]) {
return quad_resolve_descrs_fail(loop_descrs, 3);
}

// Output: QuadPrecDType with same backend as input
if (given_descrs[2] == NULL) {
loop_descrs[2] = (PyArray_Descr *)new_quaddtype_instance(target_backend);
if (!loop_descrs[2]) {
return (NPY_CASTING)-1;
return quad_resolve_descrs_fail(loop_descrs, 3);
}
} else {
QuadPrecDTypeObject *descr_out = (QuadPrecDTypeObject *)given_descrs[2];
if (descr_out->backend != target_backend) {
loop_descrs[2] = (PyArray_Descr *)new_quaddtype_instance(target_backend);
if (!loop_descrs[2]) {
return (NPY_CASTING)-1;
return quad_resolve_descrs_fail(loop_descrs, 3);
}
} else {
Py_INCREF(given_descrs[2]);
Expand Down
Loading
Loading