1

I have a template class for complex number. I made there some working operator like: <<, ==, =, /,,+,-,+=,-+,=.

I have a problem with /=. I tried to write the method. But the code is not working well. The method returns wrong value.

Can you have a look at my code and look why my method /= is not working?

This is the method /=:

   //OPERATOR /=
    template<class T>
    Zespolona<T> Zespolona<T>::operator /=(const Zespolona<T>& obj) 
    {
        Zespolona<T> temp;
        temp.reNum = ((reNum * obj.reNum) + (imNum * obj.imNum)) / ((pow(obj.reNum, 2.0)) + (pow(obj.imNum, 2.0)));
        temp.imNum = ((obj.reNum * imNum) - (reNum * obj.imNum)) / ((pow(obj.reNum, 2.0)) + (pow(obj.imNum, 2.0)));
        return temp;
    }

Rest of the code:

 #include <iostream>

using namespace std;

template <class T>
class Zespolona {
private:
    //Zmienne prywatne
    T reNum;
    T imNum;
public:
    //Deklaracja konstruktorów
    Zespolona();
    Zespolona(T re);
    Zespolona(T re, T im);

    //Deklaracja operatorów
    Zespolona<T> operator+(const Zespolona<T>&)const;
    Zespolona<T> operator-(const Zespolona<T>&)const;
    Zespolona<T> operator*(const Zespolona<T>&)const;
    Zespolona<T> operator/(const Zespolona<T>&)const;
    Zespolona<T> operator+=(const Zespolona<T>&);
    Zespolona<T> operator-=(const Zespolona<T>&);
    Zespolona<T> operator*=(const Zespolona<T>&);
    Zespolona<T> operator/=(const Zespolona<T>&);
    Zespolona<T> operator=(const Zespolona<T>&);
    bool operator==(const Zespolona&) const;
    template <class U>
    friend ostream& operator<<(ostream&, const Zespolona<U>&);


};

//Konstruktor bez argumetów
template<class T>
Zespolona<T>::Zespolona()
{
    reNum = 0.0;
    imNum = 0.0;
}
//Konstruktor z jednym argumentem
template<class T>
Zespolona<T>::Zespolona(const T re)
{
    reNum = re;
    imNum = 0.0;
}


//Konstruktor z dwoma argumentami
template<class T>
Zespolona<T>::Zespolona(const T re, const T im)
{
    reNum = re;
    imNum = im;
}

