2

I decided to port some of my Python functions to C, mostly following this simple tutorial. Problem is that my C function returns a complex float, and there's no corresponding type in ctypes's documentation. This is is a problem I couldn't solve myself with my limited knowledge on cross-language coding and C, even extended by Google.

My C function works like this:

#include <tgmath.h>
float _Complex integrand(float _Complex theta1, double r, double z){
    //[code] }

So, based on the tutorial, the corresponding Python wrapper (probably) should be something like this:

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)

But what should this type be? How should I do this?

If the fact that the function also has a complex argument makes it significantly more complicated, please ignore the complex argument.

1
  • As an aside, your global _integr statement is unnecessary and the oykd probably cause an experienced Python programmer to assume this function will mutate global state when it does not Commented Jul 28, 2018 at 22:29

2 Answers 2

1

Create a small C wrapper function:

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);
}

The re and im pointers hold the real and imaginary parts of theta when called, and the real and imaginary parts of the result afterwards.

In your Python code, call integrand_wrapper() using e.g.

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))

Note that if integrand() is defined in a binary library you cannot modify, you can always create another dynamic library containing only integrand_wrapper, that is dynamically linked (in C) to the original binary library.

Overall, I don't think the added overhead is significant at all. It is certainly worth testing.

Sign up to request clarification or add additional context in comments.

Comments

1

Naively, perhaps split it into two arguments, Re(z), Im(z) If that's not an option, perhaps pass the argument to the python function complex().

These are naive solutions; perhaps they don't work but if you haven't considered it and in lack of better responses, may be worth experimenting with.

Good luck!

1 Comment

Splitting the values occured to me too, but unfortunately it'd badly damage the purpose (performance improvement), as I'd have to calculate essentially everything twice. And there are some costly functions there. Maybe I could go with putting them in an array though at the end... hmm.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.