/*  *   *   *   *   *   *   *   *   *
 *  Zad. 3                          *
 *  Obliczyć sumę szeregu:          *
 *      m                           *
 *      E   z^n,                    *
 *     n=0                          *
 *  gdy z jest liczbą zespoloną.    *
 *  *   *   *   *   *   *   *   *   */

#include <stdio.h>

///////////////////////////////////////////////////
/// struktura przedstawiająca liczby zespolone  ///
///////////////////////////////////////////////////
typedef struct Zespolona                            //  typedef oznacza, że zdefiniujemy alias do struktury
{
    double Re;                                      //  część rzeczywista
    double Im;                                      //  część urojona
} Zespolona;                                        //  alias do struktury Zespolona to Zespolona

//////////////////////////////////////////////////////
/// deklaracje funkcji do operacji na strukturze   ///
//////////////////////////////////////////////////////
Zespolona utworz1();                                //  utworzymy zespoloną z klawiatury         
Zespolona utworz2(double, double);                  //  utworzymy zespoloną z argumentów
Zespolona potega(const Zespolona, int);             //  potęga zespolonej
Zespolona dodaj(const Zespolona, const Zespolona);  //  suma dwóch zespolonych
void pokaz(const Zespolona);                        //  pokaz zespolonej

///////////////////////////////////////////////////
/// definicje funkcji do operacji na strukturze ///
///////////////////////////////////////////////////
Zespolona utworz()
{
    Zespolona Z;                                    //  tworzymy lokalną strukturę Z
    
    printf("Podaj Re: ");                           //  wczytujemy dane do pól struktury
    scanf("%lf", &Z.Re);
    
    printf("Podaj Im: ");
    scanf("%lf", &Z.Im);
    
    return Z;                                       //  zwracamy strukturę
}

Zespolona utworz2(double re, double im)
{
    Zespolona Z;
    
    Z.Re = re;                                      //  przypisujemy wartości polom struktury
    Z.Im = im;
    
    return Z;
}

Zespolona potega(const Zespolona Z1, int i)         //  argumentami jest stała struktura i jej potęga
{                                                   //  const oznacza, że nie możemy w tej funkcji zmienić wartości
    Zespolona Z;                                    //  struktury Z1, tekie zabezpieczenie przed utratą danych
    
    if (i == 0)                                     //  (a + bi)^0 = 1 + 0i
    {
        Z.Re = 1;
        Z.Im = 0;
    }
    else
    {
        Z.Re = Z1.Re;                               //  (a + bi)^1 = a + bi
        Z.Im = Z1.Im;
        
        ///////////////////////////////////////////////
        /// (a + bi)(c + di) = ac - bd + adi + bci  ///
        ///                                         ///
        /// (1 + i)(1 + i) = 1 + i + i - 1 = 0 + 2i ///
        ///////////////////////////////////////////////
        int j;
        for (j = 1; j < i; j++)                     //  pętla od 1 bo powyżej policzyliśmy potęgę 1
        {
            Z = utworz2(Z.Re*Z1.Re - Z.Im*Z1.Im, Z.Re*Z1.Im + Z.Im*Z1.Re);
        }
    }
    
    return Z;
}

Zespolona dodaj(const Zespolona Z1, const Zespolona Z2) //  argumentami są dwie stałe struktury
{
    Zespolona Z;
    
    Z.Re = Z1.Re + Z2.Re;                           //  przypisanie polom struktury lokalnej sumy składowych dwóch
    Z.Im = Z1.Im + Z2.Im;                           //  liczb zespolonych
    
    return Z;
}

void pokaz(const Zespolona Z)
{
    printf("%.4lf + %.4lfi\n", Z.Re, Z.Im);         //  wypisanie na ekran zespolonej
}

int main()
{
    Zespolona Z1 = utworz();                        //  tworzymy zespoloną z klawiatury
    int m;                                          //  składowa sumy
    
    printf("Podaj m: ");
    scanf("%d", &m);
    
    Zespolona Z = utworz2(1, 0);                    //  struktura wynikowa = Z1^0 = 1 + 0i
    
    int n;
    for (n = 1; n <= m; n++)                        //  pominięte 0, jak wyżej
    {
        Z = dodaj(Z, potega(Z1, n));                //  suma wynikowej oraz potęgi wejściowej
    }
    
    pokaz(Z);                                       //  pokaz wynikowej
    
    return 0;
}