/* CS 203. Correction de la feuille 2 */
/* Note : pour compiler ce fichier, il faut faire appel a la librairie mathematique avec l'option -lm */
/* Credit : certains des programmes presentes ici ont ete realises par Pierre Cohort */

#include <stdio.h>
#include <math.h> /* pour les fonctions sqrt, floor, ... */

/* exercice 1 */
double conversion(int somme_en_francs)
{
  const double taux=6.55957;
  return (double)somme_en_francs/taux;
  /* commentaire : la syntaxe (double) devant le parametre somme_en_francs 
     signifie que celui-ci est, dans la division,  converti en double.
     La conversion est en fait ici automatique (un entier divise ou multiplie
     par un reel est tjrs converti en reel). */  
}

void table_franc_euro(int smin, int smax, int pas)
{
  int i;
  for (i=smin; i<=smax; i+=pas){
    printf("%d francs = %f euros\n",i,conversion(i));
  }
}

/* exercice 2 */
void table1010()
{
  int i,j;
  for (i=0;i<=10;i++){
    for (j=0;j<=i;j++){
      printf("%d * %d = %d\t",i,j,i*j); 
    }
    printf("\n");
  }
}

/* exercice 3 */
int fibonacci(int n)
{
  int u0=0,u1=1,u2,i;
  for (i=2;i<=n;i++){
    u2=u0+u1;
    u0=u1;
    u1=u2;
  }
  return u2;
}

/* commentaire : si on desire calculer a differents moments
   plusieurs valeurs de la suite, la fonction precedente n'est
   pas efficace car elle induit le recalcul des premiers termes
   de la suite pour chaque nouvelle valeur demandee. On peut 
   resoudre ce probleme en conservant en memoire le dernier indice
   calcule et la valeur correspondante de u. */

int Fibonacci(int n)
{
  int i;
  static int u0=0,u1=1,u2,_n=2;
  /* en presence du mot cle static, les initialisations precedentes
     sont effectuees une seule fois (au premier appel de la fonction).
     Les valeurs de u0,u1,u2 et i sont ensuite conservees en memoire
     entre les differents appels a la fonction. */

  for (i=_n;i<=n;i++){
    u2=u0+u1;
    u0=u1;
    u1=u2;
  }
  _n=n+1;
  /* la variable _n contient l'indice de depart des calculs au prochain
     appel. Noter que les appels successifs a Fibonacci doivent
     etres faits avec une suite croissante d'entiers. */
  return u2;
}

/* exercice 4 */
/* on implemente d'abord la fonction f a partir de laquelle la
   suite est definie.*/
long f(int n)
{
  if (n%2==0){  /* n%2==0 equivaut a n pair */
    return n/2;
  } else {
    return 3*n+1;
  }
}   

/* La fonction suivante calcule les termes d'une suite de syracuse
   jusqu'a verifier la conjecture ou atteindre un indice maximal
   n_max fixe a l'avance. Elle retourne min(n(u0),n_max) ou n(u0) est
   le plus petit k pour lequel uk=1 */

long Syracuse(long u0)
{
  const long n_max=1000000;
  long u=u0,n=0;
  while ((u!=1)&&(n<n_max)) {u=f(u);n++;}
  return n;
}  

/* teste la conjecture pour u0 dans {1,...,n} */
void Collatz(long n)
{
  long i;
  for (i=1;i<=n;i++){
    printf("u0 = %d ; u%d = 1\n",i,Syracuse(i));
  }
}
/* commentaire : il est interessant de visualiser la fonction Syracuse.
   Pour cela, on ecrit une fonction qui stocke les couples (u0,Syracuse(u0))
   dans un fichier. */

void writeFile(long n)
{
  FILE* file=NULL;
  int i;

  file=fopen("syracuse.dat","w"); /* cree le fichier syracuse.dat */
  if (file==NULL){ return; } /* arret si probleme d'ouverture du fichier */ 
  
  for (i=1;i<=n;i++){
    /* ecriture dans le fichier syracuse.dat des couples (u0,Syracuse(u0))
       pour uo dans {0,...,n} */
    fprintf(file,"%d %d\n",i,Syracuse(i));
  }
  fclose(file); /* fermeture du fichier */
}
    
/* Verifier que le programme a bien fonctionne en examinant
   le contenu de syracuse.dat avec la commande linux
   more syracuse.dat, ou en l'ouvrant avec emacs (dans ce cas, attention
   a ne pas modifier le fichier). Vous pouvez visualiser les resultats graphiquement en
   utilisant gnuplot (lancer gnuplot puis, sous l'invite de
   commandes gnuplot, tapez plot "syracuse.dat"), ou en utilisant
   matlab/scilab (en scilab : x=fscanfMat("syracuse.dat") puis 
   fonctions graphiques appliquees a x (voir aide du logiciel)*/

