/*----------------------------2.1.c--------------------------*/
/* if-else viseznacnost */

#include <stdio.h>

/* Bez obzir na nacin kako je kod nazubljen, 
   else se uvek odnosi na najblizi if */
int main() {
  int a = -3, b = -3;
  if (a > 0)
    if (b > 0)
      printf("b je pozitivan\n");
  else
    printf("a je negativan\n");

  /*
  C prevodilac kod tumaci na sledeci nacin:
  if (a > 0)
    if (b > 0)
      printf("b je pozitivan\n");
    else
      printf("a je negativan\n");

  Gornja struktura bi morala da se nametne kao:
  if (a > 0) {
    if (b > 0)
      printf("b je pozitivan\n");
  } else
    printf("a je negativan\n")

  */
  return 0;
}

/*----------------------------2.2a.c--------------------------*/
/* petlja sa dva brojaca */
#include <stdio.h>

int main() {
  int i, j;

  for (i = 0, j = 10; i < j; i++, j--)
	printf("i = %d,  j = %d\n", i, j);
  return 0;
}

/*----------------------------2.2b.c--------------------------*/
/* ugnjezdjene petlje */
#include <stdio.h>

#define MAX 3
/* int MAX = 3; */

int main() {
  int i, j;
  for (i = 0; i < MAX; i++)
	for (j = 0; j < MAX; j++) 
	  printf("i = %d,  j = %d\n", i, j);
  return 0;
}

/*----------------------------2.2c.c--------------------------*/
/* ugnjezdjene petlje - tablica mnozenja */
#include <stdio.h>

int main() {
  int i, j;

  printf("    |");
  for (j = 1; j <= 10; j++)
	  printf("%4d", j);
  printf("\n");

  for (j = 0; j < 45; j++)
	printf("-");
  printf("\n");
	
  for (i = 1; i <= 10; i++) {
	printf("%4d|", i);
	for (j = 1; j <= 10; j++) {
	  printf("%4d", i*j);
	}
	printf("\n");
  }
  return 0;
}

/*----------------------------2.3a.c--------------------------*/
/* atoi - konverzija niske karaktera u ceo broj */
#include <stdio.h>
#include <ctype.h>

unsigned atoi(char s[]) {
  unsigned v = 0, i;
  /* Na ASCII sistemima isdigit(c) je ekvivalentno sa:
     '0' <= c && c <= '9'. Ipak, preporucuje se koriscenje 
     funkcija iz <ctype.h>*/
  for (i = 0;  isdigit(s[i]); i++) 
    v = v * 10 + (s[i] - '0');
  return v;
}

int main() {
  char s[] = "1234abc";
  printf("Vrednost niske %s je %d\n", s, atoi(s));
  return 0;
}

/* Vezba: dopuniti funkciju tako da u obzir uzima i znak broja. */

/*----------------------------2.3b.c--------------------------*/
/* atof - konverzija niske karaktera s u realni broj */
#include <stdio.h>
#include <ctype.h>

double atof(char s[]) {
  double value, power;
  int i, sign;

  /* preskacemo pocetne beline */
  for (i=0; isspace(s[i]); i++)
    ;
  
  /* odredjujemo znak broja */
  sign = (s[i] == '-') ? -1 : +1;
  if (s[i] == '+' || s[i] == '-')
    i++;

  /* celobrojni deo */
  for (value = 0.0; isdigit(s[i]); i++)
    value = 10.0 * value + (s[i] - '0');
  
  /* preskacemo decimalnu tacku */
  if (s[i] == '.')
    i++;

  /* razlomljeni deo */
  for(power=1.0; isdigit(s[i]); i++) {
    value = 10.0 * value + (s[i] - '0');
    power *= 10.0;
  }
  
  /* izracunavamo i vracamo krajnji rezultat */
  return sign * value / power;
}

int main() {
  char s[] = "-123.456";
  printf("Vrednost niske %s je %f\n", s, atof(s));
  return 0;
}

/*----------------------------2.3c.c--------------------------*/
/* btoi - konverzija iz datog brojnog sistema u dekadni */
#include <stdio.h>
#include <ctype.h> 

