// Copyright 2018-2025 RnD Center "ELVEES", JSC

/*! \file
 *  \brief Реализация вспомогательных функций
 *  \author Фролов Андрей
 */

#include "helper.h"

void print_table_header() {
  printf("| func name              ");
  printf("| element count  ");
  printf("| ref tic    ");
#ifdef PRINT_INSTR
  printf("| ref instr  ");
#endif
  printf("| opt tic    ");
#ifdef PRINT_INSTR
  printf("| opt instr  ");
#endif

  printf("| TI tic     ");
  printf("| byte/tic opt ");
  printf("| byte/tic TI  ");
  printf("| status |\n");
  printf(
      "---------------------------------------------------------------------------------------------------------------"
      "----------\n");
}

void print_performance(uint32_t* ref_tic_count, uint32_t* ref_instruction_count, uint32_t* tic_count,
                       uint32_t* instruction_count, int32_t input_bytes, int32_t ti_tics) {
  printf(" %10u |", ref_tic_count[1] - ref_tic_count[0]);
#ifdef PRINT_INSTR
  printf(" %10u |", ref_instruction_count[1] - ref_instruction_count[0]);
#endif
  printf(" %10u |", tic_count[1] - tic_count[0]);
#ifdef PRINT_INSTR
  printf(" %10u |", instruction_count[1] - instruction_count[0]);
#endif
  if (ti_tics)
    printf(" %10d |", ti_tics);
  else
    printf("          - |");

  printf(" %12.2f |", 1.0 * input_bytes / (tic_count[1] - tic_count[0]));

  if (ti_tics)
    printf(" %12.2f |", 1.0 * input_bytes / ti_tics);
  else
    printf("            - |");
}

void create_vector_s16(int16_t* vect, int size, int sign) {
  if (sign == -1) {
    for (int i = 0; i < size; ++i) {
      vect[i] = rand() % INT16_MAX + INT16_MIN;
    }
    return;
  } else {
    if (sign == 1) {
      for (int i = 0; i < size; ++i) {
        vect[i] = rand() % INT16_MAX;
      }
      return;
    }
  }

  for (int i = 0; i < size; ++i) {
    vect[i] = rand() % (2 * INT16_MAX) + INT16_MIN;
  }
}

uint8_t compare_s16(int16_t* vect0, int16_t* vect1, int size) {
  uint8_t ret = 0;
  int err_counter = 0;
  for (int i = 0; i < size; ++i) {
    if (vect0[i] != vect1[i]) {
      // printf("\nError num = %d: %d %d", i, vect0[i], vect1[i]);
      ret = 1;
      ++err_counter;
      if (err_counter == 10) break;
    }
  }

  return ret;
}

void print_vector_s16(int16_t* vect, int size) {
  for (int i = 0; i < size; ++i) {
    if (i % 32 == 0) printf("\n");
    printf("%7d, ", vect[i]);
  }
  printf("\n");
}

void create_vector_s32(int32_t* vect, int size, int sign) {
  if (sign == -1) {
    for (int i = 0; i < size; ++i) {
      vect[i] = -(rand() % 100) - 1;
    }
    return;
  }

  if (sign == 1) {
    for (int i = 0; i < size; ++i) {
      vect[i] = rand() % 100;
    }
    return;
  }

  for (int i = 0; i < size; ++i) {
    vect[i] = rand() % 100 - 50;
  }
}

uint8_t compare_s32(int32_t* vect0, int32_t* vect1, int size) {
  uint8_t ret = 0;
  int err_counter = 0;
  for (int i = 0; i < size; ++i) {
    if (vect0[i] != vect1[i]) {
      // printf("\nError num = %d: %d %d", i, vect0[i], vect1[i]);
      ret = 1;
      ++err_counter;
      if (err_counter == 10) break;
    }
  }

  return ret;
}

uint8_t compare_float_eps(float* vect0, float* vect1, int size, float eps) {
  uint8_t ret = 0;
  int err_counter = 0;
  for (int i = 0; i < size; ++i) {
    if ((fabs((double)(vect0[i] - vect1[i]) / vect0[i]) > eps) && !(vect1[i] == vect0[i])) {
      // printf("\nError num = %d: %f %f", i, vect0[i], vect1[i]);
      ret = 1;
      ++err_counter;
    }
  }

  return ret;
}

uint8_t compare_double_eps(double* vect0, double* vect1, int size, float eps) {
  uint8_t ret = 0;
  int err_counter = 0;
  for (int i = 0; i < size; ++i) {
    if (fabs((double)(vect0[i] - vect1[i]) / vect0[i]) > eps && !(vect1[i] == vect0[i])) {
      // printf("\nError num = %d: %f %f", i, vect0[i], vect1[i]);
      ret = 1;
      ++err_counter;
      if (err_counter == 10) break;
    }
  }

  return ret;
}

void print_vector_s32(int32_t* vect, int size) {
  for (int i = 0; i < size; ++i) {
    if (i % 16 == 0) printf("\n");
    printf("%11d, ", vect[i]);
  }
  printf("\n");
}

