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

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



/* exercice I */

double conversion(int somme_en_francs)
     /* Conversion des francs en euros
	ENTREE : somme en francs
	SORTIE : equivalent en euros
     */
{
  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 toujours converti en reel). */  
}

void table_franc_euro(int smin, int smax, int pas)
     /* Affichage de la table de conversion francs -> euros
	ENTREE : smin somme minimale
	         smax somme maximale
		 pas increment
        SORTIE : A l'ecran, affichage de la table
     */
{
  int i;
  for (i=smin; i<=smax; i+=pas){
    printf("%d francs = %f euros\n",i,conversion(i));
  }
}

int main_exercice1()
{
  table_franc_euro(0, 100, 5);
  return 0;
}



/* exercice II */

int main_exercice2()
{
  int i,j;
  for (i=0;i<=10;i++){
    for (j=0;j<=10;j++){
      printf("%4d",i*j); 
    }
    printf("\n");
  }
  return 0;
}



/* exercice III */

/* Attention a la difficulte suivante : 
   Si on calcule n! pour n=16, on depasse la capacite de int */

int Hermite(int n)
     /* Calcul du n-ieme nombre de Hermite
	ENTREE : n
	SORTIE : Hn
     */
{
  int i, res;

  if (n%2!=0) res=0;
  else {

    /* (-1)^(n/2) */
    if (n%4==0) res=1;
    else res=-1;

    /* n!/[(n/2)!] */
    for (i=n/2+1;i<=n;i++)
      res*=i;
  }
  
  return res;
}

int main_exercice3()
{
  int i;

  /* Les 17 premiers termes sont H0,...,H16 */
  for (i=0;i<=16;i++)
    printf("H%d=\t%d\n",i,Hermite(i));

  return 0;
}



/* exercice IV */

int Fibonacci(int n)
     /* n-ieme terme de la suite de Fibonacci
	ENTREE : n
	SORTIE : Un ou U est la suite de Fibonacci
     */
{
  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_Static(int n)
     /* n-ieme terme de la suite de Fibonacci
	ENTREE : n
	SORTIE : Un ou U est la suite de Fibonacci
	Fonction utilisant des variables statiques, plus efficasses en cas d'appels 
	pour des termes successifs
     */
{
  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;
}

int main_exercice4() {
  printf("fibonacci(12) = %d\n",Fibonacci(12));
  printf("fibonacci(12) = %d\n",Fibonacci_Static(12));
  return 0;
}



/* Exercice V */

void PiecesARendre(int MontantARendre, int TypeDePiece)
     /* Affiche le nombre de pieces (de type TypeDePiece) a rendre 
        pour le montant MontantARendre
        ENTREE : MontantARendre est le montant a rendre en centimes d'euros
                 TypeDePiece est la valeur de la piece en centimes d'euros
        SORTIE : Aucune mais le programme affiche les messages a l'ecran
     */
{
  int ARendre;
  ARendre=MontantARendre/TypeDePiece;
  printf("Rendre %d piece(s) de %.2f euro(s)\n",ARendre,(float)TypeDePiece/100);
}

int ResteARendre(int MontantARendre, int TypeDePiece)
     /* Indique ce qui reste a rendre une fois que les pieces TypeDePiece ont
        ete rendues.        
        ENTREE : MontantARendre est le montant a rendre en centimes d'euros
                 TypeDePiece est la valeur de la piece en centimes d'euros
        SORTIE : Montant restant a rendre
     */
{
  return (MontantARendre%TypeDePiece);
}

void RenduMonnaie (int PrixArticle, int MontantPaye)
     /* Affiche le nombre de pieces a rendre afin de minimiser le nombre de 
        pieces rendues.
        ENTREE : PrixArticle est le prix de l'article achete
	         MontantPaye est le montant paye par l'acheteur
        SORTIE : Aucune mais le programme affiche les messages a l'ecran
     */
{
  int MontantARendre, Reste;

  MontantARendre=MontantPaye-PrixArticle;
  assert(MontantARendre>=0);

  PiecesARendre(MontantARendre,200);
  Reste=ResteARendre(MontantARendre,200);
  PiecesARendre(Reste,100);
  Reste=ResteARendre(MontantARendre,100);
  PiecesARendre(Reste,50);
  Reste=ResteARendre(MontantARendre,50);
  PiecesARendre(Reste,20);
  Reste=ResteARendre(MontantARendre,20);
  PiecesARendre(Reste,10);
  assert(ResteARendre(MontantARendre,10)==0);
}

void main_exercice5()
     /* On verifie sur l'exemple */
{
  RenduMonnaie(430,570); 
}



/* exercice VI */

/* Question 1 */

/*
Notons Qi le quotient de la division entiere de Ni par 97.
On a N1=97Q1+R1 et N2=97Q2+R2.
D'autre part N0=10^6N1+N2 ainsi
N0=10^6(97Q1+R1)+(97Q2+R2)=97*(10^6Q1+Q2)+10^6R1+R2
Or 10309*97=999973 donc 10^6=10309*97+27, par suite
N0=97*(10^6Q1+Q2+10309)+27R1+R2
ainsi R0=N0 mod 97=97*(10^6Q1+Q2+10309)+27R1+R2 mod 97
donc R0=27R1+R2 mod 97
*/

/* Question 2 */

int clef (long int N1, long int N2)
     /* 
	Calcul de la clef d'un numero de securite sociale 
	ENTREE : N1 les 7 premiers chiffres du numero SS
	         N2 les 6 derniers chiffres du numero SS
	SORTIE : clef du numero SS 
	Cette fonction utilise la formule etablie dans la question 1
     */
{
  int R0, R1, R2;

  R1=N1%97;
  R2=N2%97;
  R0=(27*R1+R2)%97;

  return(97-R0);
}

/* Question 3 */

void main_exercice6()
{
  int groupe1, groupe2, groupe3, groupe4, groupe5, groupe6;
  long int N1, N2;

  printf("Entrez le numero de securite sociale en separant les 6 groupes par un espace.\n"); 
  scanf("%d %d %d %d %d %d",&groupe1,&groupe2,&groupe3,&groupe4,&groupe5,&groupe6);

  /* N1 comprend les 7 premiers chiffres et N2 les 6 deriniers */
  N1=groupe4+100*groupe3+10000*groupe2+1000000*groupe1;
  N2=groupe6+groupe5*1000;

  /* Affichage de la clef */
  printf("La clef associee a ce numero est %d\n",clef(N1,N2));

  /* Affichage homme/femme */
  if ((groupe1==1)||(groupe1==7))
    printf("L'individu est un homme\n");
  else
    printf("L'individu est une femme\n");

  /* Affichage du lieu de naissance */
  if ((groupe4==99)||((groupe2<=64)&&(groupe4>=90)&&(groupe4<=96)))
    /* Dans la gestion du groupe4 entre 90 et 96, on ne gere pas le cas des 
       individus nes apres l'an 2000 */
    printf("L'individu est ne a l'etranger\n");
  else
    printf("L'individu est ne en France\n");
}




/* main */

int main()
{
  int n;

  printf("Feuille d'exercices 2\n");
  printf("Choix de l'exercice : ");
  scanf("%d",&n);

  switch (n) {
  case 1: main_exercice1(); break;
  case 2: main_exercice2(); break;
  case 3: main_exercice3(); break;
  case 4: main_exercice4(); break;
  case 5: main_exercice5(); break;
  case 6: main_exercice6(); break;
  }

  return 0;
}