diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 55c3f2d..3bbdf2b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,16 +10,27 @@ on: jobs: test: runs-on: ubuntu-latest + strategy: + matrix: + numpy-version: ['2.3.2', 'nightly'] steps: - uses: actions/checkout@v3 - name: Setup Python uses: actions/setup-python@v3 with: - python-version: "3.10" + python-version: "3.11" - name: Install build and test dependencies run: | - python -m pip install -U pip build pytest unyt wheel meson ninja meson-python patchelf pandas numpy + python -m pip install -U pip build pytest unyt wheel meson ninja meson-python patchelf pandas + - name: Install numpy nightly + if: matrix.numpy-version == 'nightly' + run: | + pip install --pre --upgrade --timeout=60 -i https://pypi.anaconda.org/scientific-python-nightly-wheels/simple numpy + - name: Install numpy from PyPI + if: matrix.numpy-version != 'nightly' + run: | + pip install "numpy==${{ matrix.numpy-version }}" - name: Install asciidtype working-directory: asciidtype run: | @@ -63,8 +74,13 @@ jobs: - name: Install quaddtype working-directory: quaddtype run: | + if [ "${{ matrix.numpy-version }}" == "nightly" ]; then + # obscure errors when using command line 2_4 if numpy does not define it + python -c "import numpy as np; assert np.__version__ >= '2.4'" + extra_args="-Csetup-args=-Dcpp_args=-DNPY_TARGET_VERSION=NPY_2_4_API_VERSION --no-build-isolation" + fi export LDFLAGS="-fopenmp" - python -m pip install . -v + python -m pip install $extra_args . -v - name: Run quaddtype tests working-directory: quaddtype diff --git a/quaddtype/numpy_quaddtype/src/casts.cpp b/quaddtype/numpy_quaddtype/src/casts.cpp index bfd4296..8f9385d 100644 --- a/quaddtype/numpy_quaddtype/src/casts.cpp +++ b/quaddtype/numpy_quaddtype/src/casts.cpp @@ -1,7 +1,9 @@ #define PY_ARRAY_UNIQUE_SYMBOL QuadPrecType_ARRAY_API #define PY_UFUNC_UNIQUE_SYMBOL QuadPrecType_UFUNC_API #define NPY_NO_DEPRECATED_API NPY_2_0_API_VERSION -#define NPY_TARGET_VERSION NPY_2_0_API_VERSION +#ifndef NPY_TARGET_VERSION + #define NPY_TARGET_VERSION NPY_2_0_API_VERSION +#endif #define NO_IMPORT_ARRAY #define NO_IMPORT_UFUNC @@ -21,6 +23,11 @@ extern "C" { #include "casts.h" #include "dtype.h" +#if NPY_FEATURE_VERSION < NPY_2_0_API_VERSION + #warning "Is NPY_TARGET_VERSION set too high for this numpy installation?" + #error "NPY_FEATURE_VERSION too low, must be > NPY_2_0_API_VERSION" +#endif + #define NUM_CASTS 34 // 16 to_casts + 16 from_casts + 1 quad_to_quad + 1 void_to_quad static NPY_CASTING @@ -157,7 +164,7 @@ void_to_quad_resolve_descriptors(PyObject *NPY_UNUSED(self), PyArray_DTypeMeta * PyArray_Descr *given_descrs[2], PyArray_Descr *loop_descrs[2], npy_intp *view_offset) { - PyErr_SetString(PyExc_TypeError, + PyErr_SetString(PyExc_TypeError, "Void to QuadPrecision cast is not implemented"); return (NPY_CASTING)-1; } @@ -401,7 +408,7 @@ to_quad(long double x, QuadBackendType backend) } template -static NPY_CASTING +static int numpy_to_quad_resolve_descriptors(PyObject *NPY_UNUSED(self), PyArray_DTypeMeta *dtypes[2], PyArray_Descr *given_descrs[2], PyArray_Descr *loop_descrs[2], npy_intp *view_offset) @@ -419,7 +426,11 @@ numpy_to_quad_resolve_descriptors(PyObject *NPY_UNUSED(self), PyArray_DTypeMeta } loop_descrs[0] = PyArray_GetDefaultDescr(dtypes[0]); +#if defined(NPY_2_3_API_VERSION) && (NPY_TARGET_VERSION > NPY_2_3_API_VERSION) + return NPY_SAFE_CASTING | NPY_SAME_VALUE_CASTING_FLAG; +#else return NPY_SAFE_CASTING; +#endif } template @@ -667,6 +678,27 @@ from_quad(quad_value x, QuadBackendType backend) } template +static inline int +from_quad_checked(quad_value x, QuadBackendType backend, typename NpyType::TYPE *ret) { + *ret = from_quad::TYPE>(x, backend); + quad_value check = to_quad::TYPE>(*ret, backend); + if (backend == BACKEND_SLEEF) { + if (check.sleef_value == x.sleef_value) { + return 0; + } + } + else { + if (check.longdouble_value == x.longdouble_value) { + return 0; + } + } + NPY_ALLOW_C_API_DEF; + NPY_ALLOW_C_API; + PyErr_SetString(PyExc_ValueError, "could not cast 'same_value' to QuadType"); + NPY_DISABLE_C_API; + return -1; +} + static NPY_CASTING quad_to_numpy_resolve_descriptors(PyObject *NPY_UNUSED(self), PyArray_DTypeMeta *dtypes[2], PyArray_Descr *given_descrs[2], PyArray_Descr *loop_descrs[2], @@ -694,6 +726,28 @@ quad_to_numpy_strided_loop_unaligned(PyArrayMethod_Context *context, char *const size_t elem_size = (backend == BACKEND_SLEEF) ? sizeof(Sleef_quad) : sizeof(long double); +#if defined(NPY_2_3_API_VERSION) && (NPY_TARGET_VERSION > NPY_2_3_API_VERSION) + int same_value_casting = 0; + if (PyArray_GetNDArrayCFeatureVersion() > NPY_2_3_API_VERSION) { + same_value_casting = ((context->flags & NPY_SAME_VALUE_CONTEXT_FLAG) == NPY_SAME_VALUE_CONTEXT_FLAG); + } + if (same_value_casting) { + while (N--) { + quad_value in_val; + memcpy(&in_val, in_ptr, elem_size); + typename NpyType::TYPE out_val; + if (from_quad_checked(in_val, backend, &out_val) < 0) { + return -1; + } + memcpy(out_ptr, &out_val, sizeof(typename NpyType::TYPE)); + + in_ptr += strides[0]; + out_ptr += strides[1]; + } + } else { +#else + { +#endif while (N--) { quad_value in_val; memcpy(&in_val, in_ptr, elem_size); @@ -703,7 +757,7 @@ quad_to_numpy_strided_loop_unaligned(PyArrayMethod_Context *context, char *const in_ptr += strides[0]; out_ptr += strides[1]; - } + }} return 0; } @@ -720,6 +774,33 @@ quad_to_numpy_strided_loop_aligned(PyArrayMethod_Context *context, char *const d QuadPrecDTypeObject *quad_descr = (QuadPrecDTypeObject *)context->descriptors[0]; QuadBackendType backend = quad_descr->backend; +#if defined(NPY_2_3_API_VERSION) && (NPY_TARGET_VERSION > NPY_2_3_API_VERSION) + int same_value_casting = 0; + if (PyArray_GetNDArrayCFeatureVersion() > NPY_2_3_API_VERSION) { + same_value_casting = ((context->flags & NPY_SAME_VALUE_CONTEXT_FLAG) == NPY_SAME_VALUE_CONTEXT_FLAG); + } + if (same_value_casting) { + while (N--) { + quad_value in_val; + if (backend == BACKEND_SLEEF) { + in_val.sleef_value = *(Sleef_quad *)in_ptr; + } + else { + in_val.longdouble_value = *(long double *)in_ptr; + } + + typename NpyType::TYPE out_val; + if (from_quad_checked(in_val, backend, &out_val) < 0) { + return -1; + } + *(typename NpyType::TYPE *)(out_ptr) = out_val; + + in_ptr += strides[0]; + out_ptr += strides[1]; + }} else { +#else + { +#endif while (N--) { quad_value in_val; if (backend == BACKEND_SLEEF) { @@ -734,7 +815,7 @@ quad_to_numpy_strided_loop_aligned(PyArrayMethod_Context *context, char *const d in_ptr += strides[0]; out_ptr += strides[1]; - } + }} return 0; } @@ -762,7 +843,7 @@ add_cast_from(PyArray_DTypeMeta *to) PyArray_DTypeMeta **dtypes = new PyArray_DTypeMeta *[2]{&QuadPrecDType, to}; PyType_Slot *slots = new PyType_Slot[]{ - {NPY_METH_resolve_descriptors, (void *)&quad_to_numpy_resolve_descriptors}, + {NPY_METH_resolve_descriptors, (void *)&quad_to_numpy_resolve_descriptors}, {NPY_METH_strided_loop, (void *)&quad_to_numpy_strided_loop_aligned}, {NPY_METH_unaligned_strided_loop, (void *)&quad_to_numpy_strided_loop_unaligned}, {0, nullptr}}; @@ -771,7 +852,11 @@ add_cast_from(PyArray_DTypeMeta *to) .name = "cast_QuadPrec_to_NumPy", .nin = 1, .nout = 1, +#if defined(NPY_2_3_API_VERSION) && (NPY_TARGET_VERSION > NPY_2_3_API_VERSION) + .casting = NPY_SAME_VALUE_CASTING, +#else .casting = NPY_UNSAFE_CASTING, +#endif .flags = NPY_METH_SUPPORTS_UNALIGNED, .dtypes = dtypes, .slots = slots, @@ -904,4 +989,4 @@ free_casts(void) } } spec_count = 0; -} \ No newline at end of file +} diff --git a/quaddtype/numpy_quaddtype/src/dragon4.c b/quaddtype/numpy_quaddtype/src/dragon4.c index 5843141..b35e408 100644 --- a/quaddtype/numpy_quaddtype/src/dragon4.c +++ b/quaddtype/numpy_quaddtype/src/dragon4.c @@ -3,6 +3,16 @@ This code was extracted from NumPy and the original author was Allan Haldane(@ah Modifications are specific to support the SLEEF_QUAD */ +#define PY_ARRAY_UNIQUE_SYMBOL QuadPrecType_ARRAY_API +#define PY_UFUNC_UNIQUE_SYMBOL QuadPrecType_UFUNC_API +#define NPY_NO_DEPRECATED_API NPY_2_0_API_VERSION +#ifndef NPY_TARGET_VERSION + #define NPY_TARGET_VERSION NPY_2_0_API_VERSION +#endif +#define NO_IMPORT_ARRAY +#define NO_IMPORT_UFUNC + + #include #include #include @@ -14,17 +24,16 @@ Modifications are specific to support the SLEEF_QUAD #include "quaddtype_config.h" -#define PY_ARRAY_UNIQUE_SYMBOL QuadPrecType_ARRAY_API -#define PY_UFUNC_UNIQUE_SYMBOL QuadPrecType_UFUNC_API -#define NPY_NO_DEPRECATED_API NPY_2_0_API_VERSION -#define NPY_TARGET_VERSION NPY_2_0_API_VERSION -#define NO_IMPORT_ARRAY -#define NO_IMPORT_UFUNC - #include "dragon4.h" #include "dtype.h" #include "scalar.h" +#if NPY_FEATURE_VERSION < NPY_2_0_API_VERSION + #warning "Is NPY_TARGET_VERSION set too high for this numpy installation?" + #warning "NPY_FEATURE_VERSION is NPY_TOSTRING(NPY_FEATURE_VERSION)" + #error "NPY_FEATURE_VERSION too low, must be > NPY_2_0_API_VERSION" +#endif + #ifdef __cplusplus #define NPY_TLS thread_local @@ -2044,4 +2053,4 @@ Dragon4_Scientific(PyObject *obj, DigitMode digit_mode, int precision, int min_d } return NULL; -} \ No newline at end of file +} diff --git a/quaddtype/numpy_quaddtype/src/dtype.c b/quaddtype/numpy_quaddtype/src/dtype.c index 7d0fad3..f277021 100644 --- a/quaddtype/numpy_quaddtype/src/dtype.c +++ b/quaddtype/numpy_quaddtype/src/dtype.c @@ -5,7 +5,9 @@ #define PY_ARRAY_UNIQUE_SYMBOL QuadPrecType_ARRAY_API #define PY_UFUNC_UNIQUE_SYMBOL QuadPrecType_UFUNC_API #define NPY_NO_DEPRECATED_API NPY_2_0_API_VERSION -#define NPY_TARGET_VERSION NPY_2_0_API_VERSION +#ifndef NPY_TARGET_VERSION + #define NPY_TARGET_VERSION NPY_2_0_API_VERSION +#endif #define NO_IMPORT_ARRAY #define NO_IMPORT_UFUNC #include "numpy/arrayobject.h" @@ -17,6 +19,11 @@ #include "dtype.h" #include "dragon4.h" +#if NPY_FEATURE_VERSION < NPY_2_0_API_VERSION + #warning "Is NPY_TARGET_VERSION set too high for this numpy installation?" + #error "NPY_FEATURE_VERSION too low, must be > NPY_2_0_API_VERSION" +#endif + static inline int quad_load(void *x, char *data_ptr, QuadBackendType backend) { @@ -263,4 +270,4 @@ init_quadprec_dtype(void) free_casts(); return 0; -} \ No newline at end of file +} diff --git a/quaddtype/numpy_quaddtype/src/quadblas_interface.cpp b/quaddtype/numpy_quaddtype/src/quadblas_interface.cpp index b51851a..f9b15b4 100644 --- a/quaddtype/numpy_quaddtype/src/quadblas_interface.cpp +++ b/quaddtype/numpy_quaddtype/src/quadblas_interface.cpp @@ -3,7 +3,7 @@ #include #ifndef DISABLE_QUADBLAS -#include "../subprojects/qblas/include/quadblas/quadblas.hpp" +#include "quadblas/quadblas.hpp" #endif // DISABLE_QUADBLAS extern "C" { @@ -230,4 +230,4 @@ _quadblas_get_num_threads(void) #endif // DISABLE_QUADBLAS -} // extern "C" \ No newline at end of file +} // extern "C" diff --git a/quaddtype/numpy_quaddtype/src/quaddtype_main.c b/quaddtype/numpy_quaddtype/src/quaddtype_main.c index b8c2bc4..40eeba7 100644 --- a/quaddtype/numpy_quaddtype/src/quaddtype_main.c +++ b/quaddtype/numpy_quaddtype/src/quaddtype_main.c @@ -6,8 +6,9 @@ #define PY_ARRAY_UNIQUE_SYMBOL QuadPrecType_ARRAY_API #define PY_UFUNC_UNIQUE_SYMBOL QuadPrecType_UFUNC_API #define NPY_NO_DEPRECATED_API NPY_2_0_API_VERSION -#define NPY_TARGET_VERSION NPY_2_0_API_VERSION - +#ifndef NPY_TARGET_VERSION + #define NPY_TARGET_VERSION NPY_2_0_API_VERSION +#endif #include "numpy/arrayobject.h" #include "numpy/dtype_api.h" #include "numpy/ufuncobject.h" @@ -19,6 +20,11 @@ #include "quadblas_interface.h" #include "float.h" +#if NPY_FEATURE_VERSION < NPY_2_0_API_VERSION + #warning "Is NPY_TARGET_VERSION set too high for this numpy installation?" + #error "NPY_FEATURE_VERSION too low, must be > NPY_2_0_API_VERSION" +#endif + static PyObject * py_is_longdouble_128(PyObject *self, PyObject *args) { @@ -177,4 +183,4 @@ PyInit__quaddtype_main(void) error: Py_XDECREF(m); return NULL; -} \ No newline at end of file +} diff --git a/quaddtype/numpy_quaddtype/src/scalar_ops.cpp b/quaddtype/numpy_quaddtype/src/scalar_ops.cpp index ef0fa84..d24aa01 100644 --- a/quaddtype/numpy_quaddtype/src/scalar_ops.cpp +++ b/quaddtype/numpy_quaddtype/src/scalar_ops.cpp @@ -1,6 +1,8 @@ #define PY_ARRAY_UNIQUE_SYMBOL QuadPrecType_ARRAY_API #define NPY_NO_DEPRECATED_API NPY_2_0_API_VERSION -#define NPY_TARGET_VERSION NPY_2_0_API_VERSION +#ifndef NPY_TARGET_VERSION + #define NPY_TARGET_VERSION NPY_2_0_API_VERSION +#endif #define NO_IMPORT_ARRAY extern "C" { @@ -18,6 +20,11 @@ extern "C" { #include "scalar_ops.h" #include "quad_common.h" +#if NPY_FEATURE_VERSION < NPY_2_0_API_VERSION + #warning "Is NPY_TARGET_VERSION set too high for this numpy installation?" + #error "NPY_FEATURE_VERSION too low, must be > NPY_2_0_API_VERSION" +#endif + template static PyObject * quad_unary_func(QuadPrecisionObject *self) @@ -240,4 +247,4 @@ PyNumberMethods quad_as_scalar = { .nb_int = (unaryfunc)QuadPrecision_int, .nb_float = (unaryfunc)QuadPrecision_float, .nb_true_divide = (binaryfunc)quad_binary_func, -}; \ No newline at end of file +}; diff --git a/quaddtype/numpy_quaddtype/src/umath/binary_ops.cpp b/quaddtype/numpy_quaddtype/src/umath/binary_ops.cpp index 8adfe4d..3055b47 100644 --- a/quaddtype/numpy_quaddtype/src/umath/binary_ops.cpp +++ b/quaddtype/numpy_quaddtype/src/umath/binary_ops.cpp @@ -1,7 +1,9 @@ #define PY_ARRAY_UNIQUE_SYMBOL QuadPrecType_ARRAY_API #define PY_UFUNC_UNIQUE_SYMBOL QuadPrecType_UFUNC_API #define NPY_NO_DEPRECATED_API NPY_2_0_API_VERSION -#define NPY_TARGET_VERSION NPY_2_0_API_VERSION +#ifndef NPY_TARGET_VERSION + #define NPY_TARGET_VERSION NPY_2_0_API_VERSION +#endif #define NO_IMPORT_ARRAY #define NO_IMPORT_UFUNC @@ -21,6 +23,11 @@ #include "promoters.hpp" #include "binary_ops.h" +#if NPY_FEATURE_VERSION < NPY_2_0_API_VERSION + #warning "Is NPY_TARGET_VERSION set too high for this numpy installation?" + #error "NPY_FEATURE_VERSION too low, must be > NPY_2_0_API_VERSION" +#endif + static NPY_CASTING quad_binary_op_resolve_descriptors(PyObject *self, PyArray_DTypeMeta *const dtypes[], PyArray_Descr *const given_descrs[], @@ -241,4 +248,4 @@ init_quad_binary_ops(PyObject *numpy) return -1; } return 0; -} \ No newline at end of file +} diff --git a/quaddtype/numpy_quaddtype/src/umath/comparison_ops.cpp b/quaddtype/numpy_quaddtype/src/umath/comparison_ops.cpp index e4b9579..4cfa5bb 100644 --- a/quaddtype/numpy_quaddtype/src/umath/comparison_ops.cpp +++ b/quaddtype/numpy_quaddtype/src/umath/comparison_ops.cpp @@ -1,7 +1,9 @@ #define PY_ARRAY_UNIQUE_SYMBOL QuadPrecType_ARRAY_API #define PY_UFUNC_UNIQUE_SYMBOL QuadPrecType_UFUNC_API #define NPY_NO_DEPRECATED_API NPY_2_0_API_VERSION -#define NPY_TARGET_VERSION NPY_2_0_API_VERSION +#ifndef NPY_TARGET_VERSION + #define NPY_TARGET_VERSION NPY_2_0_API_VERSION +#endif #define NO_IMPORT_ARRAY #define NO_IMPORT_UFUNC @@ -23,6 +25,10 @@ #include "binary_ops.h" #include "comparison_ops.h" +#if NPY_FEATURE_VERSION < NPY_2_0_API_VERSION + #warning "Is NPY_TARGET_VERSION set too high for this numpy installation?" + #error "NPY_FEATURE_VERSION too low, must be > NPY_2_0_API_VERSION" +#endif static NPY_CASTING quad_comparison_op_resolve_descriptors(PyObject *self, PyArray_DTypeMeta *const dtypes[], @@ -241,4 +247,4 @@ init_quad_comps(PyObject *numpy) } return 0; -} \ No newline at end of file +} diff --git a/quaddtype/numpy_quaddtype/src/umath/matmul.cpp b/quaddtype/numpy_quaddtype/src/umath/matmul.cpp index 6ac0d5c..f10adab 100644 --- a/quaddtype/numpy_quaddtype/src/umath/matmul.cpp +++ b/quaddtype/numpy_quaddtype/src/umath/matmul.cpp @@ -1,7 +1,9 @@ #define PY_ARRAY_UNIQUE_SYMBOL QuadPrecType_ARRAY_API #define PY_UFUNC_UNIQUE_SYMBOL QuadPrecType_UFUNC_API #define NPY_NO_DEPRECATED_API NPY_2_0_API_VERSION -#define NPY_TARGET_VERSION NPY_2_0_API_VERSION +#ifndef NPY_TARGET_VERSION + #define NPY_TARGET_VERSION NPY_2_0_API_VERSION +#endif #define NO_IMPORT_ARRAY #define NO_IMPORT_UFUNC @@ -24,6 +26,11 @@ extern "C" { #include "promoters.hpp" #include "../quadblas_interface.h" +#if NPY_FEATURE_VERSION < NPY_2_0_API_VERSION + #warning "Is NPY_TARGET_VERSION set too high for this numpy installation?" + #error "NPY_FEATURE_VERSION too low, must be > NPY_2_0_API_VERSION" +#endif + static NPY_CASTING quad_matmul_resolve_descriptors(PyObject *self, PyArray_DTypeMeta *const dtypes[], PyArray_Descr *const given_descrs[], PyArray_Descr *loop_descrs[], @@ -452,4 +459,4 @@ init_matmul_ops(PyObject *numpy) Py_DECREF(ufunc); return 0; -} \ No newline at end of file +} diff --git a/quaddtype/numpy_quaddtype/src/umath/umath.cpp b/quaddtype/numpy_quaddtype/src/umath/umath.cpp index 0c72d32..462d4fe 100644 --- a/quaddtype/numpy_quaddtype/src/umath/umath.cpp +++ b/quaddtype/numpy_quaddtype/src/umath/umath.cpp @@ -1,7 +1,9 @@ #define PY_ARRAY_UNIQUE_SYMBOL QuadPrecType_ARRAY_API #define PY_UFUNC_UNIQUE_SYMBOL QuadPrecType_UFUNC_API #define NPY_NO_DEPRECATED_API NPY_2_0_API_VERSION -#define NPY_TARGET_VERSION NPY_2_0_API_VERSION +#ifndef NPY_TARGET_VERSION + #define NPY_TARGET_VERSION NPY_2_0_API_VERSION +#endif #define NO_IMPORT_ARRAY #define NO_IMPORT_UFUNC @@ -25,6 +27,11 @@ extern "C" { #include "comparison_ops.h" #include "matmul.h" +#if NPY_FEATURE_VERSION < NPY_2_0_API_VERSION + #warning "Is NPY_TARGET_VERSION set too high for this numpy installation?" + #error "NPY_FEATURE_VERSION too low, must be > NPY_2_0_API_VERSION" +#endif + // helper debugging function static const char * get_dtype_name(PyArray_DTypeMeta *dtype) @@ -119,4 +126,4 @@ init_quad_umath(void) err: Py_DECREF(numpy); return -1; -} \ No newline at end of file +} diff --git a/quaddtype/numpy_quaddtype/src/umath/unary_ops.cpp b/quaddtype/numpy_quaddtype/src/umath/unary_ops.cpp index d60591e..e866d23 100644 --- a/quaddtype/numpy_quaddtype/src/umath/unary_ops.cpp +++ b/quaddtype/numpy_quaddtype/src/umath/unary_ops.cpp @@ -1,7 +1,9 @@ #define PY_ARRAY_UNIQUE_SYMBOL QuadPrecType_ARRAY_API #define PY_UFUNC_UNIQUE_SYMBOL QuadPrecType_UFUNC_API #define NPY_NO_DEPRECATED_API NPY_2_0_API_VERSION -#define NPY_TARGET_VERSION NPY_2_0_API_VERSION +#ifndef NPY_TARGET_VERSION + #define NPY_TARGET_VERSION NPY_2_0_API_VERSION +#endif #define NO_IMPORT_ARRAY #define NO_IMPORT_UFUNC @@ -20,6 +22,11 @@ extern "C" { #include "../dtype.h" #include "../ops.hpp" +#if NPY_FEATURE_VERSION < NPY_2_0_API_VERSION + #warning "Is NPY_TARGET_VERSION set too high for this numpy installation?" + #error "NPY_FEATURE_VERSION too low, must be > NPY_2_0_API_VERSION" +#endif + static NPY_CASTING quad_unary_op_resolve_descriptors(PyObject *self, PyArray_DTypeMeta *const dtypes[], PyArray_Descr *const given_descrs[], PyArray_Descr *loop_descrs[], @@ -235,4 +242,4 @@ init_quad_unary_ops(PyObject *numpy) return -1; } return 0; -} \ No newline at end of file +} diff --git a/quaddtype/numpy_quaddtype/src/umath/unary_props.cpp b/quaddtype/numpy_quaddtype/src/umath/unary_props.cpp index 7e399ad..f3df47b 100644 --- a/quaddtype/numpy_quaddtype/src/umath/unary_props.cpp +++ b/quaddtype/numpy_quaddtype/src/umath/unary_props.cpp @@ -1,7 +1,9 @@ #define PY_ARRAY_UNIQUE_SYMBOL QuadPrecType_ARRAY_API #define PY_UFUNC_UNIQUE_SYMBOL QuadPrecType_UFUNC_API #define NPY_NO_DEPRECATED_API NPY_2_0_API_VERSION -#define NPY_TARGET_VERSION NPY_2_0_API_VERSION +#ifndef NPY_TARGET_VERSION + #define NPY_TARGET_VERSION NPY_2_0_API_VERSION +#endif #define NO_IMPORT_ARRAY #define NO_IMPORT_UFUNC @@ -20,6 +22,11 @@ extern "C" { #include "../dtype.h" #include "../ops.hpp" +#if NPY_FEATURE_VERSION < NPY_2_0_API_VERSION + #warning "Is NPY_TARGET_VERSION set too high for this numpy installation?" + #error "NPY_FEATURE_VERSION too low, must be > NPY_2_0_API_VERSION" +#endif + static NPY_CASTING quad_unary_prop_resolve_descriptors(PyObject *self, PyArray_DTypeMeta *const dtypes[], PyArray_Descr *const given_descrs[], PyArray_Descr *loop_descrs[], diff --git a/quaddtype/tests/test_quaddtype.py b/quaddtype/tests/test_quaddtype.py index a761df1..c9c8df0 100644 --- a/quaddtype/tests/test_quaddtype.py +++ b/quaddtype/tests/test_quaddtype.py @@ -6,6 +6,7 @@ import numpy_quaddtype from numpy_quaddtype import QuadPrecDType, QuadPrecision +np_major, np_minor = map(int, np.__version__.split('.')[:2]) def test_create_scalar_simple(): assert isinstance(QuadPrecision("12.0"), QuadPrecision) @@ -76,6 +77,17 @@ def test_unsupported_astype(dtype): np.array(QuadPrecision(1)).astype(dtype, casting="unsafe") +@pytest.mark.skipif(np_major < 2 or (np_major == 2 and np_minor < 4), + reason="numpy version>2.4 required for test") +def test_same_value_cast(): + a = np.arange(30, dtype=np.float32) + # upcasting can never fail + b = a.astype(QuadPrecision, casting='same_value') + c = b.astype(np.float32, casting='same_value') + assert np.all(c == a) + with pytest.raises(ValueError, match="could not cast 'same_value'"): + (b + 1e22).astype(np.float32, casting='same_value') + def test_basic_equality(): assert QuadPrecision("12") == QuadPrecision( "12.0") == QuadPrecision("12.00")