在 C++ 中获取指向复数向量的实部和虚部的指针
Posted
技术标签:
【中文标题】在 C++ 中获取指向复数向量的实部和虚部的指针【英文标题】:Getting pointers to the real and imaginary parts of a complex vector in C++ 【发布时间】:2014-06-15 12:56:18 【问题描述】:使用标准 C++ 复数和向量库,我定义了一个复数向量。现在,我想获得指向包含这个复数向量的实部和虚部的向量的指针(double *
类型)。以下解决方案有效,但由于内存使用量增加了一倍,因此不优雅且浪费;
using namespace std;
typedef complex<double> cmp;
.
.
int i,m=10;
vector<cmp> C(m);
//Do something to populate the vector C
vector<double> R(m), I(m);
for(i=0; i<m; i++)
R[i] = C[i].real();
I[i] = C[i].imag();
double * r = &R[0];
double * i = &I[0];
【问题讨论】:
为什么要指针? 如果你必须有一个双精度数组,你就无法避免加倍的内存使用,因为实部和虚部在内存中并不相邻。 没有安全的方法可以做到这一点。双原语封装在complex<double>
对象中。你试图在错误的范围内解决更高层次的问题。
@Jefffrey 我需要将指针传递给我无法控制的第 3 方代码。
【参考方案1】:
根据 C++ 标准
If z is an lvalue expression of type cv std::complex<T> then:
— the expression reinterpret_cast<cv T(&)[2]>(z) shall be well-formed,
— reinterpret_cast<cv T(&)[2]>(z)[0] shall designate the real part of z, and
— reinterpret_cast<cv T(&)[2]>(z)[1] shall designate the imaginary part of z.
Moreover, if a is an expression of type cv std::complex<T>* and the expression a[i] is well-defined
for an integer expression i, then:
— reinterpret_cast<cv T*>(a)[2*i] shall designate the real part of a[i], and
— reinterpret_cast<cv T*>(a)[2*i + 1] shall designate the imaginary part of a[i].
所以你可以简单地写
using namespace std;
typedef complex<double> cmp;
.
.
int i,m=10;
vector<cmp> C(m);
//Do something to populate the vector C
double * r = &reinterpret_cast<double(&)[2]>( C[0] )[0];
double * i = &reinterpret_cast<double(&)[2]>( C[0] )[1];
这是一个例子
#include <iostream>
#include <complex>
#include <vector>
int main()
std::vector<std::complex<double>> v( 1, 1.1, 2.2 );
double * r = &reinterpret_cast<double(&)[2]>( v[0] )[0];
double * i = &reinterpret_cast<double(&)[2]>( v[0] )[1];
std::cout << *r << '\t' << *i << std::endl;
return 0;
输出是
1.1 2.2
【讨论】:
太好了,感谢@Vlad 提供有用的答案和示例代码:)。 这个答案是不正确的——至少对于具有多个元素的向量来说是这样。vector<complex>
对象的内存结构通常为[RIRIRIRIRI...]
,这意味着您无法获得指向实部或虚部的指针。我说通常,因为正式地说,这取决于编译器的实现。但实际上,内存通常是连续的。【参考方案2】:
(C++03) 标准没有定义 std::complex<double>
的内部结构如何,但通常它由 2 个双精度数组成,实部在虚部之前。因此,给定一个std::complex<double>
的数组(或std::vector
),您无法获得一个指向所有实部数组的指针,以及另一个指向所有虚部数组的指针:实部和虚部是交错的。如果您确实需要拆分它们,则必须复制所有元素(就像您已经这样做的那样)。
但是你为什么首先要把它们分开呢?将它们传递给某个库的一些例程?也许那个库也支持交错格式?在这种情况下,您可以使用reinterpret_cast<double*>(&C[0])
。请注意,这是非标准的,但它似乎在大多数情况下都有效。有关详细信息,请参阅广泛使用的 fftw-library 的 documentation,推荐使用此方法。
如果考虑性能,您应该从一开始就将实部和虚部分开,而不是先构造std::complex<double>
向量。
【讨论】:
感谢您的回答并提醒我注意 fftw 库中的相同问题。可以想象,我需要进行这种拆分,因为某些第三方库(阅读:Matlab)希望将它们的复杂数据放在单独的真实和虚构容器中。 @UdX 我认为您误读了我的回答。 fftw 库需要 interleaved 格式。并且因为 std::complexr
指向 1,3,5,.. 和 i
指向 2,4,6,.. 但由于这些是 double *
类型,对它们的迭代应该按以下步骤完成1,而不是 2。然而,在 @Vlad 的回答中,迭代 r
和 i
似乎有效。 :-?
不,从弗拉德的回答中取 r
和 i
,你有以下内容:r[0]
给出第一个数字的实部,r[1]
给出 虚数 第一个数字的一部分,r[2]
给出第二个数字的实部,r[3]
给出第三个数字的虚部。等等。对于i
:i[0]
给出第一个数字的虚部,i[1]
给出第二个数字的实部,i[2]
给出第二个数字的虚部。等等。因此,i
与 r
相比偏移了 1 个元素。弗拉德并没有真正回答你的问题。
谢谢@Gugi,我现在明白了。我的误解源于没有仔细检查 Vlad 的方法应用于大小 > 1 的向量。我现在已将正确答案更新为您的答案。以上是关于在 C++ 中获取指向复数向量的实部和虚部的指针的主要内容,如果未能解决你的问题,请参考以下文章
FFTW 和 OpenCV 的 C++ 接口,Mat 输出中的实部和虚部