1
+ #define PY_ARRAY_UNIQUE_SYMBOL QuadPrecType_ARRAY_API
2
+ #define PY_UFUNC_UNIQUE_SYMBOL QuadPrecType_UFUNC_API
3
+ #define NPY_NO_DEPRECATED_API NPY_2_0_API_VERSION
4
+ #define NPY_TARGET_VERSION NPY_2_0_API_VERSION
5
+ #define NO_IMPORT_ARRAY
6
+ #define NO_IMPORT_UFUNC
7
+
8
+ extern " C" {
9
+ #include < Python.h>
10
+ #include < cstdio>
11
+
12
+ #include " numpy/arrayobject.h"
13
+ #include " numpy/ndarraytypes.h"
14
+ #include " numpy/ufuncobject.h"
15
+ #include " numpy/dtype_api.h"
16
+ }
17
+ #include " ../quad_common.h"
18
+ #include " ../scalar.h"
19
+ #include " ../dtype.h"
20
+ #include " ../ops.hpp"
21
+
22
+ // Forward declarations for frexp operations
23
+ static Sleef_quad quad_frexp_mantissa (const Sleef_quad *op, int *exp);
24
+ static long double ld_frexp_mantissa (const long double *op, int *exp);
25
+
26
+ static Sleef_quad
27
+ quad_frexp_mantissa (const Sleef_quad *op, int *exp)
28
+ {
29
+ return Sleef_frexpq1 (*op, exp);
30
+ }
31
+
32
+ static long double
33
+ ld_frexp_mantissa (const long double *op, int *exp)
34
+ {
35
+ return frexpl (*op, exp);
36
+ }
37
+
38
+ static NPY_CASTING
39
+ quad_frexp_resolve_descriptors (PyObject *self, PyArray_DTypeMeta *const dtypes[],
40
+ PyArray_Descr *const given_descrs[], PyArray_Descr *loop_descrs[],
41
+ npy_intp *NPY_UNUSED (view_offset))
42
+ {
43
+ Py_INCREF (given_descrs[0 ]);
44
+ loop_descrs[0 ] = given_descrs[0 ];
45
+
46
+ // Output 1: QuadPrecDType (mantissa)
47
+ if (given_descrs[1 ] == NULL ) {
48
+ Py_INCREF (given_descrs[0 ]);
49
+ loop_descrs[1 ] = given_descrs[0 ];
50
+ }
51
+ else {
52
+ Py_INCREF (given_descrs[1 ]);
53
+ loop_descrs[1 ] = given_descrs[1 ];
54
+ }
55
+
56
+ // Output 2: Int32 (exponent)
57
+ if (given_descrs[2 ] == NULL ) {
58
+ loop_descrs[2 ] = PyArray_DescrFromType (NPY_INT32);
59
+ }
60
+ else {
61
+ Py_INCREF (given_descrs[2 ]);
62
+ loop_descrs[2 ] = given_descrs[2 ];
63
+ }
64
+
65
+ return NPY_NO_CASTING;
66
+ }
67
+
68
+ static int
69
+ quad_frexp_strided_loop_unaligned (PyArrayMethod_Context *context, char *const data[],
70
+ npy_intp const dimensions[], npy_intp const strides[],
71
+ NpyAuxData *auxdata)
72
+ {
73
+ npy_intp N = dimensions[0 ];
74
+ char *in_ptr = data[0 ];
75
+ char *mantissa_ptr = data[1 ];
76
+ char *exp_ptr = data[2 ];
77
+ npy_intp in_stride = strides[0 ];
78
+ npy_intp mantissa_stride = strides[1 ];
79
+ npy_intp exp_stride = strides[2 ];
80
+
81
+ QuadPrecDTypeObject *descr = (QuadPrecDTypeObject *)context->descriptors [0 ];
82
+ QuadBackendType backend = descr->backend ;
83
+ size_t elem_size = (backend == BACKEND_SLEEF) ? sizeof (Sleef_quad) : sizeof (long double );
84
+
85
+ quad_value in, mantissa;
86
+ int exp;
87
+ while (N--) {
88
+ memcpy (&in, in_ptr, elem_size);
89
+
90
+ if (backend == BACKEND_SLEEF) {
91
+ mantissa.sleef_value = quad_frexp_mantissa (&in.sleef_value , &exp);
92
+ }
93
+ else {
94
+ mantissa.longdouble_value = ld_frexp_mantissa (&in.longdouble_value , &exp);
95
+ }
96
+
97
+ memcpy (mantissa_ptr, &mantissa, elem_size);
98
+ *(npy_int32 *)exp_ptr = (npy_int32)exp;
99
+
100
+ in_ptr += in_stride;
101
+ mantissa_ptr += mantissa_stride;
102
+ exp_ptr += exp_stride;
103
+ }
104
+ return 0 ;
105
+ }
106
+
107
+ static int
108
+ quad_frexp_strided_loop_aligned (PyArrayMethod_Context *context, char *const data[],
109
+ npy_intp const dimensions[], npy_intp const strides[],
110
+ NpyAuxData *auxdata)
111
+ {
112
+ npy_intp N = dimensions[0 ];
113
+ char *in_ptr = data[0 ];
114
+ char *mantissa_ptr = data[1 ];
115
+ char *exp_ptr = data[2 ];
116
+ npy_intp in_stride = strides[0 ];
117
+ npy_intp mantissa_stride = strides[1 ];
118
+ npy_intp exp_stride = strides[2 ];
119
+
120
+ QuadPrecDTypeObject *descr = (QuadPrecDTypeObject *)context->descriptors [0 ];
121
+ QuadBackendType backend = descr->backend ;
122
+
123
+ int exp;
124
+ while (N--) {
125
+ if (backend == BACKEND_SLEEF) {
126
+ *(Sleef_quad *)mantissa_ptr = quad_frexp_mantissa ((Sleef_quad *)in_ptr, &exp);
127
+ }
128
+ else {
129
+ *(long double *)mantissa_ptr = ld_frexp_mantissa ((long double *)in_ptr, &exp);
130
+ }
131
+
132
+ *(npy_int32 *)exp_ptr = (npy_int32)exp;
133
+
134
+ in_ptr += in_stride;
135
+ mantissa_ptr += mantissa_stride;
136
+ exp_ptr += exp_stride;
137
+ }
138
+ return 0 ;
139
+ }
140
+
141
+ int
142
+ create_quad_frexp_ufunc (PyObject *numpy)
143
+ {
144
+ PyObject *ufunc = PyObject_GetAttrString (numpy, " frexp" );
145
+ if (ufunc == NULL ) {
146
+ return -1 ;
147
+ }
148
+
149
+ PyArray_DTypeMeta *dtypes[3 ] = {&QuadPrecDType, &QuadPrecDType, &PyArray_Int32DType};
150
+
151
+ PyType_Slot slots[] = {
152
+ {NPY_METH_resolve_descriptors, (void *)&quad_frexp_resolve_descriptors},
153
+ {NPY_METH_strided_loop, (void *)&quad_frexp_strided_loop_aligned},
154
+ {NPY_METH_unaligned_strided_loop, (void *)&quad_frexp_strided_loop_unaligned},
155
+ {0 , NULL }};
156
+
157
+ PyArrayMethod_Spec Spec = {
158
+ .name = " quad_frexp" ,
159
+ .nin = 1 ,
160
+ .nout = 2 ,
161
+ .casting = NPY_NO_CASTING,
162
+ .flags = NPY_METH_SUPPORTS_UNALIGNED,
163
+ .dtypes = dtypes,
164
+ .slots = slots,
165
+ };
166
+
167
+ if (PyUFunc_AddLoopFromSpec (ufunc, &Spec) < 0 ) {
168
+ return -1 ;
169
+ }
170
+
171
+ Py_DECREF (ufunc);
172
+ return 0 ;
173
+ }
174
+
175
+ int
176
+ init_quad_frexp (PyObject *numpy)
177
+ {
178
+ if (create_quad_frexp_ufunc (numpy) < 0 ) {
179
+ return -1 ;
180
+ }
181
+ return 0 ;
182
+ }
0 commit comments