/* exercice 5 */
void racine(double a, double b, double c)
{
  double delta=b*b-4*a*c;

  if (delta==0.){
    /* une seule racine reelle */
    printf("Racine unique de %fx^2+%fx+c=0 : %f\n",a,b,c,-b/(2.*a));
  } else if (delta>0) {
    /* deux racines reelles */
    printf("Racines de %fx^2+%fx+c=0 : %f et %f\n",
           a,b,c,(-b-sqrt(delta))/(2.*a),(-b+sqrt(delta))/(2.*a) );    
  } else {
    /* deux racines complexes conjuguees */
    double r=-b/(2.*a), im=sqrt(-delta)/(2.*a);
    printf("Racines de %fx^2+%fx+%f=0 : %f-i*(%f) et %f+i*(%f)\n",a,b,c,r,im,r,im);
  }
}

/* exercice 6 */
/* un entier positif compris entre 10^k et 10^(k+1)-1 possede k+1 chiffres.
   Donc, un entier n positif dont le logarithme en base 10 est compris entre k et k+1
   (k+1 exclus) est k+1. Ainsi, le nombre de chiffres d'un entier n positif est la 
   partie entiere de son logarithme en base 10 plus 1. Pour les entiers negatifs, on passe
   a la valeur absolue. */

int NCHIFFRES(long n)
{
  if (n==0) {
    return 1;
  } else {
    return (int)floor(log(fabs((double)(n))/log(10.)))+1;
    /* en C, log est le logarithme de base e */
  }
}

/* exercice 7 */
/* Le resultat du programme est l'affichage de "x=1, y=2".
   Il ne s'est donc rien passe, malgre l'appel a la fonction
   echange, censee echanger deux entiers.
   
   Explication : Lors de l'appel de la fonction echange, les parametres 
   a et b sont temporairement crees et initialises avec les valeurs
   de x et y. Ils sont ensuite echanges :  apres
   l'instruction b=auxi , on a bien a=2 et b=1 mais, en fin d'execution,
   a et b sont detruits. Au resultat, x et y ne sont pas modifies.
   
   Solution : il faut passer les adresses de x et y a la fonction echange, a l'aide
   de pointeurs d'entiers : */

void echange(int* a, int* b)
{
  int auxi;

  auxi=*a;
  *a=*b;  /*  *a est l'entier dont l'adresse est a  */
  *b=auxi;
}
/* L'appel a echange est alors echange(&x,&y) (&x est l'adresse de x en memoire).
   La fonction echange agit ainsi directement sur les variables x et y. Le
   resultat sera "x=2, y=1" */


/* exercice 8 */
/* on nomme g la fonction integree  pour ne pas dupliquer l'identificateur f de 
   l'exercice 4 */

double g(double x)
{
  return x*x;
}

double trapeze(double a, double b, double pas)
{
  double h=a+pas,aux1=g(a),aux2=g(a+pas),I=0;
  
  do {
    I+=(aux1+aux2)*0.5*pas;
    aux1=aux2;
    h+=pas;
    aux2=g(h);
  } while (h<b);

  return I;
}

/* exercice 9 */
float Celcius2Fahrenheit (float DegresCelcius)
     /* Conversion de Degres Celcius en Degres Fahrenheit
        ENTREE : DegresCelcius, temperature a convertir
        SORTIE : temperature convertie en Degres Fahrenheit
     */
{
  return(9.0*DegresCelcius/5.0+32);
}

float Fahrenheit2Celcius (float DegresFahrenheit)
     /* Conversion de Degres Fahrenheit en Degres Celcius 
        ENTREE : DegreFahrenheit, temperature a convertir
        SORTIE : temperature convertie en Degres Celcius
     */
{
  return(5.0/9.0*(DegresFahrenheit-32));
}


int main()
{
  printf("Exercice 1 :\n");
  table_franc_euro(0, 100, 5);

  printf("Exercice 2 :\n");
  table1010();

  printf("Exercice 3 :\n");
  printf("fibonacci(12) = %d\n",fibonacci(12));
  printf("Fibonacci(1) = %d\n",Fibonacci(1));
  printf("Fibonacci(4) = %d\n",Fibonacci(4));
  printf("Fibonacci(10) = %d\n",Fibonacci(10));
  printf("Fibonacci(12) = %d\n",Fibonacci(12));

  printf("Exercice 4 :\n");
  Collatz(1000);
  /*writeFile(1000);*/

  printf("Exercice 5 :\n");
  racine(1,1,1);

  printf("Exercice 6 :\n");
  printf("%d possede %d chiffres\n",124573,NCHIFFRES(124573));

  printf("Exercice 7 :\n");
  { 
    int a=1,b=2;
    printf("a=%d b=%d\n",a,b);
    echange(&a,&b);  /* &a est l'adresse de la variable a */
    printf("a=%d b=%d\n",a,b);
  }
  
  printf("Exercice 8 :\n");
  {
    double a=1.0,b=2.0;
    printf("valeur theorique de l'integrale de g entre %f et %f = %f\n",a,b,(b*b*b-a*a*a)/3.);
    printf("valeur calculee de l'integrale de g entre %f et %f = %f\n",a,b,trapeze(a,b,0.001));
  }

  printf("Exercice 9 :\n");
  printf("20 degres Celcius corresponded a %f degres Fahrenheit\n",Celcius2Fahrenheit(20));
  printf("-40 degres Fahrenheit corresponded a %f degres Celcius\n",Fahrenheit2Celcius(-40));
  return(0);
}