ctypes中的复数

2024-06-26 00:03:47 发布

您现在位置:Python中文网/ 问答频道 /正文

这可能有点愚蠢,但我尝试使用ctypes调用一个函数,该函数接收一个复杂的向量作为参数。但在ctypes中没有类c\u复合体。 有人知道怎么解决这个问题吗?在

编辑:我指的是python的cype,以防有其他的cype。。。。在


Tags: 函数编辑参数ctypes向量复合体cype
3条回答

正如OP在评论@Armin Rigo的答案时指出的,正确的方法是使用包装器函数。此外,正如在原问题的注释(我)中所提到的,这也是C++和FORTRAN的可能。然而,在这三种语言中实现这一点的方法并不明显。因此,这个答案为每种语言提供了一个工作示例。在

假设你有一个C/C++ +FORTRAN程序,它采用标量复杂的参数。然后,您需要编写一个包装程序,它接受两个浮点/双精度(实数和虚部),将它们组合成一个复数,然后调用原始过程。显然,这可以扩展到复数数组,但现在让我们用一个复数保持简单。在

C

例如,假设您有一个C函数来打印格式化的复数。所以我们有my_complex.c

#include <stdio.h>
#include <complex.h>

void print_complex(double complex z)
{
    printf("%.1f + %.1fi\n", creal(z), cimag(z));
}

然后我们必须添加一个包装器函数(在同一个文件的末尾),如下所示:

^{pr2}$

用通常的方法将其编译到库中:

gcc -shared -fPIC -o my_complex_c.so my_complex.c

然后从Python调用wrapper函数:

from ctypes import CDLL, c_double
c = CDLL('./my_complex_c.so')
c.print_complex_wrapper.argtypes = [c_double, c_double]
z = complex(1.0 + 1j * 2.0)
c.print_complex_wrapper(c_double(z.real), c_double(z.imag))

C++ +/H1>

C++中的相同的东西有点不太灵活,因为需要定义一个^ {< CD2>}接口以避免名称的篡改,并且我们需要用Python处理该类(既按^ this SO Q&A)。在

所以,现在我们有了my_complex.cpp(我已经在其中添加了包装函数):

#include <stdio.h>
#include <complex>

class ComplexPrinter
{
    public:
        void printComplex(std::complex<double> z)
        {   
            printf("%.1f + %.1fi\n", real(z), imag(z));
        }

        void printComplexWrapper(double z_real, double z_imag)
        {   
            std::complex<double> z(z_real, z_imag);
            printComplex(z);
        }   
};

我们还需要添加一个extern "C"接口(在同一个文件的末尾),如下所示:

extern "C" 
{
    ComplexPrinter* ComplexPrinter_new()
    {   
        return new ComplexPrinter();
    }   
    void ComplexPrinter_printComplexWrapper(ComplexPrinter* printer, double z_real, double z_imag)
    {   
        printer->printComplexWrapper(z_real, z_imag);
    }   
}

按常规方法编译到库中:

g++ -shared -fPIC -o my_complex_cpp.so my_complex.cpp

并从Python调用包装器:

from ctypes import CDLL, c_double
cpp = CDLL('./my_complex_cpp.so')
cpp.ComplexPrinter_printComplexWrapper.argtypes = [c_double, c_double]


class ComplexPrinter:

    def __init__(self):
        self.obj = cpp.ComplexPrinter_new()

    def printComplex(self, z):
        cpp.ComplexPrinter_printComplexWrapper(c_double(z.real), c_double(z.imag))


printer = ComplexPrinter()
z = complex(1.0 + 1j * 2.0)
printer.printComplex(z)

Fortran语言

最后在Fortran中,我们在my_complex.f90中有一个原始子例程:

subroutine print_complex(z)
  use iso_c_binding, only: c_double_complex
  implicit none
  complex(c_double_complex), intent(in) :: z
  character(len=16) :: my_format = "(f4.1,a3,f4.1,a)"
  print my_format, real(z), " + ", aimag(z), "i" 
end subroutine print_complex

我们在其中添加了包装器函数(在同一文件的末尾):

subroutine print_complex_wrapper(z_real, z_imag) bind(c, name="print_complex_wrapper")
  use iso_c_binding, only: c_double, c_double_complex
  implicit none
  real(c_double), intent(in) :: z_real, z_imag
  complex(c_double_complex) :: z
  z = cmplx(z_real, z_imag)
  call print_complex(z)
end subroutine print_complex_wrapper

然后按常规方法编译到库中:

gfortran -shared -fPIC -o my_complex_f90.so my_complex.f90

并从Python调用(注意指针的用法):

from ctypes import CDLL, c_double, POINTER
f90 = CDLL('./my_complex_f90.so')
f90.print_complex_wrapper.argtypes = [POINTER(c_double), POINTER(c_double)]
z = complex(1.0 + 1j * 2.0)
f90.print_complex_wrapper(c_double(z.real), c_double(z.imag))

如果c_complex是一个c结构,并且您在文档或头文件中有的定义,则可以利用ctypes来组合兼容的类型。也有可能,尽管可能性不大,但c\u complex是ctypes已经支持的类型的typdef。在

需要更多的信息来提供更好的答案。。。在

使用两次c趶double或c_float,一次用于实数,一次用于假想。 例如:

from ctypes import c_double, c_int
dimType = c_int * 1
m = dimType(2)
n = dimType(10)
complexArrayType = (2 * c_double) * ( n * m ) 
complexArray = complexArrayType()

status = yourLib.libcall(m,n,complexArray)

在库端(fortran示例):

^{pr2}$

相关问题 更多 >