Как использовать функцию C со сложными типами в Python?

1

Я решил перенести некоторые из моих функций 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)

Но какой должен быть этот тип? Как мне это сделать?

Если факт, что функция также имеет сложный аргумент, делает его значительно более сложным, пожалуйста, игнорируйте сложный аргумент.

  • 0
    Кроме того, ваш global _integr оператор global _integr является необходимым, и опыт oykd, вероятно, заставит опытного программиста Python предположить, что эта функция будет изменять глобальное состояние, когда оно не
Теги:
complex-numbers

2 ответа

1
Лучший ответ

Создайте небольшую 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) с исходной бинарной библиотекой.

В целом, я не думаю, что дополнительные накладные расходы значительны. Это, безусловно, стоит проверить.

1

Наивно, возможно, разделите его на два аргумента: Re(z), Im(z) Если это не опция, возможно, передайте аргумент функции python complex().

Это наивные решения; возможно, они не работают, но если вы не учли это и не получили лучших ответов, возможно, стоит поэкспериментировать.

Удачи!

  • 0
    Разделение значений произошло и со мной, но, к сожалению, это сильно повредило бы цель (улучшение производительности), так как мне пришлось бы вычислять практически все дважды. И там есть некоторые дорогостоящие функции. Может быть, я мог бы положить их в массив, хотя в конце ... хм.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню