/*
Autor: Łukasz Romanowski

Biblioteka standarodowa: <complex>

Opis: Klasa szablonowa complex służy do reprezentacji i manipulacji liczbami zespolonymi.
Operacje zdefiniowane na liczbach zespolonych pozwalają na swobodne mieszanie obiektów tej
klasy z wbudowanymi typami numerycznymi. Należy zauważyć, że większość operacji wykonywanych
na obiektach tej klasy to zwykłe funkcje. Wyjątkami są metody real() i imag() należące do klasy complex. 
*/

#include <iostream>
#include <complex>
#include <utility>

using namespace std;

typedef complex<double> Complex;

// deklaracja funkcji obliczajacej pierwiastki kwadratowe równania o współczynnikach zespolonych
// implementacja poniżej 
pair<Complex, Complex> roots (Complex a, Complex b, Complex c);

int main() {
	// deklaracje wykorzystujące rózne konstruktory dostępne w bibliotece standardowej
   complex<double> cplx_one;               // wartość 0 + 0i
   complex<double> cplx_two(3.14);         // wartość 3.14 + 0i
   complex<double> cplx_three(1.5, 3.14);   // wartość 1.5 + 3.14i
   complex<double> cplx_four(cplx_two);    // wartość również 3.14 + 0i

	cout << "cplx_one:   " << cplx_one << endl;
	cout << "cplx_two:   " << cplx_two << endl;
	cout << "cplx_three: " << cplx_three << endl;
	cout << "cplx_four:  " << cplx_four << endl;
   
   // wykorzystanie operatora przypisania oraz konwersji za pomocą konstruktora jednoargumentowego
   cplx_one = cplx_three;                 // staje się 1.5 + 3.14i
   cplx_three = 2.17;                     // staje się 2.17 + 0i

	cout << "cplx_one:   " << cplx_one << endl;
	cout << "cplx_three: " << cplx_three << endl;
   
   // wykorzystanie funkcji polar() do konstrukcji liczby zespolonej na podstawie modułu i kąta fazowego
   cplx_four = polar(5.6, 1.8);
   
	cout << "cplx_four:  " << cplx_four << endl;
	
	// wartosc sprzężoną otrzymujemy za pomocą funkcji conj()
	complex<double> cplx_five = conj(cplx_four);
	
	cout << "cplx_five:  " << cplx_five << endl;
	
	// aby otrzymać wartości części rzeczywistej i urojonej korzystamy z funkcji real() i imag()
   cout << cplx_one.real() << "+" << cplx_one.imag() << "i" << endl;
   cout << real(cplx_one)  << "+" << imag(cplx_one)  << "i" << endl;   
   
   // operatory można wykorzystywać zgodnie z przyjętą konwencją
   cout << cplx_one + cplx_two << endl;            // wartość (4.64,3.14)
   cout << cplx_one - 3.14 << endl;                // wartość (-1.64,3.14)
   cout << 2.75 * cplx_two << endl;                // wartość (8.635,0)
   cout << (cplx_one += cplx_three / 2.0) << endl; // wartość (2.585,3.14)
   
   // dostepne są również operatory jednoargumentowe + i -
   cout << -cplx_one << endl;                      // wartość (-2.585,-3.14)
   
   // do porównania wartości dwóch liczb zespolonych używamy operatorów == i !=,
   // pozostałe operatory porównujące są niedostępne
   cout << (cplx_one == cplx_three) << endl;  // wartość 0 (fałsz)
   cout << (cplx_one != cplx_three) << endl;  // wartość 1 (prawda)
   
   // wartości normalna i moduł dostępne są za pomocą funkcji norm() i abs()
   cout << norm(cplx_two) << endl;
   cout << abs(cplx_two)  << endl;
   
   // kąt fazowy można uzyskać za pomocą funkcji funkcji arg()
   cout << cplx_four << " w postaci biegunowej wynosi "
        << abs(cplx_four) << "e^" << arg(cplx_four) << "i"<< endl;
   
   /*
   przykład wykorzystania klasy complex<> do obliczenia pierwiastków równania danego wzorem:
      (2,1)*x^2 + (0,1)*x + (5,0) = 0;
   W celu przetestowania działania funkcji należy zmieniać wartości a, b i c dane poniżej
   */
   
   Complex a(2,1);
   Complex b(0,1);
   Complex c(5,0);
   
   pair<Complex,Complex> res(roots(a,b,c));
   
   cout << "Wyniki przykładowej funkcji roots() obliczającej pierwiastki równania" << endl
        << a << "*x^2 + " << b << "*x + " << c << " = 0" << endl;
   cout << "  x1= " << res.first << endl;
   cout << "  x2= " << res.second << endl;
   
}

// definicja funkcji obliczajacej pierwiastki kwadratowe równania o współczynnikach zespolonych
pair<Complex, Complex> roots (Complex a, Complex b, Complex c)
{
   Complex root = sqrt(b * b - 4.0 * a * c);
   a *= 2.0;
   return make_pair(
      (-b + root)/a, 
      (-b - root)/a
   );
}

