Reputation: 16605
I would like to be able to convert between std::complex and float 's with minimal overhead in copying of data. (None at all if possible.)
I have a class which contains samples of data. On one side of the class, there is a program which reads and writes data in the form of std::complex. The data is either all real-valued, or all imaginary, and hence the input is a (float*). Inside the class there is a function which carries out processing, such as fourier transform processing, which takes arguments of float*. (Pointer to floats.) The data inside the class is stored in a std::vector.
Hence the description is;
std::vector<std::complex<float>>
;
The reason for this choice is that the output is not always either real or imaginary. And it would be advantageous to access data using vector.at(index).real() or vector.at(index).imag(), as this makes coding other functions, such as a function to compute the average power, much easier. (The alternative is to use indices to dereference a pointer. Usually, I would not have any problem with this method, however many other SO programmers will tell you that it is an awful method because you have to be able to multiply by 2 and add up... In this case, it becomes more difficult to be sure you have got the algorithm correct, as there is a change in the way in which the data is stored[1], hence why I agree with the SO consensus in this case.)
[1]: The input data is a (float*) to all real values. 2 blocks of input values are interleaved into an array twice the size: real0 = data0[0], imag0 = data1[0], real1 = data0[1], imag1 = data1[1], ... etc ...
This is then stored as: { complex(real0, imag0) , complex(real1, imag1) , ... etc ... }
But then processed using an FFT which takes a float*, and uses indices rather than complex.real() and complex.imag().
Then another set of functions compute values using complex.real() and complex.imag() rather than just indices.
Results are then returned back in both the forms above: Using std::vector>& (reference to) and float*...
Clearly this method of changing the way in which data is stored is idiotic. It should be 1 way or another, not many different ways.
Unfortunately, I didn't write most of this code and so I can't edit it... Solution 2 it is then...
It would be possible to return a pointer to the data inside the vector class. For this to work, I am assuming that:
The std::complex class stores real and imaginary values in that order
If this is not true, the following will not work:
// Function inside my_class which returns access to real components
float* getReal(int& stride, int& length)
{
stride = 2;
return &my_vector.at(0); // Think this is the same as my_vector.data()?
}
// This is then used in the following way to set all real values to 0.0
void Reset()
{
int stride, length;
float* data_p = my_class.getReal(stride, length);
float* data_p_last_value = data_p + length - 1;
for(; data_p <= data_p_last_value; ++ data_p)
{
(*data_p) = 0.0;
}
}
But this is kind of not very nice. Is there an alternative, more "sleek" or intuitive, method?
Upvotes: 1
Views: 3434
Reputation: 137320
std::complex
is a very special class, specified for interoperability with complex number types in other languages, including C. The standard guarantees that (§26.4 [complex.numbers]/p2, 4):
The specializations
complex<float>
,complex<double>
, andcomplex<long double>
are literal types (3.9).[...]
If
z
is an lvalue expression of typecv 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, andreinterpret_cast<cv T(&)[2]>(z)[1]
shall designate the imaginary part of z.Moreover, if
a
is an expression of typecv std::complex<T>*
and the expressiona[i]
is well-defined for an integer expressioni
, then:
reinterpret_cast<cv T*>(a)[2*i]
shall designate the real part ofa[i]
, andreinterpret_cast<cv T*>(a)[2*i + 1]
shall designate the imaginary part ofa[i]
.
So the approach in your suggested solution 2 is safe modulo bugs (for instance, you are using length
in Reset()
uninitialized, and your algorithm seems to be zeroing everything and not just the real parts).
Upvotes: 9