Using classes to work with Mathematical Numbers

Hi, I am a very inexperienced programmer and in need of some help. My goal for this program is to add, subtract, multiply and divide complex numbers. Complex numbers are basically binomials (4 +5i) where the real part is 4 and the imaginary part is 5. Two complex numbers ( (4+5i) + (6+7i) would add to be (10+12i) for example. Anyway, I am having trouble with my inputting and outputting. I will try to show only the things I needed to show. Thanks for any help that can be offered

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
  #include<iostream>;
#include<complex.h>;
#include<cmath>;
#include<cstdlib>;
using namespace std;
class complex
{
public:
	complex();
	complex(double real);
	complex(double real, double imaginary);
	double getReal() const;
	double getImaginary() const;

	friend const complex operator +(const complex& number1, const complex& number2);
	friend const complex operator -(const complex& number1, const complex& number2);
	friend complex operator *(const complex& number1, const complex& number2);
	friend complex operator /(const complex& number1, double divider);
	friend bool operator == (const complex& number1, const complex& number2);
	friend bool operator !=(const complex& number1, const complex& number2);
	friend istream& operator >> (istream& inputstream, complex newNumber);
	friend ostream& operator <<(ostream& outputstream, const complex& number);
private: 
	double real, imaginary;
	friend double real(const complex&);
	friend double imaginary(const complex&);
	const char i = 'i';
};
int main()
{

}
complex::complex() :real(0), imaginary(0){}
complex::complex(double real) :real(real){}
complex::complex(double real, double imaginary) :real(real), imaginary(imaginary){}
double complex::getReal()const
{
	return real;
}
double complex::getImaginary()const
{
	return imaginary;
}
ostream& operator <<(ostream& outputstream, const complex& number)
{
	outputstream << "( " << number.real << " + " << number.imaginary<< number.i << " ) " << endl;
	return outputstream;
}
istream& operator >> (istream& inputstream, complex& newNumber)
{
	double realInput, imaginaryInput;
	char startInput;
	char comma;
	char endInput;
	inputstream >> startInput;
	if ('(' != startInput)
	{
		cout << "Incorrect Complex Number format. Please insert a '(Real,Imaginary)' format" << endl;
		exit(1);
	}
	inputstream >> realInput;
	inputstream >> comma;
	if (comma != ',')
	{
		cout << "Please make sure to include the comma between the complex numbers." << endl;
		exit(1);
	}
	inputstream >> imaginaryInput;
	inputstream >> endInput;
	if (endInput != ')')
	{
		cout << "Please do not forget to close the parantheses." << endl;
		exit(1);
	}
	newNumber = complex(realInput, imaginaryInput);
	return inputstream;
}
double imaginary(const complex& number)
{
	return number.getImaginary();
}
double real(const complex& number)
{
	return number.getReal();
}
const complex operator +(const complex& number1, const complex& number2)
{
	return complex((number1.real + number2.real), (number1.imaginary + number2.imaginary));
}
const complex operator -(const complex& number1, const complex& number2)
{
	return complex((number1.real - number2.real), (number1.imaginary - number2.imaginary));
}


bool operator ==(const complex& number1, const complex& number2)
{
	return ((number1.real == number2.real) && (number1.imaginary == number2.imaginary));
}
Last edited on
Is this an assignment?
You have included the C complex header, perhaps because you don't know there's a C++ complex header?
There is a std::complex. See:
http://en.cppreference.com/w/cpp/numeric/complex

P.S.: imaginary and complex are macros defined in <complex.h> which expand to the C keywords _Imaginary and _Complex, respectively. I wouldn't recommend using them in this context.

You can undefine them if you want, but that is strongly discouraged, given that it's name is used in an interface, and your macro (un-)definitions would leak.
Last edited on
Yes this is an assignment. I'm actually under a time constraint right now. Do you recommend changing all my uses of imaginary to imag or something like that? My professor did tell me to include the complex.h. I'm sure it wouldn't matter if I used regular std::complex
std::complex<> is a fully-featured complex number class. You can get rid of your entire class and replace it with the standard one.

I'm not entirely sure that <complex> would be acceptable since this is an assignment -- that's why I asked. But you know better than I.
Last edited on
I think that would defeat the purpose of the assignment then. We are covering overloading operators and constructing our own classes and things of that nature (friends, const, bool). I have to build it from scratch
It doesnt need to be very complex, just be able to do those basic operators with a complex number template
Okay, well still -- the interface (or even the source code of) of std::complex could be a nice reference point.

There is a canonical way to overload operators. Traditionally, the mathematical operators are defined in terms of their compound-assignment equivalents. Specifically, operator+ gets defined in terms of operator+=, and so on.

You should probably be able to make them non-member functions -- non-members are good for encapsulation in general, and in the case you can't, you can make them friends.

This excellent FAQ on Stack Overflow goes describes the canonical way to overload operators.
http://stackoverflow.com/questions/4421706/operator-overloading
There's also this:
http://en.cppreference.com/w/cpp/language/operators#Canonical_implementations

I don't understand why you were instructed to include <complex.h>, unless you are supposed to implement your class in terms of the C complex type.
See the issue I had been having was in my cin overloaded operator. Specifically the problem was on line 75 of the newNumber = complex(realInput, imaginaryInput); and it said that the issue was that "function "complex::operator=(const complex &)" (declared implicitly) cannot be referenced -- it is a deleted function"
this was on the equal sign btw
What C++ standard revision are you using?
I had to make quite a few more changes to get your code to compile.

The default operator= (either the move-assignment operator or the copy-assignment operator, or the associated constructors) will do trivial assignment. They are defined as deleted because you have a const property. Make it static:

static constexpr char i {'i'};
Last edited on
Ok so I changed my char to static like you said. I tried running it and now it starts to compile, except it doesn't prompt me for input- it just immediately closes. What else do I have to do?
Well in the code you posted, your main function is empty :)
Here is everything I got. I don't know why the main got cut out. Its not storing the values. It came back with 0+0i.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include<iostream>;
#include<complex.h>;
#include<cmath>;
#include<cstdlib>;
using namespace std;
class complex
{
public:
	complex();
	complex(double real);
	complex(double real, double imaginary);
	double getReal() const;
	double getImaginary() const;