/* Pomocna funkcija koja izracunava vrednost koju predstavlja karakter u datoj osnovi 
   Funkcija vraca -1 ukoliko cifra nije validna.
   
   Npr. 
   cifra 'B' u osnovi 16 ima vrednost 11
   cifra '8' nije validna u osnovi 6

*/
   
int digit_value(char c, int base) {
  /* Proveravamo obicne cifre */
  if (isdigit(c) && c < '0'+base)
	return c-'0';

  /* Proveravamo slovne cifre za mala slova */
  if ('a'<=c && c < 'a'+base-10)
	return c-'a'+10;

  /* Proveravamo slovne cifre za velika slova */
  if ('A'<=c && c < 'A'+base-10)
	return c-'A'+10;
  
  return -1;
}

/* Funkcija izracunava vrednost celog broja koji je zapisan u datom 
   nizu karaktera u datoj osnovi. Za izracunavanje se koristi Hornerova shema. 
*/
int btoi(char s[], int base) {
  int sum = 0;
  
  /* Obradjuju se karakteri sve dok su cifre */
  int i, vr;
  for (i = 0; (vr = digit_value(s[i], base)) != -1; i++)
	sum = base*sum + vr;
  
  return sum;
  
}

int main() {
  char bin[] = "11110000";
  char hex[] = "FF";

  printf("Dekadna vrednost binarnog broja %s je %d\n", bin, btoi(bin, 2));
  printf("Dekadna vrednost heksadekadnog broja %s je %d\n", hex, btoi(hex, 16));
  
  return 0;
}

/*----------------------------2.4a.c--------------------------*/
/* Mnozenje preko sabiranja */
#include <stdio.h>

int main() {
  unsigned x, y, z, i;

  /* Unos sabiraka */
  printf("Unesi x i y: ");
  scanf("%u %u", &x, &y);

  /* Proizvod se inicijalizuje na 0 */
  z = 0;
  /* Zatim se x puta proizvod uveca za y */
  for (i = 0; i < x; i++)
    z += y;

  printf("Proizvod je: %u\n", z);

  /*
    Nekoliko alternativnih formulacija istog algoritma:

    while petlja: 
    -------------
    z = 0;
    i = 0;
    while(i < x) {
      z = z + y;
      i = i + 1;
    }


    kombinovanje izraza koriscenjem , u for petlji:
    -----------------------------------------------
    for (z = 0, i = 0; i < x; z+=y, i++)
          ;

    izbegavanje pomocne promenljive uz izmenu promenljive x:
    --------------------------------------------------------
    z = 0;
    while(x > 0) {
      z += y;
      x--;
    }

  */
  return 0;
}

/*----------------------------2.4b.c--------------------------*/
/* Stepenovanje preko mnozenja */
#include <stdio.h>

int main() {
  float x, s;
  unsigned i, n;

  /* Unos cinilaca */
  printf("Unesi x i n: ");
  scanf("%f %u", &x, &n);

  /* Stepen se inicijalizuje na 1.0 */
  s = 1.0;
  /* Zatim se n puta pomnozi sa x */
  for (i = 0; i < n; i++)
    s *= x;

  printf("Stepen je: %f\n", s);

  /*
    Nekoliko alternativnih formulacija istog algoritma:

    s = 1.0;
    i = 0;
    while(i < n) {
      s = s * x;
      i = i + 1;
    }



    for (s = 1.0, i = 0; i < n; s*=x, i++)
          ;


    s = 1.0;
    while (n > 0) {
       s *= x;
       n--;
    }
  */
  return 0;
}

/*----------------------------2.4c.c--------------------------*/
/* power - funkcija za stepenovanje - obuhvaceni i negativni izlozioci */
#include <stdio.h>

/* stepenuje x^k tako sto k puta pomnozi x */
float power(float x, unsigned n) {
  unsigned i;
  float s = 1.0;
  for (i = 0; i<n; i++)
    s*=x;
  return s;
}

/* Verzija koja radi i za negativne izlozioce */
float power_n(float x, int n) {
  unsigned i;
  int negative = n<0;

  if (negative)
    n = -n;

  float s = 1;
  for (i = 0; i < n; i++)
    s*=x;
    
  return negative ? 1.0/s : s;  
}

int main() {
  printf("%f\n", power(2.0, 8));
  printf("%f\n", power_n(2.0, -3));
  return 0;
}