//DODAWANIE
template<class T>
Zespolona<T> Zespolona<T>::operator +(const Zespolona<T>& obj) const
{
    Zespolona<T> temp;
    temp.reNum = reNum + obj.reNum;
    temp.imNum = imNum + obj.imNum;
    return temp;
}
//ODEJMOWANIE
template<class T>
Zespolona<T> Zespolona<T>::operator -(const Zespolona<T>& obj) const
{
    Zespolona<T> temp;
    temp.reNum = reNum - obj.reNum;
    temp.imNum = imNum - obj.imNum;
    return temp;
}
//MNOZENIE
template<class T>
Zespolona<T> Zespolona<T>::operator *(const Zespolona<T>& obj) const
{
    Zespolona<T> temp;
    temp.reNum = (reNum * obj.reNum) - (imNum * obj.imNum);
    temp.imNum = (reNum * obj.imNum) + (imNum * obj.reNum);
    return temp;
}
//DZIELENIE
template<class T>
Zespolona<T> Zespolona<T>::operator /(const Zespolona<T>& obj) const
{
    Zespolona<T> temp;
    temp.reNum = ((reNum * obj.reNum) + (imNum * obj.imNum)) / ((pow(obj.reNum, 2.0)) + (pow(obj.imNum, 2.0)));
    temp.imNum = ((obj.reNum * imNum) - (reNum * obj.imNum)) / ((pow(obj.reNum, 2.0)) + (pow(obj.imNum, 2.0)));
    return temp;
}
//OPERATOR PORÓWNANIA
template <class T>
bool Zespolona<T>::operator ==(const Zespolona& obj) const
{
    return (reNum == obj.reNum && imNum == obj.imNum);
}
//OPERATOR =
template <class T>
Zespolona<T> Zespolona<T>::operator=(const Zespolona& obj)
{
    if (this != &obj)
    {
        reNum = obj.reNum;
        imNum = obj.imNum;
    }

    return  *this;
}
//OPERATOR +=
template<class T>
Zespolona<T> Zespolona<T>::operator +=(const Zespolona<T>& obj)
{
    reNum += obj.reNum;
    imNum += obj.imNum;

    return *this;
}
//OPERATOR -=
template<class T>
Zespolona<T> Zespolona<T>::operator -=(const Zespolona<T>& obj)
{
    reNum -= obj.reNum;
    imNum -= obj.imNum;
    return *this;
}
//OPERATOR *=
template<class T>
Zespolona<T> Zespolona<T>::operator *=(const Zespolona<T>& obj)
{

    reNum = (reNum * obj.reNum) - (reNum * obj.imNum);
    imNum = (imNum * obj.reNum) + (imNum * obj.imNum);
    return *this;
}
//OPERATOR /=
template<class T>
Zespolona<T> Zespolona<T>::operator /=(const Zespolona<T>& obj) 
{
    Zespolona<T> temp;
    temp.reNum = ((reNum * obj.reNum) + (imNum * obj.imNum)) / ((pow(obj.reNum, 2.0)) + (pow(obj.imNum, 2.0)));
    temp.imNum = ((obj.reNum * imNum) - (reNum * obj.imNum)) / ((pow(obj.reNum, 2.0)) + (pow(obj.imNum, 2.0)));
    return temp;
}
//OPERATOR WEJSCIA
template<class T>
ostream& operator<<(ostream& out, const Zespolona<T>& zesp)
{
    out << zesp.reNum;
    out << "+";
    out << zesp.imNum;
    out << "i";
    return out;
}
//funkcja testująca
void test() {
    try {
        Zespolona<double> a(1.0, 2.1);
        Zespolona<double> b(0.8, 1.7);
        Zespolona<double> c;

        cout << a << " + " << b << " = " << a + b << endl;
        cout << a << " * " << b << " = " << a * b << endl;

        cout << a << " == " << b << " = " << (a == b) << endl;
        c = a;
        cout << a << " == " << c << " = " << (a == c) << endl;

        c = Zespolona<double>(1.0, 1.0);
    }
    catch (const char *e) {
        cout << "Exception: " << e << endl;
    }
    catch (const exception &e) {
        cout << "Exception: " << e.what() << endl;
    }
    catch (...) {
        cout << "Caught not expected exception" << endl;
    }

}
int main() {
    Zespolona<double> x(1.0, 1.0);
    Zespolona<double> z(0.5, 1.0);

    cout << x / z << endl;

    x /= z;
    cout << x << endl;




    //test();
    system("pause");
}
Headsman
  • 25
  • 5
  • 1
    `/=` should modify `this` (but indeed temporary might be needed to compute with old value). – Jarod42 Nov 21 '18 at 09:00
  • 2
    Possible duplicate of [What are the basic rules and idioms for operator overloading?](https://stackoverflow.com/questions/4421706/what-are-the-basic-rules-and-idioms-for-operator-overloading) – Dan M. Nov 21 '18 at 09:02
  • Unrelated: calculate power of `obj` only once, e.g. `p2 = obj * conj(obj)`, after implementing `conj(.)` – Damien Nov 21 '18 at 09:17
  • Unrelated: your constructors can be simplified to `Zespolona(T re = 0.0, T im = 0.0) : reNum(re), imNum(im) {}`, and the non-assignment arithmetic operators can be simplified as non-members that take the left hand side by value `Zespolona operator +(Zespolona left, const Zespolona & right){ return left += right; }` – Caleth Nov 21 '18 at 09:58
  • Also, your copy assignment operator is worse than what the default would be, just remove it. – Caleth Nov 21 '18 at 10:00

2 Answers2

5

You are calculating the correct result but you don't store it in the variable. Change your code to:

template<class T>
Zespolona<T>& Zespolona<T>::operator /=(const Zespolona<T>& obj) 
{
    *this = *this / obj;
    return *this;
}

You shouldn't implement logic like this at multiple places. After implementing a method or operator use it. Remember that a method works like a function with a pointer to the object

Zespolona<T> operator /=(Zespolona<T>* this, const Zespolona<T>& obj) 

If you call this method with

a /= b;

a pointer to a would be the first parameter and b is the second. The return value is not copied to a.

Alternatively you could change the call to

x = x /= z;

to fix it. Maybe this helps you to understand the problem.

EDIT: It would be better to implement the logic into operator/= and to use it in the implementation of operator/. That way you can implement the calculations in operator/= in place and avoid the copy.

Thomas Sablik
  • 16,127
  • 7
  • 34
  • 62
  • also conventionally you return a reference (`Zespolona &`) from an assignment operator – Caleth Nov 21 '18 at 09:44
  • 1
    isnt it better to implement `operator/` in terms of `operator/=` ? The way you do it `/=` cannot be done in place. Imho when the operation is not done in place sometimes it is even better to not provide compound assignment at all – 463035818_is_not_an_ai Nov 21 '18 at 09:46
2
  • First store the current value of this into a temp variable
  • Compute the division using temp and obj assign it to this
  • Return *this

>

template<class T>
Zespolona<T> Zespolona<T>::operator /=(const Zespolona<T>& obj) 
{
    Zespolona<T> temp = *this;
    this->reNum = ((temp.reNum  * obj.reNum) + (temp.imNum * obj.imNum)) / ((pow(obj.reNum, 2.0)) + (pow(obj.imNum, 2.0)));
    this->imNum = ((obj.reNum * temp.imNum) - (temp.reNum  * obj.imNum)) / ((pow(obj.reNum, 2.0)) + (pow(obj.imNum, 2.0)));
    return *this;
}
P.W
  • 26,289
  • 6
  • 39
  • 76