Cory
Cory

Reputation: 161

Passing Complex real and imag by reference

The Problem: C++11 has made some changes to complex numbers so that real() and imag() can no longer be used and abused like member variables. I have some code that I am converting over that passes real() and imag() to sincosf() by reference. It looks a little like this:

sincosf(/*...*/, &cplx.real(), &cplx.imag());

This now gives a error: lvalue required as unary '&' operand

which error was not received prior to c++11.

My Question: Is there an easy inline fix? or do I have to create temporary variables to get the result and then pass those to the complex number via setters?

Thanks

Upvotes: 3

Views: 734

Answers (3)

yuri kilochek
yuri kilochek

Reputation: 13486

Just do

cplx = std::polar(1.0f, /*...*/);

Upvotes: 2

EyasSH
EyasSH

Reputation: 3769

Do not that declaring temporaries still is a good option and should be just as efficient as what you are previously doing, given a good optimizing compiler (say, gcc -O3).

See the resulting assembly 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 scf2 is equivalent to your statement, you can see very similar assembly in the 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

Upvotes: 0

Praetorian
Praetorian

Reputation: 109119

As T.C. mentions in the comments, the standard allows you to reinterpret_cast std::complex to your heart's content.

From N3337, §26.4/4 [complex.numbers]

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 make the following replacement in your code

sincosf(/*...*/, 
        &reinterpret_cast<T*>(&cplx)[0], 
        &reinterpret_cast<T*>(&cplx)[1]);

Upvotes: 3

Related Questions