/*----------------------------2.5a.c--------------------------*/
/* Deljenje preko oduzimanja */
#include <stdio.h>

int main() {
  unsigned x = 19, y = 5, q, r;
  /* Kolicnik i ostatak su takvi brojevi q i r
	 za koje vazi: 
	    x = q*y + r,  0 <= r < y
  */

  /* Inicijalno postavljamo q na 0 i uvecavamo ga postepeno za po
	 jedan, podesavajuci r tako da sve vreme zadovoljava uslov x = q*y
	 + r.  Iteracija se prekida u trenutku kada r postane manje od y.
  */
  q = 0; r = x;
  while (r >= y) {
	q++;
	r-=y;
  }

  printf("Kolicnik: %u, ostatak: %u\n", q, r);
  return 0;
}

/*----------------------------2.6a.c--------------------------*/
/* Euklidov algoritam za odredjivanje NZD - preko oduzimanja -
   rekurzivna definicija */
#include <stdio.h>

/* O rekurziji vise u kursu P2 - predstavlja prirodan nacin za
   formulaciju nekih algoritama. */
unsigned nzd(unsigned a, unsigned b) {
  /* printf("%u, %u\n", a, b); */
  if (a == 0)
    return b;
  if (b == 0)
    return a;
  if (a > b)
    return nzd(a - b, b);
  else
    return nzd(a, b - a);
}


int main() {
  unsigned a = 105, b = 252;
  printf("NZD(%u, %u) = %u\n", a, b, nzd(a, b));
  return 0;
}

/*----------------------------2.6b.c--------------------------*/
/* Euklidov algoritam za odredjivanje NZD - preko oduzimanja - uklonjena rekurzija */
#include <stdio.h>

unsigned nzd__(unsigned a, unsigned b) {
  /* Beskonacna petlja - oslanjamo se na cinjenicu da return naredba
	 prekida petlju */
  while (true) {
	/* printf("%u, %u\n", a, b); */
    if (a == 0)
      return b;
    if (b == 0)
      return a;
    if (a > b)
      a -= b;
    else
      b -= a;
  }
}

unsigned nzd_(unsigned a, unsigned b) {
  /* Uklonjena beskonacna petlja */
  while (a != 0 && b != 0) {
	/* printf("%u, %u\n", a, b); */
    if (a > b)
       a -= b;
    else
      b -= a;
  }
  if (a == 0)
	return b;
  if (b == 0)
	return a;
}


/* Uslov a == 0 u prethodnoj funkciji je moguc samo na pocetku, posto
   se u slucaju da je a == b umanjuje b. Ovim se implementacija moze
   ubrzati. */
unsigned nzd(unsigned a, unsigned b) {
  if (a == 0)
	return b;

  while (b != 0) {
	/* printf("%u, %u\n", a, b); */
	if (a > b)
	  a -= b;
	else
	  b -= a;
  }

  return a;
}


int main() {
  unsigned a = 105, b = 252;
  printf("NZD(%u, %u) = %u\n", a, b, nzd(a, b));
  return 0;
}

/*----------------------------2.6c.c--------------------------*/
/* Euklidov algoritam za odredjivanje NZD - preko deljenja -
   rekurzivna definicija*/
#include <stdio.h>

/* O rekurziji vise u kursu P2 - predstavlja prirodan nacin za
   formulaciju nekih algoritama. */
unsigned nzd(unsigned a, unsigned b) {
  /* printf("%u, %u\n", a, b); */
  if (b == 0)
	return a;
  else
	return nzd(b, a % b);
}

int main() {
  unsigned a = 105, b = 252;
  printf("NZD(%u, %u) = %u\n", a, b, nzd(a, b));
  return 0;
}

/*----------------------------2.6d.c--------------------------*/
/* Euklidov algoritam za odredjivanje NZD - preko deljenja - uklonjena rekurzija */
#include <stdio.h>

unsigned nzd(unsigned a, unsigned b) {
  while (b != 0) {
    unsigned r = a % b;
    a = b;
    b = r;
  }
  return a;
}

int main() {
  unsigned a = 105, b = 252;
  printf("NZD(%u, %u) = %u\n", a, b, nzd(a, b));
  return 0;
}