void print_matrix_s16(int16_t* mat, int rows, int columns) {
  for (int i = 0; i < rows; ++i) {
    for (int j = 0; j < columns; ++j) {
      printf("%6d, ", mat[i * columns + j]);
    }
    printf("\n");
  }
}

void print_matrix_float(float* mat, int rows, int columns) {
  for (int i = 0; i < rows; ++i) {
    for (int j = 0; j < columns; ++j) {
      printf("%f, ", mat[i * columns + j]);
    }
    printf("\n");
  }
}

void print_matrix_s32(int32_t* mat, int rows, int columns) {
  for (int i = 0; i < rows; ++i) {
    for (int j = 0; j < columns; ++j) {
      printf("%d, ", mat[i * columns + j]);
    }
    printf("\n");
  }
}

float pow_(int a, int b) {
  if (b == 0) return 1;

  return a * pow_(a, b - 1);
}

int ceil_(float num) {
  int inum = (int)num;
  if (num == (float)inum) {
    return inum;
  }
  return inum + 1;
}

void print_vector_float(float* vect, int size) {
  for (int i = 0; i < size; ++i) {
    if (i % 16 == 0) printf("\n");
    printf("%7.7f, ", vect[i]);
  }
  printf("\n");
}

void print_vector_double(double* vect, int size) {
  for (int i = 0; i < size; ++i) {
    if (i % 16 == 0) printf("\n");
    printf("%f, ", vect[i]);
  }
  printf("\n");
}

uint8_t compare_float(float* vect0, float* vect1, int size) {
  uint8_t ret = 0;
  int err_counter = 0;
  for (int i = 0; i < size; ++i) {
    if (vect0[i] != vect1[i]) {
      // printf("\nError num = %d: %f %f", i, vect0[i], vect1[i]);
      ret = 1;
      ++err_counter;
      if (err_counter == 10) break;
    }
  }

  return ret;
}

uint8_t compare_double(double* vect0, double* vect1, int size) {
  uint8_t ret = 0;
  int err_counter = 0;
  for (int i = 0; i < size; ++i) {
    if (vect0[i] != vect1[i]) {
      // printf("\nError num = %d: %f %f", i, vect0[i], vect1[i]);
      ret = 1;
      ++err_counter;
      if (err_counter == 10) break;
    }
  }

  return ret;
}

void create_vector_float(float* vect, int size, int sign) {
  if (sign == -1) {
    for (int i = 0; i < size; ++i) {
      vect[i] = (rand() % 100) * 0.01 + rand() % 10 - 10;
    }
    return;
  }

  if (sign == 1) {
    for (int i = 0; i < size; ++i) {
      vect[i] = (rand() % 100) * 0.01 + rand() % 10;
    }
    return;
  }

  for (int i = 0; i < size; ++i) {
    vect[i] = (rand() % 100) * 0.01 + rand() % 20 - 10;
  }
}

void create_vector_double(double* vect, int size, int sign) {
  if (sign == -1) {
    for (int i = 0; i < size; ++i) {
      vect[i] = (rand() % 1000000) * 0.000001 + rand() % (100) - 100;
    }

    return;
  }

  if (sign == 1) {
    for (int i = 0; i < size; ++i) {
      vect[i] = (rand() % 1000000) * 0.000001 + rand() % 100;
    }

    return;
  }

  for (int i = 0; i < size; ++i) {
    vect[i] = (rand() % 1000000) * 0.000001 + rand() % 200 - 100;
  }
}

uint8_t compare_s64(int64_t* vect0, int64_t* vect1, int size) {
  uint8_t ret = 0;
  int err_counter = 0;
  for (int i = 0; i < size; ++i) {
    if (vect0[i] != vect1[i]) {
      // printf("\nError num = %d: %lld %lld", i, vect0[i], vect1[i]);
      ret = 1;
      ++err_counter;
      if (err_counter == 10) break;
    }
  }

  return ret;
}

void print_matrix_double(double* mat, int rows, int columns) {
  for (int i = 0; i < rows; ++i) {
    for (int j = 0; j < columns; ++j) {
      printf("%f, ", mat[i * columns + j]);
    }
    printf("\n");
  }
}

uint8_t compare_16i16f_eps(int32_t* vect0, int32_t* vect1, int size, float eps) {
  uint8_t ret = 0;
  int err_counter = 0;
  uint32_t xl, yl, xh, yh;
  float x_d, y_d, x_c, y_c, x, y;

  for (int i = 0; i < size; ++i) {
    xl = 0x0000ffff & vect0[i];
    yl = 0x0000ffff & vect1[i];

    xh = vect0[i] >> 16;
    yh = vect1[i] >> 16;

    x_d = (float)xl / 0xffff;
    y_d = (float)yl / 0xffff;

    x_c = (float)(int16_t)xh;
    y_c = (float)(int16_t)yh;

    x = x_d + x_c;
    y = y_d + y_c;

    if ((fabs((double)(x - y) / (x)) > eps) && !(x == y)) {
      // printf("\nError num = %d: %f %f", i, vect0[i], vect1[i]);
      ret = 1;
      ++err_counter;
    }
  }

  return ret;
}
