Reputation: 463
I'm trying to create a set of classes in order to handle complex numbers. I've seen that there is already a set of classes for the complex numbers, but because I'm learning C++ I thought it was a good idea to create a basic implementation. The problem comes up when I tried to overload the operator "/". I got a segfault and I can't understand if the problem is my implementation of the division:
complex.hpp :
#include <iostream>
#include <cstdlib>
class Complex {
float real;
float imm;
public:
Complex(float new_real = 0,float new_imm = 0) {this->real = new_real;this->imm = new_imm;}
void set(float new_real,float new_imm) {this->real = new_real; this->imm = new_imm;}
float get_real(void) const { return this->real;}
float get_imm(void) const { return this->imm;}
Complex conj(void) const {Complex tmp; tmp.set(this->real,-1.0 * this->imm); return tmp;}
friend std::ostream& operator<<(std::ostream& os, const Complex& cpx) {os << "Real: " << cpx.real << " Imm: " << cpx.imm << std::endl; return os; }
friend Complex operator*(const Complex& lhs,const Complex& rhs);
friend Complex operator+(const Complex& lhs,const Complex& rhs);
friend Complex operator+(const Complex& lhs,const float& rhs);
};
complex.cpp:
#include "complex.hpp"
Complex operator*(const Complex& lhs,const Complex& rhs)
{
float real_part = (lhs.real * rhs.real) - ( lhs.imm * rhs.imm);
float imm_part = (lhs.real * rhs.imm) + ( lhs.imm * rhs.real);
Complex result;
result.set(real_part,imm_part);
return result;
}
Complex operator+(const Complex& lhs,const Complex& rhs)
{
float real_part = lhs.real + rhs.real;
float imm_part = lhs.imm + rhs.imm;
Complex result;
result.set(real_part,imm_part);
return result;
}
Complex operator+(const Complex& lhs,const float& rhs)
{
float real_part = lhs.real + rhs;
float imm_part = lhs.imm;
Complex result;
result.set(real_part,imm_part);
return result;
}
Complex operator/(const Complex& lhs,const Complex& rhs)
{
Complex numerator(0,0);
numerator = rhs * rhs.conj();
Complex denominator(0,0);
denominator = lhs * rhs.conj();
Complex result;
float real_numerator = numerator.get_real();
result = denominator / real_numerator;
return result;
}
Complex operator/(const Complex& lhs,const float& rhs)
{
float real_part = lhs.get_real() / rhs;
float imm_part = lhs.get_imm() / rhs;
Complex result;
result.set(real_part,imm_part);
return result;
}
The whole idea of the division between 2 complex is to multiply the numerator and denominator for the conjugate of the numerator in order to have only a real number on the numerator. Just to make it clear :
(a + ib) / (c + id) = ((a + ib) / (c + id)) * ((c - id) / (c - id)) = ((a + ib) * (c - id)) / (c^2 + d^2)
Now when I try to do this:
main.cpp :
int main(int argc, char *argv[])
{
Complex x(4,8);
Complex y(3,7);
Complex result = x / y;
result = x / 6;
return 0;
}
I got this segfault, which I don't understand:
(gdb) break main
Breakpoint 2 at 0x401c56: file equalization_main.cpp, line 49.
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
`/home/campiets/workspace/frontend/dfe_equalizer_fe/dev/view/src_c/test' has changed; re-reading symbols.
Starting program: /home/campiets/workspace/frontend/dfe_equalizer_fe/dev/view/src_c/test
Breakpoint 2, main (argc=1, argv=0x7fffffffbf08) at equalization_main.cpp:49
49 Complex x(4,8);
(gdb) n
50 Complex y(3,7);
(gdb) n
51 Complex result = x / y;
(gdb) n
Program received signal SIGSEGV, Segmentation fault.
0x0000000000401e64 in Complex::Complex (this=<error reading variable: Cannot access memory at address 0x7fffff3feff8>, new_real=<error reading variable: Cannot access memory at address 0x7fffff3feff4>,
new_imm=<error reading variable: Cannot access memory at address 0x7fffff3feff0>) at complex.hpp:38
38 Complex(float new_real = 0,float new_imm = 0) {this->real = new_real; this->imm = new_imm;}
Any ideas ?
Upvotes: 3
Views: 303
Reputation: 6125
Complex operator/(const Complex& lhs,const Complex& rhs)
{
...
Complex denominator...;
...
float real_numerator = ...;
result = denominator / real_numerator;
...
}
That's infinite recursion.
Since the compiler hasn't seen operator/(const Complex &lhs, const float &rhs)
, it converts the float
argument to Complex
and hence you get recursion.
The simplest solution is to declare or define operator/(const Complex &lhs, const float &rhs)
before operator/(const Complex &lhs, const Complex &rhs)
.
My preference would be to implement the operators as class members, though. That yields simpler source code and solves the problem too.
Upvotes: 5
Reputation: 206707
The function
Complex operator/(const Complex& lhs,const Complex& rhs) { ... }
causes stack overflow since the line
result = denominator / real_numerator;
ends up being interpreted as:
result = denominator / Complex(real_numerator);
You can resolve that problem by defining or declaring
Complex operator/(const Complex& lhs, const float& rhs)
before it.
If you change your code to use:
Complex operator/(const Complex& lhs,const float& rhs)
{
return Complex(lhs.get_real()/rhs, lhs.get_imm()/rhs);
}
Complex operator/(const Complex& lhs,const Complex& rhs)
{
...
}
your program will work ok.
A suggestion for simplifying the above operator/
function.
If you add the following member function
float magnitude_square() const { return (real*real + imm*imm); }
then you can use
Complex operator/(const Complex& lhs,const Complex& rhs)
{
return (lhs * rhs.conj())/rhs.magnitude_square());
}
Upvotes: 3