Skip to content

Commit a8b2599

Browse files
committed
adding quad precision support with sleef
1 parent 6ec99a5 commit a8b2599

File tree

9 files changed

+342
-117
lines changed

9 files changed

+342
-117
lines changed

quaddtype2/meson.build

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
project(
2-
'quaddtype2',
3-
'c',
4-
)
1+
project('quaddtype2', 'c')
52

63
py_mod = import('python')
74
py = py_mod.find_installation('/home/rootacess/numpy-user-dtypes/quaddtype2/.venv/bin/python3')
85

6+
c = meson.get_compiler('c')
7+
sleef = c.find_library('sleef')
8+
sleefquad_math =c.find_library('sleefquad')
9+
910
incdir_numpy = run_command(py,
1011
[
1112
'-c',
@@ -15,31 +16,32 @@ incdir_numpy = run_command(py,
1516
).stdout().strip()
1617

1718
includes = include_directories(
18-
[
19-
incdir_numpy,
20-
'quaddtype/src'
21-
]
19+
[
20+
incdir_numpy,
21+
'quaddtype/src'
22+
]
2223
)
2324

2425
srcs = [
25-
'quaddtype/src/dtype.c',
26-
'quaddtype/src/quaddtype_main.c',
26+
'quaddtype/src/scalar.h',
27+
'quaddtype/src/scalar.c',
28+
'quaddtype/src/dtype.h',
29+
'quaddtype/src/dtype.c',
30+
'quaddtype/src/quaddtype_main.c'
2731
]
2832

2933
py.install_sources(
30-
[
31-
'quaddtype/__init__.py',
32-
'quaddtype/quadscalar.py'
33-
],
34-
subdir: 'quaddtype',
35-
pure: false
34+
[
35+
'quaddtype/__init__.py',
36+
],
37+
subdir: 'quaddtype',
38+
pure: false
3639
)
3740

38-
py.extension_module(
39-
'_quaddtype_main',
40-
srcs,
41-
c_args: ['-g', '-O0' ,'-lsleef', '-lsleefquad'],
42-
install: true,
43-
subdir: 'quaddtype',
44-
include_directories: includes
45-
)
41+
py.extension_module('_quaddtype_main',
42+
srcs,
43+
c_args: ['-g', '-O0', '-lsleef', '-lsleefquad'],
44+
install: true,
45+
subdir: 'quaddtype',
46+
include_directories: includes
47+
)

quaddtype2/quaddtype/__init__.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1 @@
1-
from .quadscalar import QuadScalar
2-
from ._quaddtype_main import QuadDType
3-
4-
__all__ = ["QuadScalar", "QuadDType"]
1+
from ._quaddtype_main import QuadPrecDType, QuadPrecision

quaddtype2/quaddtype/quadscalar.py

Lines changed: 0 additions & 11 deletions
This file was deleted.

quaddtype2/quaddtype/src/dtype.c

Lines changed: 158 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,89 +1,202 @@
11
#include <Python.h>
2-
#include<sleef.h>
3-
#include<sleefquad.h>
2+
#include <sleef.h>
3+
#include <sleefquad.h>
44

5-
#define PY_ARRAY_UNIQUE_SYMBOL quaddtype_ARRAY_API
6-
#define PY_UFUNC_UNIQUE_SYMBOL quaddtype_UFUNC_API
5+
#define PY_ARRAY_UNIQUE_SYMBOL QuadPrecType_ARRAY_API
6+
#define PY_UFUNC_UNIQUE_SYMBOL QuadPrecType_UFUNC_API
77
#define NPY_NO_DEPRECATED_API NPY_2_0_API_VERSION
88
#define NPY_TARGET_VERSION NPY_2_0_API_VERSION
99
#define NO_IMPORT_ARRAY
1010
#define NO_IMPORT_UFUNC
11-
#include "numpy/ndarraytypes.h"
1211
#include "numpy/arrayobject.h"
12+
#include "numpy/ndarraytypes.h"
1313
#include "numpy/dtype_api.h"
14+
#include "numpy/_public_dtype_api_table.h" // not included in dtype_api.h
1415

16+
#include "scalar.h"
1517
#include "dtype.h"
1618

19+
static inline int quad_load(Sleef_quad *x, char *data_ptr)
20+
{
21+
if (data_ptr == NULL || x == NULL)
22+
{
23+
PyErr_SetString(PyExc_ValueError, "Invalid memory location");
24+
return -1;
25+
}
26+
*x = *(Sleef_quad *)data_ptr;
27+
return 0;
28+
}
1729

18-
PyTypeObject *QuadScalar_Type = NULL;
30+
static inline int quad_store(char *data_ptr, Sleef_quad x)
31+
{
32+
if (data_ptr == NULL)
33+
{
34+
PyErr_SetString(PyExc_ValueError, "Invalid memory location");
35+
return -1;
36+
}
37+
*(Sleef_quad *)data_ptr = x;
38+
return 0;
39+
}
1940

20-
QuadDTypeObject *new_quaddtype_instance(void)
41+
QuadPrecDTypeObject * new_quaddtype_instance(void)
2142
{
22-
QuadDTypeObject *new =
23-
(QuadDTypeObject *)PyArrayDescr_Type.tp_new((PyTypeObject *)&QuadDType, NULL, NULL);
43+
QuadPrecDTypeObject *new = (QuadPrecDTypeObject *)PyArrayDescr_Type.tp_new((PyTypeObject *)&QuadPrecDType, NULL, NULL);
2444
if (new == NULL) {
2545
return NULL;
2646
}
27-
2847
new->base.elsize = sizeof(Sleef_quad);
2948
new->base.alignment = _Alignof(Sleef_quad);
49+
new->base.flags |= NPY_NEEDS_INIT; // Indicates memory for this data-type must be initialized (set to 0) on creation.
50+
3051
return new;
3152
}
3253

33-
static PyObject *quaddtype_new(PyTypeObject *NPY_UNUSED(cls), PyObject *args, PyObject *kwargs)
54+
static QuadPrecDTypeObject * ensure_canonical(QuadPrecDTypeObject *self)
3455
{
35-
return (PyObject *)new_quaddtype_instance();
56+
Py_INCREF(self);
57+
return self;
3658
}
3759

38-
static void quaddtype_dealloc(QuadDTypeObject *self)
60+
static QuadPrecDTypeObject * common_instance(QuadPrecDTypeObject *dtype1, QuadPrecDTypeObject *dtype2)
3961
{
40-
PyArrayDescr_Type.tp_dealloc((PyObject *)self);
62+
Py_INCREF(dtype1);
63+
return dtype1;
4164
}
4265

43-
static PyObject *quaddtype_repr(QuadDTypeObject *self)
66+
67+
static PyArray_DTypeMeta * common_dtype(PyArray_DTypeMeta *cls, PyArray_DTypeMeta *other)
4468
{
45-
PyObject *res = PyUnicode_FromString("This is a Sleef based quad (128-bit float) dtype.");
46-
return res;
47-
}
69+
// Promote integer and floating-point types to QuadPrecDType
70+
if (other->type_num >= 0 &&
71+
(PyTypeNum_ISINTEGER(other->type_num) ||
72+
PyTypeNum_ISFLOAT(other->type_num))) {
73+
Py_INCREF(cls);
74+
return cls;
75+
}
76+
// Don't promote complex types
77+
if (PyTypeNum_ISCOMPLEX(other->type_num)) {
78+
Py_INCREF(Py_NotImplemented);
79+
return (PyArray_DTypeMeta *)Py_NotImplemented;
80+
}
4881

49-
PyArray_DTypeMeta QuadDType = {
50-
{{
51-
PyVarObject_HEAD_INIT(NULL, 0).tp_name = "quaddtype.QuadDType",
52-
.tp_basicsize = sizeof(QuadDTypeObject),
53-
.tp_new = quaddtype_new,
54-
.tp_dealloc = (destructor)quaddtype_dealloc,
55-
.tp_repr = (reprfunc)quaddtype_repr,
56-
.tp_str = (reprfunc)quaddtype_repr,
57-
}},
58-
};
82+
Py_INCREF(Py_NotImplemented);
83+
return (PyArray_DTypeMeta *)Py_NotImplemented;
84+
}
5985

60-
int init_quad_dtype(void)
86+
static PyArray_Descr *
87+
quadprec_discover_descriptor_from_pyobject(PyArray_DTypeMeta *NPY_UNUSED(cls), PyObject *obj)
6188
{
62-
PyArrayMethod_Spec *casts[] = {
63-
NULL,
64-
};
65-
66-
PyArrayDTypeMeta_Spec QuadDType_DTypeSpec = {
67-
.flags = NPY_DT_NUMERIC,
68-
.casts = casts,
69-
.typeobj = QuadScalar_Type,
70-
.slots = NULL,
71-
};
89+
if (Py_TYPE(obj) != &QuadPrecision_Type)
90+
{
91+
PyErr_SetString(PyExc_TypeError, "Can only store QuadPrecision in a QuadPrecDType array.");
92+
return NULL;
93+
}
94+
return (PyArray_Descr *)new_quaddtype_instance();
95+
}
7296

73-
((PyObject *)&QuadDType)->ob_type = &PyArrayDTypeMeta_Type;
74-
((PyTypeObject *)&QuadDType)->tp_base = &PyArrayDescr_Type;
75-
if (PyType_Ready((PyTypeObject *)&QuadDType) < 0) {
76-
return -1;
97+
static int quadprec_setitem(QuadPrecDTypeObject *descr, PyObject *obj, char *dataptr)
98+
{
99+
QuadPrecisionObject *value;
100+
if (PyObject_TypeCheck(obj, &QuadPrecision_Type))
101+
{
102+
Py_INCREF(obj);
103+
value = (QuadPrecisionObject *)obj;
104+
}
105+
else
106+
{
107+
value = QuadPrecision_from_object(obj);
108+
if (value == NULL) {
109+
return -1;
110+
}
77111
}
78112

79-
if (PyArrayInitDTypeMeta_FromSpec(&QuadDType, &QuadDType_DTypeSpec) < 0) {
113+
if (quad_store(dataptr, value->quad.value) < 0)
114+
{
115+
Py_DECREF(value);
80116
return -1;
81117
}
82118

83-
QuadDType.singleton = PyArray_GetDefaultDescr(&QuadDType);
119+
Py_DECREF(value);
84120
return 0;
85121
}
86122

123+
static PyObject * quadprec_getitem(QuadPrecDTypeObject *descr, char *dataptr)
124+
{
125+
QuadPrecisionObject *new = QuadPrecision_raw_new();
126+
if (!new)
127+
{
128+
return NULL;
129+
}
130+
if (quad_load(&new->quad.value, dataptr) < 0)
131+
{
132+
Py_DECREF(new);
133+
return NULL;
134+
}
135+
return (PyObject *)new;
136+
}
137+
138+
static PyType_Slot QuadPrecDType_Slots[] =
139+
{
140+
{NPY_DT_ensure_canonical, &ensure_canonical},
141+
{NPY_DT_common_instance, &common_instance},
142+
{NPY_DT_common_dtype, &common_dtype},
143+
{NPY_DT_discover_descr_from_pyobject, &quadprec_discover_descriptor_from_pyobject},
144+
{NPY_DT_setitem, &quadprec_setitem},
145+
{NPY_DT_getitem, &quadprec_getitem},
146+
{0, NULL}
147+
};
148+
87149

150+
static PyObject * QuadPrecDType_new(PyTypeObject *NPY_UNUSED(cls), PyObject *args, PyObject *kwds)
151+
{
152+
if (PyTuple_GET_SIZE(args) != 0 || (kwds != NULL && PyDict_Size(kwds) != 0)) {
153+
PyErr_SetString(PyExc_TypeError,
154+
"QuadPrecDType takes no arguments");
155+
return NULL;
156+
}
88157

158+
return (PyObject *)new_quaddtype_instance();
159+
}
89160

161+
static PyObject * QuadPrecDType_repr(QuadPrecDTypeObject *self)
162+
{
163+
return PyUnicode_FromString("QuadPrecDType()");
164+
}
165+
166+
PyArray_DTypeMeta QuadPrecDType = {
167+
{{
168+
PyVarObject_HEAD_INIT(NULL, 0)
169+
.tp_name = "QuadPrecDType.QuadPrecDType",
170+
.tp_basicsize = sizeof(QuadPrecDTypeObject),
171+
.tp_new = QuadPrecDType_new,
172+
.tp_repr = (reprfunc)QuadPrecDType_repr,
173+
.tp_str = (reprfunc)QuadPrecDType_repr,
174+
}},
175+
};
176+
177+
int init_quadprec_dtype(void)
178+
{
179+
PyArrayMethod_Spec **casts = NULL; // Initialize casts if needed
180+
181+
PyArrayDTypeMeta_Spec QuadPrecDType_DTypeSpec = {
182+
.flags = NPY_DT_NUMERIC,
183+
.casts = casts,
184+
.typeobj = &QuadPrecision_Type,
185+
.slots = QuadPrecDType_Slots,
186+
};
187+
188+
((PyObject *)&QuadPrecDType)->ob_type = &PyArrayDTypeMeta_Type;
189+
190+
((PyTypeObject *)&QuadPrecDType)->tp_base = &PyArrayDescr_Type;
191+
192+
if (PyType_Ready((PyTypeObject *)&QuadPrecDType) < 0)
193+
{
194+
return -1;
195+
}
196+
197+
if (PyArrayInitDTypeMeta_FromSpec(&QuadPrecDType, &QuadPrecDType_DTypeSpec) < 0)
198+
{
199+
return -1;
200+
}
201+
return 0;
202+
}

quaddtype2/quaddtype/src/dtype.h

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
1-
#ifndef _NPY_DTYPE_H
2-
#define _NPY_DTYPE_H
1+
#ifndef _QUADDTYPE_DTYPE_H
2+
#define _QUADDTYPE_DTYPE_H
33

44
#include<Python.h>
5+
#include<sleef.h>
56
#include<numpy/ndarraytypes.h>
67
#include<numpy/dtype_api.h>
78

9+
#include "scalar.h"
10+
811
typedef struct
912
{
1013
PyArray_Descr base;
1114

12-
} QuadDTypeObject;
15+
} QuadPrecDTypeObject;
1316

14-
extern PyArray_DTypeMeta QuadDType;
15-
extern PyTypeObject *QuadScalar_Type;
17+
extern PyArray_DTypeMeta QuadPrecDType;
1618

17-
QuadDTypeObject * new_quaddtype_instance(void);
19+
QuadPrecDTypeObject * new_quaddtype_instance(void);
1820

19-
int init_quad_dtype(void);
21+
int init_quadprec_dtype(void);
2022

2123
#endif

0 commit comments

Comments
 (0)