Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting pointers to the real and imaginary parts of a complex vector in C++

Using the standard C++ complex number and vector libraries, I define a vector of complex numbers. Now, I would like to get pointers (of the type double *) to the vectors that contain the real and imaginary parts of this complex vector. The following solution works, but is inelegant and wasteful as the memory usage is doubled;

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];
like image 620
xadu Avatar asked Jun 15 '14 12:06

xadu


2 Answers

According to the C++ Standard

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].

So you can write simply

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];

Here is an example

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

The output is

1.1 2.2
like image 112
Vlad from Moscow Avatar answered Sep 18 '22 02:09

Vlad from Moscow


The (C++03) standard does not define how the internals of a std::complex<double> look, but usually it consists of 2 doubles, with the real part coming before the imaginary part. Therefore, given an array (or std::vector) of std::complex<double>, you cannot get a pointer to an array of all real parts, and another pointer to an array of all imaginary parts: Real and imaginary parts are interleaved. If you really need to split them up, you cannot do it without copying all elements (as you already do).

But why do you want to split them up in the first place? To pass them on to some routines of some library? Maybe that library supports the interleaved format, too? In that case you could do a reinterpret_cast<double*>(&C[0]). Note, that this is non-standard, but it seems to work in most cases. For more information, see the documentation of the widely used fftw-library, where this approach is recommended.

If performance is a concern, you should split up the real and imaginary parts right from the beginning, without constructing a std::complex<double> vector first.

like image 28
Sedenion Avatar answered Sep 20 '22 02:09

Sedenion