#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <memory.h>

#include "complex.h"

/**
 * 複素数を0で初期化します。
 * 
 * @param target 複素数
 */
void complex_zero(complex_t *target){
  {
    // 埋めてね
    target->real = 0;
    target->imaginary = 0;
  }
}

/**
 * 複素数を見やすい形で表示します。
 * 
 * @param target 複素数
 */
void complex_print(complex_t target){
  {
    // 埋めてね
    printf("%f + %f i", target.real, target.imaginary);
  }
}

/**
 * 複素数のコピーを行います。
 * 
 * @param src コピー元
 * @param dist コピー先
 */
void complex_copy(complex_t *src, complex_t *dist){
  {
    // 埋めてね
    memcpy(dist, src, sizeof(complex_t));
    //*dist = *src;
  }
}

/**
 * 2つの複素数の値が等しいか調べます。
 * 
 * @param a 複素数その1
 * @param b 複素数その2
 * @return 等しい場合は TRUE。そうでない場合は FALSE。 
 */
BOOL complex_is_equal(complex_t a, complex_t b){
  {
    // 埋めてね
    if(memcmp(&a, &b, sizeof(complex_t)) != 0){
      return FALSE;
    }
  }
  return TRUE;
}

/**
 * 2つの複素数の加算を行います。
 * 
 * @param a 複素数その1
 * @param b 複素数その2
 * @return 加算した結果
 */
complex_t complex_add(complex_t a, complex_t b){
  complex_t result;
  {
    // 埋めてね
    result.real = a.real + b.real;
    result.imaginary = a.imaginary + b.imaginary;
  }
  return result;
}

/**
 * 2つの複素数の減算を行います。
 * 
 * @param a 複素数(ひかれる側)
 * @param b 複素数(ひく側)
 * @return 減算した結果
 */
complex_t complex_sub(complex_t a, complex_t b){
  complex_t result;
  {
    // 埋めてね
    result.real = a.real - b.real;
    result.imaginary = a.imaginary - b.imaginary;
  }
  return result;
}

/**
 * 2つの複素数の積算を行います。
 * 
 * @param a 複素数その1
 * @param b 複素数その2
 * @return 積算した結果
 */
complex_t complex_multi(complex_t a, complex_t b){
  complex_t result;
  {
    // 埋めてね
    result.real = a.real * b.real - a.imaginary * b.imaginary;
    result.imaginary = a.real * b.imaginary + a.imaginary * b.real;
  }
  return result;
}

/**
 * 複素数と実数の加算を行います。
 * 
 * @param a 複素数
 * @param b 実数
 * @return 加算した結果(複素数)
 */
complex_t complex_scalar_add(complex_t a, double b){
  complex_t result;
  {
    // 埋めてね
    result.real = a.real + b;
    result.imaginary = a.imaginary;
  }
  return result;
}

/**
 * 複素数から実数の減算を行います。
 * 
 * @param a 複素数
 * @param b 引く実数
 * @return 減算した結果(複素数)
 */
complex_t complex_scalar_sub(complex_t a, double b){
  complex_t result;
  {
    // 埋めてね
    result.real = a.real - b;
    result.imaginary = a.imaginary;
  }
  return result;
}

/**
 * 複素数を実数倍します。
 * 
 * @param a 複素数
 * @param b 実数
 * @return 実数倍した結果(複素数)
 */
complex_t complex_scalar_multi(complex_t a, double b){
  complex_t result;
  {
    // 埋めてね
    result.real = a.real * b;
    result.imaginary = a.imaginary * b;
  }
  return result;
}

/**
 * 複素数を実数割します。
 * 
 * @param a 複素数
 * @param b 実数
 * @return 実数割した結果(複素数)
 */
complex_t complex_scalar_div(complex_t a, double b){
  return complex_scalar_multi(a, 1.0 / b);
}

/**
 * 複素数のノルムの2乗を求めます。
 * 
 * @param target 対称となる複素数
 * @return ノルムの2乗(実数)
 */
double complex_abs2(complex_t target){
  return pow(target.real, 2) + pow(target.imaginary, 2);
}

/**
 * 複素数のノルムを求めます。
 * 
 * @param target 対称となる複素数
 * @return ノルム(実数)
 */
double complex_abs(complex_t target){
  return sqrt(complex_abs2(target));
}