	friend const complex operator +(const complex& number1, const complex& number2);
	friend const complex operator -(const complex& number1, const complex& number2);
	friend complex operator *(const complex& number1, const complex& number2);
	friend complex operator /(const complex& number1, double divider);
	friend bool operator == (const complex& number1, const complex& number2);
	friend bool operator !=(const complex& number1, const complex& number2);
	friend istream& operator >> (istream& inputstream, complex newNumber);
	friend ostream& operator <<(ostream& outputstream, const complex& number);
private:
	double real, imaginary;
	friend double real(const complex&);
	friend double imaginary(const complex&);
	static constexpr char i = { 'i' };
};
int main()
{

}
complex::complex() :real(0), imaginary(0) {}
complex::complex(double real) : real(real) {}
complex::complex(double real, double imaginary) : real(real), imaginary(imaginary) {}
double complex::getReal()const
{
	return real;
}
double complex::getImaginary()const
{
	return imaginary;
}
ostream& operator <<(ostream& outputstream, const complex& number)
{
	outputstream << "( " << number.real << " + " << number.imaginary << number.i << " ) " << endl;
	return outputstream;
}
istream& operator >> (istream& inputstream, complex newNumber)
{
	double realInput, imaginaryInput;
	char startInput;
	char comma;
	char endInput;
	inputstream >> startInput;
	if ('(' != startInput)
	{
		cout << "Incorrect Complex Number format. Please insert a '(Real,Imaginary)' format" << endl;
		exit(1);
	}
	inputstream >> realInput;
	inputstream >> comma;
	if (comma != ',')
	{
		cout << "Please make sure to include the comma between the complex numbers." << endl;
		exit(1);
	}
	inputstream >> imaginaryInput;
	inputstream >> endInput;
	if (endInput != ')')
	{
		cout << "Please do not forget to close the parantheses." << endl;
		exit(1);
	}
	newNumber = complex(realInput, imaginaryInput);
	return inputstream;
}
double imaginary(const complex& number)
{
	return number.getImaginary();
}
double real(const complex& number)
{
	return number.getReal();
}
const complex operator +(const complex& number1, const complex& number2)
{
	return complex((number1.real + number2.real), (number1.imaginary + number2.imaginary));
}
const complex operator -(const complex& number1, const complex& number2)
{
	return complex((number1.real - number2.real), (number1.imaginary - number2.imaginary));
}
complex operator *(const complex& number1, const complex& number2)
{
	return complex((number1.real*number2.real), (number1.imaginary*number2.imaginary));
}
complex operator /(const complex& number1, double divider)
{
	return complex((number1.real / divider), (number1.imaginary / divider));
}
bool operator ==(const complex& number1, const complex& number2)
{
	return ((number1.real == number2.real) && (number1.imaginary == number2.imaginary));
}
bool operator !=(const complex& number1, const complex& number2)
{
	return ((number1.real != number2.real) || (number1.imaginary != number2.imaginary));
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int main()
{
	complex x, y;
	cout << "Please enter a complex number with the format (Real,Imaginary): ";
	cin >> x;
	cout << "Great. Please enter another complex number: ";
	cin >> y;
	cout << "Now we will manipulate the data." << endl;
	cout << "First we will begin by adding these two complex numbers." << endl;
	complex z = x + y;
	cout << z;
	cout << "Now we will subtract the two complex numbers." << endl;
	complex a = x - y;
	cout << a;
	cout << "Now we will multiply these two complex numbers together." << endl;
	complex b = x*y;
	cout << b;
	int divider;
	cout << "Finally we will devide the first complex number by a divider. Please enter a divider." << endl;
	cin >> divider;
	complex c = x / divider;
	cout << c;
	cout << "Thank you." << endl;
	system("pause");
	return 0;
}
Again sorry, I dont know why it kept cutting out the main.
You really should rename your class. Just going from complex to Complex, imaginary to imag should be fine.

I just spent a few minutes rewriting your code, so I don't know precisely what's going wrong (perhaps argument dependent-lookup wrt. std::complex, or another bug -- you're not checking your input stream's state), but here's a version that works more or less:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# include <stdexcept>
# include <cerrno>
# include <cstring>
# include <cassert>
# include <iostream>

// 'using namespace' is strongly discouraged, especially for beginners.  On some
// implementations (like mine) your code will not compile with this declaration;
// there are name collisions with objects in the standard namespace.
//
// In the worst case, the behaviour of your program will simply change, silently.
// Bugs like that are _very_ hard to diagnose when unexpected.
// using namespace std;

struct Complex;
constexpr Complex operator*(Complex const& lhs, Complex const& rhs) noexcept;
constexpr Complex operator/(Complex const& lhs, Complex const& rhs) noexcept;

struct Complex {
  constexpr Complex(double const real = 0.0, double const imag = 0.0) noexcept
    : real{real} , imag{imag} {};

  // Prefer in-class initializers to member initializers in constructors for
  // constant initializers
  // No need to make these private.
  double real{}, imag{};

  // operator overloads
  constexpr Complex& operator+=(Complex const& that) noexcept {
    this->real += that.real; this->imag += that.imag;
    return *this;
  }
  constexpr Complex& operator-=(Complex const& that) noexcept {
    this->real -= that.real; this->imag -= that.imag;
    return *this;
  }
  // breaking convention here by implementing *=, /= in terms of *, /: a copy is
  // required no matter what.
  constexpr Complex& operator*=(Complex const& that) noexcept
  { return *this = *this * that; }
  constexpr Complex& operator/=(Complex const& that) noexcept
  { return *this = *this / that; }
};
constexpr Complex operator-(Complex lhs, Complex const& rhs) noexcept
{ return lhs -= rhs; }
constexpr Complex operator+(Complex lhs, Complex const& rhs) noexcept
{ return lhs += rhs; }
constexpr Complex operator*(Complex const& lhs, Complex const& rhs) noexcept {
  // (a + bi)(c + di) = (ac - bd) + (ad + bc)i
  return {(lhs.real * rhs.real) - (lhs.imag * rhs.imag),
          (lhs.real * rhs.imag) + (lhs.imag * rhs.real)};
}
constexpr Complex operator/(Complex const& lhs, Complex const& rhs) noexcept {
  // (a + bi)/(c + di) = ((ac + bd) + (bc - ad)i)/(c*c + d*d)
  auto const denom = (rhs.real * rhs.real) + (rhs.imag * rhs.imag);
  return {((lhs.real * rhs.real) + (lhs.imag * rhs.imag)) / denom,
          ((lhs.imag * rhs.real) - (lhs.real * rhs.imag)) / denom};
}

std::ostream& operator<<(std::ostream& stream, Complex const& n)
{ return stream << "(" << n.real << ", " << n.imag << ")"; }
std::istream& operator>>(std::istream& stream, Complex& num) {
  // Don't call std::exit().  It does not invoke destructors of objects with
  // automatic storage duration.  This is almost never what you want.  Instead,
  // throw an exception, or in this case, set the stream's error state.
  char format[3];
  stream >> std::ws >> format[0] >> std::ws
         >> num.real >> std::ws >> format[1] >> num.imag
         >> std::ws >> format[2];
  if (format[0] != '(' || format[1] != ',' || format[2] != ')')
    stream.setstate(std::ios::failbit);
  return stream;
}

namespace {
  template <typename CharT, typename Traits>
  void check_stream(std::basic_istream<CharT, Traits> const& s) {
    if (! s) {
      std::cerr << "stream error " << std::strerror(errno) << "\n";
      throw (std::runtime_error("stream error"));
    }
  }
}

int main() {
  std::cout << "Please enter two complex numbers in the format (real, imaginary):\n";
  Complex x, y;
  check_stream(std::cin >> x >> y);

    // works with scalars, too
  std::cout << (x + y) << " = " << x << " + " << y << "\n"
            << (x - y) << " = " << x << " - " << y << "\n"
            << (x * y) << " = " << x << " * " << y << "\n"
            << (x / y) << " = " << x << " / " << y << "\n";
  std::cout << "Thank you\n";
}

http://coliru.stacked-crooked.com/a/6d0e451a97c08ba3
Last edited on
Oh -- the problem is on line 49. Your overload for operator>> needs to accept the complex number by reference.

You're changing only a copy of the complex object:
istream& operator >> (istream& inputstream, complex& newNumber)
Last edited on
Topic archived. No new replies allowed.