+----------------------------------+---------------------------------+-----------------+
| ctypes type | C type | Python type |
+==================================+=================================+=================+
+| :class:`c_float_complex` | :c:expr:`float complex` | complex |
++----------------------------------+---------------------------------+-----------------+
| :class:`c_double_complex` | :c:expr:`double complex` | complex |
+----------------------------------+---------------------------------+-----------------+
+| :class:`c_longdouble_complex` | :c:expr:`long double complex` | complex |
++----------------------------------+---------------------------------+-----------------+
All these types can be created by calling them with an optional initializer of
.. versionadded:: 3.14
+.. class:: c_float_complex
+
+ Represents the C :c:expr:`float complex` datatype, if available. The
+ constructor accepts an optional :class:`complex` initializer.
+
+ .. versionadded:: 3.14
+
+
+.. class:: c_longdouble_complex
+
+ Represents the C :c:expr:`long double complex` datatype, if available. The
+ constructor accepts an optional :class:`complex` initializer.
+
+ .. versionadded:: 3.14
+
+
.. class:: c_int
Represents the C :c:expr:`signed int` datatype. The constructor accepts an
try:
class c_double_complex(_SimpleCData):
_type_ = "C"
+ class c_float_complex(_SimpleCData):
+ _type_ = "E"
+ class c_longdouble_complex(_SimpleCData):
+ _type_ = "F"
except AttributeError:
pass
self.assertAlmostEqual(lib.my_csqrt(-1-0.01j),
0.004999937502734214-1.0000124996093955j)
+ lib.my_csqrtf.argtypes = ctypes.c_float_complex,
+ lib.my_csqrtf.restype = ctypes.c_float_complex
+ self.assertAlmostEqual(lib.my_csqrtf(-1+0.01j),
+ 0.004999937502734214+1.0000124996093955j)
+ self.assertAlmostEqual(lib.my_csqrtf(-1-0.01j),
+ 0.004999937502734214-1.0000124996093955j)
+
+ lib.my_csqrtl.argtypes = ctypes.c_longdouble_complex,
+ lib.my_csqrtl.restype = ctypes.c_longdouble_complex
+ self.assertAlmostEqual(lib.my_csqrtl(-1+0.01j),
+ 0.004999937502734214+1.0000124996093955j)
+ self.assertAlmostEqual(lib.my_csqrtl(-1-0.01j),
+ 0.004999937502734214-1.0000124996093955j)
+
def test_qsort(self):
comparefunc = CFUNCTYPE(c_int, POINTER(c_char), POINTER(c_char))
lib.my_qsort.argtypes = c_void_p, c_size_t, c_size_t, comparefunc
@unittest.skipUnless(hasattr(ctypes, "c_double_complex"),
"requires C11 complex type")
def test_complex(self):
- for t in [ctypes.c_double_complex]:
+ for t in [ctypes.c_double_complex, ctypes.c_float_complex,
+ ctypes.c_longdouble_complex]:
self.assertEqual(t(1).value, 1+0j)
self.assertEqual(t(1.0).value, 1+0j)
self.assertEqual(t(1+0.125j).value, 1+0.125j)
values = [complex(*_) for _ in combinations([1, -1, 0.0, -0.0, 2,
-3, INF, -INF, NAN], 2)]
for z in values:
- with self.subTest(z=z):
- z2 = ctypes.c_double_complex(z).value
- self.assertComplexesAreIdentical(z, z2)
+ for t in [ctypes.c_double_complex, ctypes.c_float_complex,
+ ctypes.c_longdouble_complex]:
+ with self.subTest(z=z, type=t):
+ self.assertComplexesAreIdentical(z, t(z).value)
def test_integers(self):
f = FloatLike()
-Support :c:expr:`double complex` C type in :mod:`ctypes` via
-:class:`~ctypes.c_double_complex` if compiler has C11 complex
-arithmetic. Patch by Sergey B Kirpichev.
+Support :c:expr:`float complex`, :c:expr:`double complex` and
+:c:expr:`long double complex` C types in :mod:`ctypes` as
+:class:`~ctypes.c_float_complex`, :class:`~ctypes.c_double_complex` and
+:class:`~ctypes.c_longdouble_complex` if the compiler has C11 complex arithmetic.
+Patch by Sergey B Kirpichev.
#if !defined(CMPLX)
# if defined(__clang__) && __has_builtin(__builtin_complex)
# define CMPLX(x, y) __builtin_complex ((double) (x), (double) (y))
+# define CMPLXF(x, y) __builtin_complex ((float) (x), (float) (y))
+# define CMPLXL(x, y) __builtin_complex ((long double) (x), (long double) (y))
# else
static inline double complex
CMPLX(double real, double imag)
((double *)(&z))[1] = imag;
return z;
}
+
+static inline float complex
+CMPLXF(float real, float imag)
+{
+ float complex z;
+ ((float *)(&z))[0] = real;
+ ((float *)(&z))[1] = imag;
+ return z;
+}
+
+static inline long double complex
+CMPLXL(long double real, long double imag)
+{
+ long double complex z;
+ ((long double *)(&z))[0] = real;
+ ((long double *)(&z))[1] = imag;
+ return z;
+}
# endif
#endif
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=dd4d9646c56f43a9]*/
#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
-static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdCfuzZqQPXOv?g";
+static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdCEFfuzZqQPXOv?g";
#else
static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdfuzZqQPXOv?g";
#endif
stginfo->ffi_type_pointer = *fmt->pffi_type;
}
else {
+ const size_t els_size = sizeof(fmt->pffi_type->elements);
stginfo->ffi_type_pointer.size = fmt->pffi_type->size;
stginfo->ffi_type_pointer.alignment = fmt->pffi_type->alignment;
stginfo->ffi_type_pointer.type = fmt->pffi_type->type;
- stginfo->ffi_type_pointer.elements = PyMem_Malloc(2 * sizeof(ffi_type));
+ stginfo->ffi_type_pointer.elements = PyMem_Malloc(els_size);
memcpy(stginfo->ffi_type_pointer.elements,
- fmt->pffi_type->elements, 2 * sizeof(ffi_type));
+ fmt->pffi_type->elements, els_size);
}
stginfo->align = fmt->pffi_type->alignment;
stginfo->length = 0;
{
return csqrt(a);
}
+
+EXPORT(float complex) my_csqrtf(float complex a)
+{
+ return csqrtf(a);
+}
+
+EXPORT(long double complex) my_csqrtl(long double complex a)
+{
+ return csqrtl(a);
+}
#endif
EXPORT(void) my_qsort(void *base, size_t num, size_t width, int(*compare)(const void*, const void*))
void *p;
#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
double complex C;
+ float complex E;
+ long double complex F;
#endif
};
memcpy(&x, ptr, sizeof(x));
return PyComplex_FromDoubles(creal(x), cimag(x));
}
+
+static PyObject *
+E_set(void *ptr, PyObject *value, Py_ssize_t size)
+{
+ Py_complex c = PyComplex_AsCComplex(value);
+
+ if (c.real == -1 && PyErr_Occurred()) {
+ return NULL;
+ }
+ float complex x = CMPLXF((float)c.real, (float)c.imag);
+ memcpy(ptr, &x, sizeof(x));
+ _RET(value);
+}
+
+static PyObject *
+E_get(void *ptr, Py_ssize_t size)
+{
+ float complex x;
+
+ memcpy(&x, ptr, sizeof(x));
+ return PyComplex_FromDoubles(crealf(x), cimagf(x));
+}
+
+static PyObject *
+F_set(void *ptr, PyObject *value, Py_ssize_t size)
+{
+ Py_complex c = PyComplex_AsCComplex(value);
+
+ if (c.real == -1 && PyErr_Occurred()) {
+ return NULL;
+ }
+ long double complex x = CMPLXL(c.real, c.imag);
+ memcpy(ptr, &x, sizeof(x));
+ _RET(value);
+}
+
+static PyObject *
+F_get(void *ptr, Py_ssize_t size)
+{
+ long double complex x;
+
+ memcpy(&x, ptr, sizeof(x));
+ return PyComplex_FromDoubles((double)creall(x), (double)cimagl(x));
+}
#endif
static PyObject *
{ 'd', d_set, d_get, NULL, d_set_sw, d_get_sw},
#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
{ 'C', C_set, C_get, NULL},
+ { 'E', E_set, E_get, NULL},
+ { 'F', F_set, F_get, NULL},
#endif
{ 'g', g_set, g_get, NULL},
{ 'f', f_set, f_get, NULL, f_set_sw, f_get_sw},
case 'd': fd->pffi_type = &ffi_type_double; break;
#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
case 'C': fd->pffi_type = &ffi_type_complex_double; break;
+ case 'E': fd->pffi_type = &ffi_type_complex_float; break;
+ case 'F': fd->pffi_type = &ffi_type_complex_longdouble; break;
#endif
case 'g': fd->pffi_type = &ffi_type_longdouble; break;
case 'f': fd->pffi_type = &ffi_type_float; break;
void *p;
#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
double complex C;
+ float complex E;
+ long double complex F;
#endif
} value;
PyObject *obj;