Я решил перенести некоторые из моих функций Python на C, в основном следуя этому простому учебнику. Проблема в том, что моя функция C возвращает сложный float, и в документации ctypes нет соответствующего типа. Это проблема, которую я не мог решить самостоятельно с моими ограниченными знаниями по кросс-языковому кодированию и C, даже расширенным Google.
Моя функция C работает следующим образом:
#include <tgmath.h>
float _Complex integrand(float _Complex theta1, double r, double z){
//[code] }
Итак, на основе учебника соответствующая оболочка Python (возможно) должна быть примерно такой:
complextype = '??????'
_integr = ctypes.CDLL('libintegrand.so')
_integr.integrand.argtypes = (complextype, ctypes.c_double, ctypes.c_double)
def integrand(theta1, r, z):
global _integr
result = _integr.integrand(complextype(theta1), ctypes.c_double(r), ctypes.c_double(z))
return float(result)
Но какой должен быть этот тип? Как мне это сделать?
Если факт, что функция также имеет сложный аргумент, делает его значительно более сложным, пожалуйста, игнорируйте сложный аргумент.
Создайте небольшую C-обертку:
void integrand_wrapper(float *re, float *im, double r, double z)
{
float _Complex result;
float _Complex theta = (*re) + I*(*im);
result = integrand(theta, r, z);
(*re) = creal(result);
(*im) = cimag(result);
}
В re
и im
указателях находятся вещественные и мнимые части theta
при вызове, а затем действительная и мнимая части результата.
В коде Python вызовите integrand_wrapper()
используя, например,
def integrand(theta, r, z):
global _integr
theta = complex(theta)
re = c_float(theta.real)
im = c_float(theta.imag)
_integr.integrand_wrapper(byref(re), byref(im), c_double(r), c_double(z))
return complex(float(re), float(im))
Обратите внимание, что если integrand()
определен в бинарной библиотеке, которую вы не можете изменить, вы всегда можете создать другую динамическую библиотеку, содержащую только integrand_wrapper
, который динамически связан (в C) с исходной бинарной библиотекой.
В целом, я не думаю, что дополнительные накладные расходы значительны. Это, безусловно, стоит проверить.
Наивно, возможно, разделите его на два аргумента: Re(z), Im(z)
Если это не опция, возможно, передайте аргумент функции python complex()
.
Это наивные решения; возможно, они не работают, но если вы не учли это и не получили лучших ответов, возможно, стоит поэкспериментировать.
Удачи!
global _integr
операторglobal _integr
является необходимым, и опыт oykd, вероятно, заставит опытного программиста Python предположить, что эта функция будет изменять глобальное состояние, когда оно не