From 50e7c6aaf202b2670d997cbb4450b6d3b22efc54 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 17 Sep 2025 11:27:37 +0000 Subject: [PATCH 1/4] finfo support based on numpy/#29763 --- quaddtype/numpy_quaddtype/src/dtype.c | 23 +++++++++++++++++++++++ quaddtype/numpy_quaddtype/src/scalar.c | 3 ++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/quaddtype/numpy_quaddtype/src/dtype.c b/quaddtype/numpy_quaddtype/src/dtype.c index 7d0fad37..9e1d2e7f 100644 --- a/quaddtype/numpy_quaddtype/src/dtype.c +++ b/quaddtype/numpy_quaddtype/src/dtype.c @@ -176,6 +176,28 @@ quadprec_default_descr(PyArray_DTypeMeta *cls) return (PyArray_Descr *)temp; } +static PyObject * +quad_finfo(PyArray_Descr *descr) +{ + + PyObject *finfo_dict = PyDict_New(); + if (!finfo_dict) return NULL; + + PyDict_SetItemString(finfo_dict, "precision", PyLong_FromLong(34)); + PyDict_SetItemString(finfo_dict, "bits", PyLong_FromLong(128)); + + PyDict_SetItemString(finfo_dict, "eps", PyLong_FromLong(34)); + + PyDict_SetItemString(finfo_dict, "max", PyLong_FromLong(34)); + + PyDict_SetItemString(finfo_dict, "tiny", PyLong_FromLong(34)); + + PyDict_SetItemString(finfo_dict, "epsneg", PyLong_FromLong(34)); + PyDict_SetItemString(finfo_dict, "resolution", PyLong_FromLong(34)); + + return finfo_dict; +} + static PyType_Slot QuadPrecDType_Slots[] = { {NPY_DT_ensure_canonical, &ensure_canonical}, {NPY_DT_common_instance, &common_instance}, @@ -185,6 +207,7 @@ static PyType_Slot QuadPrecDType_Slots[] = { {NPY_DT_getitem, &quadprec_getitem}, {NPY_DT_default_descr, &quadprec_default_descr}, {NPY_DT_PyArray_ArrFuncs_dotfunc, NULL}, + {NPY_DT_get_finfo, &quad_finfo}, {0, NULL}}; static PyObject * diff --git a/quaddtype/numpy_quaddtype/src/scalar.c b/quaddtype/numpy_quaddtype/src/scalar.c index 6d82d198..38f48b87 100644 --- a/quaddtype/numpy_quaddtype/src/scalar.c +++ b/quaddtype/numpy_quaddtype/src/scalar.c @@ -239,7 +239,7 @@ QuadPrecision_dealloc(QuadPrecisionObject *self) } PyTypeObject QuadPrecision_Type = { - PyVarObject_HEAD_INIT(NULL, 0).tp_name = "numpy_quaddtype.QuadPrecision", + PyVarObject_HEAD_INIT(NULL, 0).tp_name = "numpy_quaddtype.QuadPrecDType", .tp_basicsize = sizeof(QuadPrecisionObject), .tp_itemsize = 0, .tp_new = QuadPrecision_new, @@ -253,5 +253,6 @@ PyTypeObject QuadPrecision_Type = { int init_quadprecision_scalar(void) { + QuadPrecision_Type.tp_base = &PyFloatingArrType_Type; return PyType_Ready(&QuadPrecision_Type); } \ No newline at end of file From 90e77dec91167c0ff8f24b9bddce09f574aa91ab Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 17 Sep 2025 18:11:38 +0000 Subject: [PATCH 2/4] update finfo generic --- quaddtype/numpy_quaddtype/src/dtype.c | 46 ++++++++++++++++----------- quaddtype/reinstall.sh | 6 ++-- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/quaddtype/numpy_quaddtype/src/dtype.c b/quaddtype/numpy_quaddtype/src/dtype.c index 9e1d2e7f..1e8e7e6a 100644 --- a/quaddtype/numpy_quaddtype/src/dtype.c +++ b/quaddtype/numpy_quaddtype/src/dtype.c @@ -177,25 +177,35 @@ quadprec_default_descr(PyArray_DTypeMeta *cls) } static PyObject * -quad_finfo(PyArray_Descr *descr) +quad_finfo(PyArray_Descr *descr, NPY_DTYPE_INFO_TYPE info_type) { - PyObject *finfo_dict = PyDict_New(); - if (!finfo_dict) return NULL; - - PyDict_SetItemString(finfo_dict, "precision", PyLong_FromLong(34)); - PyDict_SetItemString(finfo_dict, "bits", PyLong_FromLong(128)); - - PyDict_SetItemString(finfo_dict, "eps", PyLong_FromLong(34)); - - PyDict_SetItemString(finfo_dict, "max", PyLong_FromLong(34)); - - PyDict_SetItemString(finfo_dict, "tiny", PyLong_FromLong(34)); - - PyDict_SetItemString(finfo_dict, "epsneg", PyLong_FromLong(34)); - PyDict_SetItemString(finfo_dict, "resolution", PyLong_FromLong(34)); - - return finfo_dict; + // Handle the different info types + switch (info_type) { + case NPY_DTYPE_INFO_FLOAT: + { + PyObject *finfo_dict = PyDict_New(); + if (!finfo_dict) return NULL; + + PyDict_SetItemString(finfo_dict, "precision", PyLong_FromLong(34)); + PyDict_SetItemString(finfo_dict, "bits", PyLong_FromLong(128)); + // more fields + return finfo_dict; + } + case NPY_DTYPE_INFO_INTEGER: + // Not implemented yet, could add iinfo support later + PyErr_SetString(PyExc_NotImplementedError, + "Integer info not implemented for this dtype"); + return NULL; + case NPY_DTYPE_INFO_GENERIC: + // Not implemented yet, could add generic info later + PyErr_SetString(PyExc_NotImplementedError, + "Generic info not implemented for this dtype"); + return NULL; + default: + PyErr_SetString(PyExc_ValueError, "Unknown dtype info type"); + return NULL; + } } static PyType_Slot QuadPrecDType_Slots[] = { @@ -207,7 +217,7 @@ static PyType_Slot QuadPrecDType_Slots[] = { {NPY_DT_getitem, &quadprec_getitem}, {NPY_DT_default_descr, &quadprec_default_descr}, {NPY_DT_PyArray_ArrFuncs_dotfunc, NULL}, - {NPY_DT_get_finfo, &quad_finfo}, + {NPY_DT_get_dtype_info, &quad_finfo}, {0, NULL}}; static PyObject * diff --git a/quaddtype/reinstall.sh b/quaddtype/reinstall.sh index 5a028f1c..a5b00ac4 100755 --- a/quaddtype/reinstall.sh +++ b/quaddtype/reinstall.sh @@ -8,7 +8,7 @@ if [ -d "build/" ]; then rm -rf subprojects/sleef fi -export CFLAGS="-g -O0" -export CXXFLAGS="-g -O0" +# export CFLAGS="-g -O0" +# export CXXFLAGS="-g -O0" python -m pip uninstall -y numpy_quaddtype -python -m pip install . -v \ No newline at end of file +python -m pip install . --no-build-isolation -v 2>&1 | tee build_log.txt \ No newline at end of file From 6ed27b96a4c8ad50d0eb38fb539a70fb180d2904 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Fri, 19 Sep 2025 22:47:58 +0000 Subject: [PATCH 3/4] refactoring finfo support --- quaddtype/numpy_quaddtype/__init__.py | 42 +++++++++++++++++- quaddtype/numpy_quaddtype/src/dtype.c | 62 +++++++++++++-------------- 2 files changed, 70 insertions(+), 34 deletions(-) diff --git a/quaddtype/numpy_quaddtype/__init__.py b/quaddtype/numpy_quaddtype/__init__.py index abdc20e0..b1a38c38 100644 --- a/quaddtype/numpy_quaddtype/__init__.py +++ b/quaddtype/numpy_quaddtype/__init__.py @@ -8,6 +8,8 @@ get_quadblas_version ) +from dataclasses import dataclass + __all__ = [ 'QuadPrecision', 'QuadPrecDType', 'SleefQuadPrecision', 'LongDoubleQuadPrecision', 'SleefQuadPrecDType', 'LongDoubleQuadPrecDType', 'is_longdouble_128', @@ -15,7 +17,9 @@ 'pi', 'e', 'log2e', 'log10e', 'ln2', 'ln10', 'max_value', 'epsilon', 'smallest_normal', 'smallest_subnormal', 'bits', 'precision', 'resolution', # QuadBLAS related functions - 'set_num_threads', 'get_num_threads', 'get_quadblas_version' + 'set_num_threads', 'get_num_threads', 'get_quadblas_version', + # finfo class + 'QuadPrecFinfo' ] def SleefQuadPrecision(value): @@ -43,3 +47,39 @@ def LongDoubleQuadPrecDType(): bits = get_sleef_constant("bits") precision = get_sleef_constant("precision") resolution = get_sleef_constant("resolution") + +@dataclass +class QuadPrecFinfo: + """Floating-point information for quadruple precision dtype. + + This class provides information about the floating-point representation + used by the QuadPrecDType, similar to numpy.finfo but customized for + quad precision arithmetic. + """ + bits: int = int(bits) + eps: float = float(epsilon) + epsneg: float = float(epsilon) + iexp: int = int(precision) + machar: object = None + machep: float = float(epsilon) + max: float = float(max_value) + maxexp: float = float(max_value) + min: float = float(smallest_normal) + minexp: float = float(smallest_normal) + negep: float = float(epsilon) + nexp: int = int(bits) - int(precision) - 1 + nmant: int = int(precision) + precision: int = int(precision) + resolution: float = float(resolution) + tiny: float = float(smallest_normal) + smallest_normal: float = float(smallest_normal) + smallest_subnormal: float = float(smallest_subnormal) + + def get(self, attr): + return getattr(self, attr, None) + + def __str__(self): + return f"QuadPrecFinfo(precision={self.precision}, resolution={self.resolution})" + + def __repr__(self): + return f"QuadPrecFinfo(max={self.max}, min={self.min}, eps={self.eps}, bits={self.bits})" diff --git a/quaddtype/numpy_quaddtype/src/dtype.c b/quaddtype/numpy_quaddtype/src/dtype.c index 1e8e7e6a..950f6bf8 100644 --- a/quaddtype/numpy_quaddtype/src/dtype.c +++ b/quaddtype/numpy_quaddtype/src/dtype.c @@ -176,38 +176,6 @@ quadprec_default_descr(PyArray_DTypeMeta *cls) return (PyArray_Descr *)temp; } -static PyObject * -quad_finfo(PyArray_Descr *descr, NPY_DTYPE_INFO_TYPE info_type) -{ - - // Handle the different info types - switch (info_type) { - case NPY_DTYPE_INFO_FLOAT: - { - PyObject *finfo_dict = PyDict_New(); - if (!finfo_dict) return NULL; - - PyDict_SetItemString(finfo_dict, "precision", PyLong_FromLong(34)); - PyDict_SetItemString(finfo_dict, "bits", PyLong_FromLong(128)); - // more fields - return finfo_dict; - } - case NPY_DTYPE_INFO_INTEGER: - // Not implemented yet, could add iinfo support later - PyErr_SetString(PyExc_NotImplementedError, - "Integer info not implemented for this dtype"); - return NULL; - case NPY_DTYPE_INFO_GENERIC: - // Not implemented yet, could add generic info later - PyErr_SetString(PyExc_NotImplementedError, - "Generic info not implemented for this dtype"); - return NULL; - default: - PyErr_SetString(PyExc_ValueError, "Unknown dtype info type"); - return NULL; - } -} - static PyType_Slot QuadPrecDType_Slots[] = { {NPY_DT_ensure_canonical, &ensure_canonical}, {NPY_DT_common_instance, &common_instance}, @@ -217,7 +185,6 @@ static PyType_Slot QuadPrecDType_Slots[] = { {NPY_DT_getitem, &quadprec_getitem}, {NPY_DT_default_descr, &quadprec_default_descr}, {NPY_DT_PyArray_ArrFuncs_dotfunc, NULL}, - {NPY_DT_get_dtype_info, &quad_finfo}, {0, NULL}}; static PyObject * @@ -257,6 +224,34 @@ QuadPrecDType_str(QuadPrecDTypeObject *self) return PyUnicode_FromFormat("QuadPrecDType(backend='%s')", backend_str); } +static PyObject * +QuadPrecDType_finfo(QuadPrecDTypeObject *self, PyObject *args) +{ + PyObject *numpy_quaddtype_module = PyImport_ImportModule("numpy_quaddtype"); + if (numpy_quaddtype_module == NULL) { + return NULL; + } + + PyObject *finfo_class = PyObject_GetAttrString(numpy_quaddtype_module, "QuadPrecFinfo"); + Py_DECREF(numpy_quaddtype_module); + + if (finfo_class == NULL) { + PyErr_SetString(PyExc_AttributeError, "Could not find QuadPrecFinfo class in numpy_quaddtype module."); + return NULL; + } + + PyObject *finfo_instance = PyObject_CallNoArgs(finfo_class); + Py_DECREF(finfo_class); + + return finfo_instance; +} + +static PyMethodDef QuadPrecDType_methods[] = { + {"finfo", (PyCFunction)QuadPrecDType_finfo, METH_NOARGS, + "Return floating-point information for this QuadPrecDType"}, + {NULL, NULL, 0, NULL} +}; + PyArray_DTypeMeta QuadPrecDType = { {{ PyVarObject_HEAD_INIT(NULL, 0).tp_name = "numpy_quaddtype.QuadPrecDType", @@ -264,6 +259,7 @@ PyArray_DTypeMeta QuadPrecDType = { .tp_new = QuadPrecDType_new, .tp_repr = (reprfunc)QuadPrecDType_repr, .tp_str = (reprfunc)QuadPrecDType_str, + .tp_methods = QuadPrecDType_methods, }}, }; From 67907c20ffb5c26bcc3d44e39eee69f745bea9a3 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Sat, 20 Sep 2025 13:15:19 +0000 Subject: [PATCH 4/4] dont cast float --- quaddtype/numpy_quaddtype/__init__.py | 38 +++++++++++++-------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/quaddtype/numpy_quaddtype/__init__.py b/quaddtype/numpy_quaddtype/__init__.py index b1a38c38..8cbd24af 100644 --- a/quaddtype/numpy_quaddtype/__init__.py +++ b/quaddtype/numpy_quaddtype/__init__.py @@ -8,7 +8,7 @@ get_quadblas_version ) -from dataclasses import dataclass +from dataclasses import dataclass, field __all__ = [ 'QuadPrecision', 'QuadPrecDType', 'SleefQuadPrecision', 'LongDoubleQuadPrecision', @@ -56,24 +56,24 @@ class QuadPrecFinfo: used by the QuadPrecDType, similar to numpy.finfo but customized for quad precision arithmetic. """ - bits: int = int(bits) - eps: float = float(epsilon) - epsneg: float = float(epsilon) - iexp: int = int(precision) + bits: int = field(default_factory=lambda: bits) + eps: float = field(default_factory=lambda: epsilon) + epsneg: float = field(default_factory=lambda: epsilon) + iexp: int = field(default_factory=lambda: precision) machar: object = None - machep: float = float(epsilon) - max: float = float(max_value) - maxexp: float = float(max_value) - min: float = float(smallest_normal) - minexp: float = float(smallest_normal) - negep: float = float(epsilon) - nexp: int = int(bits) - int(precision) - 1 - nmant: int = int(precision) - precision: int = int(precision) - resolution: float = float(resolution) - tiny: float = float(smallest_normal) - smallest_normal: float = float(smallest_normal) - smallest_subnormal: float = float(smallest_subnormal) + machep: float = field(default_factory=lambda: epsilon) + max: float = field(default_factory=lambda: max_value) + maxexp: float = field(default_factory=lambda: max_value) + min: float = field(default_factory=lambda: smallest_normal) + minexp: float = field(default_factory=lambda: smallest_normal) + negep: float = field(default_factory=lambda: epsilon) + nexp: int = field(default_factory=lambda: bits - precision - 1) + nmant: int = field(default_factory=lambda: precision) + precision: int = field(default_factory=lambda: precision) + resolution: float = field(default_factory=lambda: resolution) + tiny: float = field(default_factory=lambda: smallest_normal) + smallest_normal: float = field(default_factory=lambda: smallest_normal) + smallest_subnormal: float = field(default_factory=lambda: smallest_subnormal) def get(self, attr): return getattr(self, attr, None) @@ -82,4 +82,4 @@ def __str__(self): return f"QuadPrecFinfo(precision={self.precision}, resolution={self.resolution})" def __repr__(self): - return f"QuadPrecFinfo(max={self.max}, min={self.min}, eps={self.eps}, bits={self.bits})" + return f"QuadPrecFinfo(max={self.max}, min={self.min}, eps={self.eps}, bits={self.bits})" \ No newline at end of file