--- title: "Introduction aux algorithmes I" date: "2024-09-16" --- # Qu'est-ce qu'un algorithme? ## Définition informelle (recette) * des entrées (les ingrédients, le matériel utilisé) ; * des instructions élémentaires simples (frire, flamber, etc.), dont les exécutions dans un ordre précis amènent au résultat voulu ; * un résultat : le plat préparé. . . . ## Histoire et étymologie - Existent depuis 4500 ans au moins (algorithme de division, crible d'Eratosthène). - Le mot algorithme est dérivé du nom du mathématicien perse *Muḥammad ibn Musā al-Khwārizmī*, qui a été "latinisé" comme *Algoritmi*. . . . ## Définition formelle En partant d'un état initial et d'entrées (peut-être vides), une séquence finie d'instruction bien définies (ordonnées) implémentables sur un ordinateur, afin de résoudre typiquement une classe de problèmes ou effectuer un calcul. # Notions de base d'algorithmique ## Variable . . . * Paire: identifiant - valeur (assignation); ## Séquence d'instructions / expressions . . . * Opérateurs (arithmétiques / booléens) * Boucles; * Structures de contrôle; * Fonctions; # Algorithme de vérification qu'un nombre est premier (1/3) Nombre premier: nombre possédant deux diviseurs entiers distincts. . . . ## Algorithme naïf (problème) ```C booléen est_premier(nombre) si pour tout i, t.q. 1 < i < nombre i ne divise pas nombre alors vrai sinon faux ``` . . . ## Pas vraiment un algorithme: pas une séquence ordonnée et bien définie . . . ## Problème: Comment écrire ça sous une forme algorithmique? # Algorithme de vérification qu'un nombre est premier (2/3) ## Algorithme naïf (une solution) ```C booléen est_premier(nombre) // fonction soit i = 2 // variable, type, assignation tant que i < nombre // boucle si nombre modulo i == 0 // expression typée retourne faux // expression typée i = i + 1 retourne vrai // expression typée ``` # Algorithme de vérification qu'un nombre est premier (3/3) ## Algorithme naïf (une solution en C) ```C bool est_premier(int nombre) { int i; // i est un entier i = 2; // assignation i à 2 while (i < nombre) { // boucle avec condition if (0 == nombre % i) { // is i divise nombre return false; // i n'est pas premier } i = i + 1; // sinon on incrémente i } return true; } ``` . . . ## Exercice: Comment faire plus rapide? # Génération d'un exécutable - Pour pouvoir être exécuté un code C doit être d'abord compilé (avec `gcc` ou `clang`). - Pour un code `prog.c` la compilation "minimale" est ```bash $ gcc prog.c $ ./a.out # exécutable par défaut ``` - Il existe une multitude d'options de compilation: ```console $ gcc -O1 -std=c11 -Wall -Wextra -g prog.c -o prog -fsanitize=address ``` 1. `-std=c11` utilisation de C11. 2. `-Wall et -Wextra` activation des warnings. 3. `-fsanitize=…` contrôles d’erreurs à l’exécution (coût en performance). 4. `-g` symboles de débogages sont gardés. 5. `-o` défini le fichier exécutable à produire en sortie. 6. `-O1`, `-O2`, `-O3`: activation de divers degrés d'optimisation # La simplicité de C? ## 32 mots-clé et c'est tout ---------------- -------------- ---------------- --------------- `auto`{.C} `double`{.C} `int`{.C} `struct`{.C} `break`{.C} `else`{.C} `long`{.C} `switch`{.C} `case`{.C} `enum`{.C} `register`{.C} `typedef`{.C} `char`{.C} `extern`{.C} `return`{.C} `union`{.C} `const`{.C} `float`{.C} `short`{.C} `unsigned`{.C} `continue`{.C} `for`{.C} `signed`{.C} `void`{.C} `default`{.C} `goto`{.C} `sizeof`{.C} `volatile`{.C} `do`{.C} `if`{.C} `static`{.C} `while`{.C} ---------------- -------------- ---------------- --------------- # Déclaration et typage En C lorsqu'on veut utiliser une variable (ou une constante), on doit déclarer son type ```C const double two = 2.0; // déclaration et init. int x; // déclaration (instruction) char c; // déclaration (instruction) x = 1; // affectation (expression) c = 'a'; // affectation (expression) int y = x; // déclaration et initialisation en même temps int a, b, c; // déclarations multiples a = b = c = 1; // init. multiples ``` # Les variables (1/2) ## Variables et portée - Une variable est un identifiant, qui peut être liée à une valeur (un expression). - Une variable a une **portée** qui définit où elle est *visible* (où elle peut être accédée). - La portée est **globale** ou **locale**. - Une variable est **globale** est accessible à tout endroit d'un programme et doit être déclarée en dehors de toute fonction. - Une variable est **locale** lorsqu'elle est déclarée dans un **bloc**, `{...}`{.C}. - Une variable est dans la portée **après** avoir été déclarée. # Les variables (2/2) ## Exemple ```C float max; // variable globale accessible partout int foo() { // max est visible ici float a = max; // valide // par contre les varibles du main() ne sont pas visibles } int main() { // max est visible ici int x = 1; // x est locale à main { // x est visible ici, y pas encore // on peut par exemple pas faire x = y; int y = 2; } // y est détruite à la sortie du bloc } // x est à la sortie de main ``` <!-- TODO: quiz, compile, compile pas --> <!-- ```C int main() { global = 1; } // COMPILE PAS ``` ```C int main() { int global = 1; { printf("global = %d", global); } } // COMPILE ``` ```C int local; int main() { local = 1; { printf("local = %d", local); } } // COMPILE ``` ```C #include <stdio.h> int local = 0; int main() { int local = -1; { int local = 1; printf("local = %d\n", local); } } // COMPILE ``` --> # Quiz: compile ou compile pas? ## [Quiz: compile ou compile pas](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=501934) # Types de base (1/4) ## Numériques Type Signification (**gcc pour x86-64**) ---------------------------------- --------------------------------------------- `char`{.C}, `unsigned char`{.C} Entier signé/non-signé 8-bit `short`{.C}, `unsigned short`{.C} Entier signé/non-signé 16-bit `int`{.C}, `unsigned int`{.C} Entier signé/non-signé 32-bit `long`{.C}, `unsigned long`{.C} Entier signé/non-signé 64-bit `float`{.C} Nombre à virgule flottante, simple précision `double`{.C} Nombre à virgule flottante, double précision ---------------------------------- --------------------------------------------- **La signification de `short`{.C}, `int`{.C}, ... dépend du compilateur et de l'architecture.** # Types de base (2/4) Voir `<stdint.h>` pour des représentations **portables** Type Signification ---------------------------------- --------------------------------------------- `int8_t`{.C}, `uint8_t`{.C} Entier signé/non-signé 8-bit `int16_t`{.C}, `uint16_t`{.C} Entier signé/non-signé 16-bit `int32_t`{.C}, `uint32_t`{.C} Entier signé/non-signé 32-bit `int64_t`{.C}, `uint64_t`{.C} Entier signé/non-signé 64-bit ---------------------------------- --------------------------------------------- . . . ## Prenez l'habitude d'utiliser ces types-là! # Types de base (3/4) ## Booléens - Le ANSI C n'offre pas de booléens. - L'entier `0`{.C} signifie *faux*, tout le reste *vrai*. - Depuis C99, la librairie `stdbool` met à disposition un type `bool`{.C}. - En réalité c'est un entier: - $1 \Rightarrow$ `true`{.C} - $0 \Rightarrow$ `false`{.C} - On peut les manipuler comme des entier (les sommer, les multiplier, ...). # Quiz: booléens ## [Quiz: booléens](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=501922) <!-- TODO Quiz en ligne --> <!-- ```C if (42) { /* vrai */ } int x = 100; if (x == 4) { /* faux */ } if (x) { /* vrai */ } int x = 100; while (x−−) { /* répète tant que x est différent de 0 */ } if (0) { /* faux */ } if (i = 4) { /* vrai */ } if (i = 0) { /* faux */ } #include <stdbool.h> bool x = true; if (x) { /* vrai */ } ``` --> # Types de base (4/4) ## Conversions - Les conversions se font de manière: - Explicite: ```C int a = (int)2.8; double b = (double)a; int c = (int)(2.8+0.5); ``` - Implicite: ```C int a = 2.8; // warning, si activés, avec clang double b = a + 0.5; char c = b; // pas de warning... int d = 'c'; ``` # Quiz: conversions ## [Quiz: conversions](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=501925) <!-- TODO Quiz en ligne --> <!-- ```C int a = (int)2.8; // 2 double b = 2.85; int c = b + 0.5; // 3 int d = a + 0.5; // 2 bool d = 2.78; // 1 bool e = 1.0; // 1 ``` -->