Passage of the Difficult real and imaginary
Problem: C ++ 11 has made some changes to complex numbers so that real()
both imag()
can no longer be used or abused like member variables. I have some code that I convert that transmits real()
and imag()
in sincosf()
the link. It looks something like this:
sincosf(/*...*/, &cplx.real(), &cplx.imag());
Now it gives error: lvalue required as unary '&' operand
what error was not received until c ++ 11.
My question is: Is there a lightweight inline fix? or do I need to create temporary variables to get the result and then pass them to a complex number via setters?
thank
source to share
As TC mentions in the comments, the standard allows you reinterpret_cast
std::complex
to your heart's content.
From N3337, §26.4 / 4 [complex.numbers]
If
z
is an lvalue expression of type cvstd::complex<T>
, then:
- the expressionreinterpret_cast<cv T(&)[2]>(z)
must be well formed,
-reinterpret_cast<cv T(&)[2]>(z)[0]
must denote the real part,z
and
-reinterpret_cast<cv T(&)[2]>(z)[1]
denotes the imaginary partz
.
Moreover, if ita
is an expression of type cvstd::complex<T>*
, and the expression isa[i]
well defined for an integer expressioni
, then:
-reinterpret_cast<cv T*>(a)[2*i]
must denote real parta[i]
and
-reinterpret_cast<cv T*>(a)[2*i + 1]
must denote imaginary parta[i]
.
So, do the following replacement in your code
sincosf(/*...*/,
&reinterpret_cast<T*>(&cplx)[0],
&reinterpret_cast<T*>(&cplx)[1]);
source to share
Don't argue that time series is still a good option and should be as efficient as what you've done before, given a good optimizing compiler (say gcc -O3
).
See the final build from gcc -O3
here: https://goo.gl/uCPAa9
Using this code:
#include<complex>
std::complex<float> scf1(float x) {
float r = 0., i = 0.;
sincosf(x, &r, &i);
return std::complex<float>(r, i);
}
void scf2(std::complex<float>& cmp, float x) {
float r = 0., i = 0.;
sincosf(x, &r, &i);
cmp.real(r);
cmp.imag(i);
}
void scf3(std::complex<float>& cmp, float x) {
float r = 0., i = 0.;
sincosf(x, &cmp.real(), &cmp.imag());
}
Where is scf2
equivalent to your statement, you can see a very similar assembly in three cases.
scf1(float):
subq $24, %rsp
leaq 8(%rsp), %rsi
leaq 12(%rsp), %rdi
call sincosf
movss 12(%rsp), %xmm0
movss %xmm0, (%rsp)
movss 8(%rsp), %xmm0
movss %xmm0, 4(%rsp)
movq (%rsp), %xmm0
addq $24, %rsp
ret
scf2(std::complex<float>&, float):
pushq %rbx
movq %rdi, %rbx
subq $16, %rsp
leaq 8(%rsp), %rsi
leaq 12(%rsp), %rdi
call sincosf
movss 12(%rsp), %xmm0
movss %xmm0, (%rbx)
movss 8(%rsp), %xmm0
movss %xmm0, 4(%rbx)
addq $16, %rsp
popq %rbx
ret
scf3(std::complex<float>&, float):
pushq %rbx
movq %rdi, %rbx
subq $16, %rsp
leaq 8(%rsp), %rsi
leaq 12(%rsp), %rdi
call sincosf
movss 12(%rsp), %xmm0
movss %xmm0, (%rbx)
movss 8(%rsp), %xmm0
movss %xmm0, 4(%rbx)
addq $16, %rsp
popq %rbx
ret
source to share