Le fonctionnement d'un ordinateur

Objectifs

  • Découvrir les concepts théoriques à l'origine de l'informatique moderne ;

  • Comprendre le fonctionnement d'un ordinateur.

Contexte

Durée : 2h

Environnement de travail : Repl.it, terminal

Pré-requis : Aucun

L'informatique connaît depuis plusieurs décennies un essor fulgurant. Des objets connectés aux smartphones, les ordinateurs ont envahi chaque recoin de notre vie quotidienne.

L'enjeu de ce module sera de comprendre le fonctionnement de l'ordinateur moderne et de découvrir très simplement certaines bases théoriques sous-jacentes.

Nous verrons en particulier que tous les ordinateurs, de la simple montre connectée au serveur web, ont une architecture commune : l'architecture de von Neumann.

Un ordinateur dispose donc des éléments suivants :

  • des unités de calcul, les micro-processeurs ou CPU ;

  • des mémoires vives qui permettent de stocker temporairement l'information afin de la traiter ;

  • des périphériques d'entrées/sorties qui permettent d'interagir avec la machine (comme le clavier, la souris ou l'écran) ou encore de sauvegarder les données une fois la machine éteinte (comme le disque dur).

Nous verrons également que tous les ordinateurs ont en commun le modèle de la machine de Turing. Il s'agit d'un modèle de calcul automatisé qui a été créé par Alan Turing en 1936, avant même l'apparition des premiers composants électroniques.

La machine de Turing

Objectif

  • Découvrir ce qu'est une machine de Turing.

Mise en situation

L'ordinateur possède une base théorique qui sous-tend la majorité des développements scientifiques et technologiques en informatique : la machine de Turing.

Ce modèle a été imaginé par Alan Turing en 1936 afin de donner une définition rigoureuse de la manipulation automatique de l'information.

L'idée générale de ce modèle est qu'un acteur modifie ce qui est inscrit sur un ruban découpé en plusieurs cases, en appliquant des règles mécaniques, sans réfléchir. Par exemple une règle pourrait être : « si il y a un A dans la case que tu lis, alors écrit à la place Z et va à la case suivante ». Une telle machine pourrait servir à remplacer les A par des Z dans un texte.

FondamentalLa machine de Turing

La machine de Turing est un modèle abstrait du fonctionnement d'une machine (mécanique) à calculer (type ordinateur). Ce modèle pensé par Alan Turing permet d'apporter une définition précise au concept d'algorithme (appelé alors « procédure mécanique »).

Description d'une machine de Turing

Une machine de Turing est un objet abstrait composé de quatre éléments :

  • Un ruban infini divisé en cases contenant chacune un symbole issu d'une liste finie (un alphabet).

  • Une tête de lecture/écriture pouvant lire et écrire sur le ruban, et pouvant se déplacer vers la gauche ou la droite du ruban.

  • Un registre d'état qui retient l'état actuel de la machine. Pour un être humain faisant du calcul mental, on pourrait comparer cela au fait de retenir l'état d'avancement du calcul (par exemple les retenues).

  • Une table d'actions qui lie (en fonction de l'état courant) un symbole lu à une action à effectuer par la tête de lecture/écriture (déplacement et/ou écriture).

Machine de turing

États

Une machine de Turing possède un registre permettant de retenir son état. Il existe trois types d'états :

  • L'état initial : état lors du lancement de l'algorithme

  • Les états intermédiaires : états transitoires permettant de faire avancer le calcul.

  • Les états acceptants : états correspondant à une fin possible de l'algorithme

Démonstration

Pour mieux comprendre le concept de machine de Turing, voici une application Web qui simule très bien son fonctionnement.

Choisir le programme "Ajouter 1", entrer la valeur "1" comme valeur de départ et cliquer sur "Commencer".

Le ruban contiendra "10" en fin de programme (soit le nombre 2 en binaire). Le tableau en haut à droite fait office de table d'actions en ayant un curseur pointant sur l'état courant. Ce curseur est le registre d'état. L'alphabet est : 1, 0, VIDE.

Simulation d'une machine de Turing

Attention

Une telle machine peut sembler un peu simpliste mais les algorithmes les plus complexes ne sont qu'une succession d'un très grand nombre d'opérations de base.

FondamentalMachine de Turing universelle

Alan Turing nomme Machine de Turing universelle une machine de Turing capable de « simuler » n'importe quel autre machine de Turing. Dans la mesure où il est possible de construire une machine de Turing pour n'importe quel algorithme, machine de Turing universelle peut calculer tout ce qui est considéré comme calculable.

Pour ce faire, une machine de Turing universelle doit recevoir le « codage » de la machine de Turing simulée ainsi que ses données.

Un ordinateur peut être vu comme une machine de Turing universelle.

ComplémentAller plus loin que le calcul arithmétique

Ainsi, ce modèle abstrait proposé par Turing changea totalement la notion même de calcul. Avant lui, le mot calcul ne signifiait que calcul arithmétique (additionner, soustraire, etc.). Après Turing, la notion de calcul est redéfinie et englobe des opérations bien plus abstraites, englobant tous les algorithmes. Elle ouvre la voie à des domaines nombreux comme l'intelligence artificielle qui fut le sujet d'un de ses articles.

À retenir

  • Une machine de Turing est un modèle abstrait à l'origine de la notion d'algorithme.

  • Tout algorithme peut être représenté par une machine de Turing.

  • L'ordinateur s'apparente à une machine de Turing universelle pouvant exécuter tous les algorithmes.

Appliquer la notion

Simulation d'une machine de Turing

Voici une application simulant des machines de Turing. Comment calculer 5 × 4 avec cette application ?

Les programmes de l'application ne permettent que la multiplication par deux : il faut décomposer la multiplication.

5 × 4 peut aussi s'écrire (5 × 2) × 2, et 5 s'écrit 101 en binaire. Il faudra donc utiliser deux fois le programme.

  • La première utilisation du programme avec 101 en entrée produit le résultat 1010 (soit 10 = 1 x 2³ + 0 x 2² + 1 x 2¹ + 0 x 2⁰)

  • La première utilisation du programme avec 1010 en entrée produit le résultat 10100 (soit 20 = 1 x 2⁴ + 0 x 2³ + 1 x 2² + 0 x 2¹ + 0 x 2⁰)

Automates et diagramme états-transitions

Objectifs

  • Découvrir ce qu'est un automate ;

  • Savoir lire un diagramme de transition.

Mise en situation

Le concept de machine de Turing s'inscrit au sein de la théorie des automates. Un automate est un dispositif qui est capable de produire une série d'actions sans intervention humaine. Il est programmé pour produire ces actions. Une horloge est un exemple d'automate simple.

Un ordinateur est un automate qui est capable de recevoir plusieurs programmes différents. Il peut effectuer des actions très diverses, pas seulement donner l'heure, grâce à des périphériques puissants, comme l'écran.

FondamentalThéorie des automates

Un automate est un modèle mathématique permettant de réaliser des calculs, composé de plusieurs états. Le passage d'un état à un autre est conditionné par les données transmises à l'automate.

FondamentalDiagramme états-transitions

Un diagramme états-transitions permet de représenter les états d'un automate et les passages possibles d'un état à un autre.

  • Un état est représenté par un nœud (un cercle).

  • Un changement d'état est modélisé par une flèche accompagnée de la condition de ce changement.

Il est possible qu'une flèche pointe sur l'état dont elle vient lorsqu'une action ne modifie pas l'état.

ExempleAutomate très simple

Un portillon possède deux états : verrouillé et déverrouillé. On comprend que pousser une porte verrouillée ne la débloque pas mais qu'insérer un jeton si.

Automate de portillon

RemarqueMachine de Turing et automate

Une machine de Turing est un type avancé d'automate : le passage d'un état à un autre est conditionné par le symbole lu sur le ruban.

MéthodeComment lire le diagramme états-transitions d'une machine de Turing ?

Une machine de Turing étant un automate très particulier, son diagramme possède une particularité : la condition de changement d'état.

La condition de changement d'état est représentée par un triplet :

([symbole lu] ; [symbole écrit] ; [déplacement])

Exemple : la condition (1; 0; D) signifie que si la tête lit le symbole 1, il faut écrire le symbole 0 puis déplacer la tête de lecture/écriture vers la droite.

ExempleMachine très simple

Cette machine très simple lit la bande de gauche à droite et inverse le premier bit. La machine passe enfin de l'état de départ à l'état final.

À retenir

  • Une machine de Turing est un type d'automate.

  • Il est possible de représenter une machine de Turing grâce à un diagramme états-transitions.

Appliquer la notion

Que renvoie la machine de Turing correspondant au diagramme états-transitions ci-dessous lorsqu'on lui donne entrée la valeur 0110 ?

Que renvoie la machine de Turing correspondant au diagramme états-transitions ci-dessous lorsqu'on lui donne entrée la valeur 0110 ?

1001

On reste sur l'état de départ tant que la tête de lecture lit VIDE. On passe ensuite à l'état 1, sur lequel on reste tant qu'on lit une donnée. Chaque fois, cette donnée est inversée (lecture de 0 = écriture de 1, et inversement). Enfin, dès que la donnée est terminée, on passe à l'état final.

Architecture Von Neumann

Objectif

  • Connaître le modèle conceptuel à l'origine du fonctionnement des ordinateurs modernes.

Mise en situation

Tous les ordinateurs partagent un modèle de conception similaire, hérité de l'architecture de Von Neumann. Cette architecture repose en premier lieu sur une unité de calcul et de contrôle qui est capable de manipuler l'information. On peut voir cela comme le bureau où on réalise tous les opérations. L'unité de calcul ne traite qu'une petite quantité d'information à la fois, et seulement des nombres binaires, mais il fait cela très rapidement.

Ensuite, l'ordinateur est doté d'une mémoire vive qui permet de stocker une plus grosse quantité d'informations. C'est là que l'ordinateur dépose les résultats des calculs une fois effectués et où il prend les nouvelles données à traiter. On peut voir cela comme une armoire avec des casiers où l'on range les données.

Enfin, il y a les périphériques qui permettent d'interagir avec le monde.

Architecture de Von Neumann

Cette architecture est un modèle conceptuel décrivant le fonctionnement d'un ordinateur. Elle est utilisée par la quasi-totalité des ordinateurs.

Ce modèle se compose de quatre parties :

  • L'unité arithmétique et logique (UAL ou ALU en anglais),

  • L'unité de contrôle,

  • La mémoire,

  • Les entrées/sorties.

Schéma d'une architecture Von Neumann

L'unité arithmétique et logique

Ce composant est chargé de réaliser toutes les opérations de base : les opérations arithmétiques sur les nombres (addition, multiplication, etc.) et des opérations binaires (OR, AND, etc.).

ComplémentMasques logiques

Les masques logiques diffèrent de l'arithmétique sur les nombres. Ces masques travaillent sur la représentation binaire des données, et effectuent des opérations bit à bit. Une explication plus complète est disponible ici : https://fr.wikibooks.org/wiki/Les_op%C3%A9rations_bit_%C3%A0_bit/Les_masques.

L'unité de contrôle

Ce composant est chargé d'ordonnancer les instructions et d'envoyer tous les calculs à effectuer à l'unité arithmétique et logique.

La mémoire

Cette mémoire stocke à la fois les instructions et les données. D'un côté, elle sera utilisée par l'unité de contrôle pour stocker les séquences d'instructions. De l'autre, elle sera utilisé par l'ALU pour stocker les données d'entrée d'un calcul et le résultat.

Entrées/Sorties

Il s'agit de toutes les interfaces permettant d'interagir avec l'ordinateur. Classiquement un clavier peut être vu comme une entrée et un écran comme une sortie.

Exemple

Ordinateur portable ouvert

Sur cette image d'un ordinateur portable moderne, on observe bien l'architecture Von Neumann :

  • En rouge, l'unité de contrôle et l'ALU, dont l'ensemble forme un processeur,

  • En bleu, la mémoire (ici, RAM et SSD),

  • En vert, les périphériques (ici, USB et JACK).

L'écran et la clavier intégrés à l'ordinateur portable sont aussi des périphériques.

Processeurs et Architecture de Von Neumann

Les processeurs modernes (aussi appelé CPU, pour Central Processing Unit) regroupent l'unité de contrôle et l'ALU. Beaucoup de processeurs ont de multiples cœurs, c'est à dire plusieurs ALU.

ComplémentEn quoi est-il différent d'autres modèles ?

Une autre architecture très connue (mais moins répandue) existe : l'architecture Harvard. Elle se différencie de l'architecture de Von Neumann notamment par une séparation de la mémoire des instructions exécutée par la machine et de la mémoire de données.

À retenir

  • Les ordinateurs modernes utilisent l'architecture dite de Von Neumann.

  • L'architecture Von Neumann se compose en quatre parties : ALU, unité de contrôle, mémoire et entrées/sorties.

  • Avec les avancées technologiques récentes (processeurs multi-cœurs, etc.), ce modèle perdure tout en évoluant.

Appliquer la notion

Après avoir découvert l'architecture de Von Neumann, il est intéressant d'appliquer ce modèle en essayant de disséquer un smartphone. Le but de cet exercice sera de lier chaque partie de l'architecture à des composants électroniques d'un smartphone.

En cas de manque d'inspiration, il est possible de consulter le site mobilecellphonerepairing.com qui liste les composants classiques d'un smartphone.

GPS Processeur Écran Dalle tactile Carte SIM Carte SD Haut-parleur RAM Batterie Connecteur USB Vibreur
Aucune
ALU et unité de contrôle
Mémoire
Entrée
Sortie

Après avoir découvert l'architecture de Von Neumann, il est intéressant d'appliquer ce modèle en essayant de disséquer un smartphone. Le but de cet exercice sera de lier chaque partie de l'architecture à des composants électroniques d'un smartphone.

En cas de manque d'inspiration, il est possible de consulter le site mobilecellphonerepairing.com qui liste les composants classiques d'un smartphone.

Aucune
Batterie
ALU et unité de contrôle
Processeur
Mémoire
RAM Carte SD Carte SIM
Entrée
Connecteur USB Dalle tactile GPS
Sortie
Écran Vibreur Haut-parleur
  • L'architecture de Von Neumann est un modèle conceptuel qui est indépendant de toute solution technique. Ainsi, la source d'énergie permettant le fonctionnement de l'ordinateur n'est pas incluse dans le modèle.

  • Le processeur d'un smartphone (composé ou non de plusieurs cœurs) inclut la ou les ALU ainsi que l'unité de contrôle.

  • Les types de mémoire sont multiples dans un smartphone : RAM (mémoire vive), mémoire cache des processeurs (mémoire vive), disque dur (mémoire secondaire), carte SD (mémoire secondaire), carte SIM (mémoire secondaire).

  • Les entrées/sorties d'un smartphone sont également multiples : dalle tactile, touches, connecteur USB, microphone, GPS, antenne, gyroscope, accéléromètre, écran, haut-parleur, vibreur etc.

Mémoire vive et mémoire secondaire

Objectifs

  • Connaître la différence entre mémoire vive et mémoire secondaire ;

  • Découvrir la notion de swap.

Mise en situation

La mémoire secondaire est la mémoire de stockage de l'ordinateur. Elle conserve les données même si l'ordinateur est éteint. C'est par exemple le cas d'un disque dur.

La mémoire vive est la mémoire de travail de l'ordinateur. Pour exécuter un programme l'ordinateur doit copier les données depuis une mémoire de stockage vers la mémoire vive.

Le développeur doit comprendre ce principe d'architecture. En effet, les copies entre les mémoires de stockage et la mémoire vive sont des actions très lentes, chaque fois qu'on en fait, on ralentit le programme. Pour une application web cela peut vite devenir un goulot d'étranglement. À l'inverse la mémoire vive est souvent assez limitée en volume, il n'est donc pas possible de remonter trop d'information à la fois dans la mémoire de travail.

DéfinitionMémoire vive

La mémoire vive (ou RAM, pour Random Access Memory) est caractérisée par sa volatilité : les données s'effacent lors de l'extinction du système.

Elle contient les données des processus qui s'exécutent sur l'ordinateur et est constamment sollicitée par le processeur pour traiter ces données.

DéfinitionMémoire secondaire

La mémoire secondaire est caractérisée par sa non-volatilité : les données sont conservées même lorsque le système est éteint.

Elle est moins sollicitée pas le CPU et contient les fichiers et données des programmes qui ne sont pas utilisés.

Types de mémoire secondaire

Il existe plusieurs types de mémoire secondaire classées selon la possibilité de les modifier, comme par exemple :

  • ROM (pour Read-Only Memory) : ce type de mémoire n'est pas effaçable et est utilisé, par exemple, pour stocker les instructions de démarrage d'un ordinateur. Les données stockées sont enregistrées par le constructeur et ne pourront pas être altérées.

  • EEPROM (pour Electrically Erasable Programmable Read Only Memory) : ce type est le plus répandu - c'est celui des clés USB, des cartes SD, etc. La suppression et la modification des données est possible.

ExempleStockage de la mémoire secondaire

Les disques durs sont des exemples de mémoire secondaire.

Deux grandes familles se distinguent : les disques durs utilisant des variantes d'EEPROM - les SDD - et les disques durs à disques - appelés HDD.

On utilise improprement le nom de disque dur, même si seul ce deuxième type de disque historique correspond à cette appellation.

AttentionDépassement de pile

La mémoire vive étant limitée en taille, il peut arriver que des programmes essaient de stocker plus de données que ne le permet la mémoire vive. Lorsque cela arrive, on parle de dépassement de pile (ou stack overflow).

En tant que développeur, il faut faire attention à l'utilisation de la mémoire vive pour éviter que les programme ne dysfonctionnent. Avant le dépassement de pile, il peut également arriver que la vitesse d'exécution soit fortement ralentie.

La mémoire swap

Pour éviter le problème de dépassement de pile, certains systèmes d'exploitation placent des parties de la mémoire vive inutilisée sur la mémoire secondaire pour économiser la première.

Ce processus est appelé échange et on appelle swap la mémoire associée à ce procédé.

Si le processeur a besoin de données qui se trouvent dans le swap, un échange a de nouveau lieu. Cet échange est plus lent qu'un accès direct en RAM, mais en contrepartie de la mémoire vive aura pu être mieux utilisée.

DéfinitionMémoire virtuelle

La mémoire swap est étroitement lié au concept de mémoire virtuelle. La mémoire virtuelle est le regroupement de la mémoire vive et du swap.

RemarqueComparaison des temps d'accès mémoire

La mémoire vive a un temps d'accès en mémoire bien plus rapide que la mémoire secondaire.

À titre informatif, voici quelques exemples dans le tableau ci dessous.

Type d'accès mémoire

Temps en nano-secondes

Mémoire vive

100

Mémoire secondaire (HDD)

10 000 000

Complémentramfs pour accélérer ses programmes

ramfs est un système de fichiers temporaire, sur Linux, placé sur la RAM.

Cette pratique est intéressante lorsque le développeur souhaite accéder à un petit nombre de fichiers avec rapidité d'accès très haute. Il faut absolument limiter la taille des fichiers pour éviter le dépassement de pile. Une telle pratique peut accélérer significativement certaines opérations.

À retenir

  • La mémoire vive est dédiée à des données peu nombreuses qui nécessitent un accès rapide.

  • La mémoire secondaire est dédiée à des données potentiellement volumineuses qui ne nécessitent pas un accès immédiat.

  • La mémoire vive est limitée en taille et certains mécanismes optimisent son utilisation et évitent des dépassements de pile.

Appliquer la notion

Dans cet exercice on s'intéresse à différents logiciels et au type de mémoire qu'ils utilisent.

Le BIOS correspond au micrologiciel contenu dans la carte mère qui s'exécute au démarrage de l'ordinateur.

En utilisant cette article Wikipédia sur le BIOS, quel type de mémoire stocke le BIOS ?

Mémoire secondaire

Mémoire virtuelle

Mémoire vive

Redis est un système de gestion de bases de données non relationnelles très populaire.

Grâce à cette cet article Wikipédia, quels type de mémoire utilise Redis pour ses données?

Mémoire secondaire

Mémoire flash

Mémoire virtuelle

Mémoire vive

Le BIOS correspond au micrologiciel contenu dans la carte mère qui s'exécute au démarrage de l'ordinateur.

En utilisant cette article Wikipédia sur le BIOS, quel type de mémoire stocke le BIOS ?

Mémoire secondaire

Mémoire virtuelle

Mémoire vive

Le BIOS utilise une mémoire de type ROM, persistante sur le disque : c'est donc une mémoire secondaire.

Redis est un système de gestion de bases de données non relationnelles très populaire.

Grâce à cette cet article Wikipédia, quels type de mémoire utilise Redis pour ses données?

Mémoire secondaire

Mémoire flash

Mémoire virtuelle

Mémoire vive

Redis utilise prioritairement de la mémoire vive pour assurer un accès extrêmement rapide aux données. Cependant, il utilise également de la mémoire virtuelle (et donc de la mémoire secondaire via le swap) lorsque les données deviennent volumineuses.

Langage machine et assembleur

Objectifs

  • Découvrir le langage machine ;

  • Découvrir les bases de l'assembleur.

Mise en situation

Les développeurs écrivent des programmes dans des langages compréhensibles par les humains. Mais l'ordinateur travaille à un niveau différent, il manipule des séquences binaires.

Le langage le plus proche de la machine se nomme assembleur. C'est un langage qui permet des instructions très basiques. On l'utilise assez rarement car il est beaucoup plus efficace pour un être humain d'écrire dans un langage de haut niveau comme le C ou le JavaScript. D'autant qu'il existe des compilateurs ou des interpréteurs qui transforment ce code de haut niveau que l'on écrit en langage machine.

Mais il est néanmoins utile de comprendre les mécaniques de l'assembleur. Cela aide à comprendre certains concepts comme l'adressage mémoire. Et c'est utile pour programmer plus efficacement.

FondamentalCodage binaire

Un processeur ne comprend pas les langages de programmation. Il ne peut traiter que des instructions sous forme binaire, c'est-à-dire constituées de 0 et de 1. Un processeur ne traitera pas le nombre 42 mais la suite 00101010, qui est l'équivalent de 42 en codage binaire.

DéfinitionLe langage assembleur

L'assembleur est un langage compréhensible par le processeur. Il ne comporte que quelques instructions très simples (déplacer une donnée, multiplier, additionner, etc.), là où les langages de programmation classiques comportent des instructions plus complexes, correspondant à une combinaisons d'instructions en assembleur.

Les registres

Les registres sont des petites zones mémoire dans le processeur où sont stockées les variables d'entrée ou de sortie d'un calcul. Chaque processeur n'a que quelques registres nommés AX, BX, CX, DX, etc.

Leur taille étant extrêmement limitée, leur tâche est de stocker une donnée uniquement le temps du calcul (quelques fractions de secondes) et d'envoyer le résultat en mémoire vive par la suite, quitte à récupérer le résultat dans la mémoire vive pour un calcul ultérieur.

ExempleQuelques instructions de base

Chaque instruction assembleur a une équivalence binaire direct. Le processeur peut ainsi comprendre ces instructions.

Voici quelques exemples d'instructions de base pour le processeur Intel 8086 :

  • MOV destination source : déplace une valeur fixe ou celle d'un registre dans un autre,

  • INC registre : additionne 1 à la valeur d'un registre,

  • NEG registre : change le signe de la valeur stockée dans un registre,

  • IMUL destination source : multiplie les valeurs et stocke le résultat dans le premier registre.

AttentionTraduire un langage de programmation en langage machine

L'écriture d'un programme informatique ne se fait la plupart du temps pas en assembleur.

On utilise des langages dits de plus haut niveau qui sont eux-mêmes traduits automatiquement en assembleur par un autre programme :

  • le compilateur pour les langages compilés (comme C ou C++),

  • ou l'interpréteur pour les langages interprétés (comme JavaScript ou Python).

ComplémentToutes les machines ne parlent pas exactement le même langage

Tous les processeurs comprennent un langage binaire. Cependant, chaque type de processeur a son propre jeu d'instructions.

Par exemple, la plupart des ordinateurs ont des processeurs utilisant un jeu d'instructions étendu (dit CISC) alors que les smartphones ont des processeurs utilisant un jeu d'instructions réduit (RISC). Ainsi, un code dans un langage de programmation donné sera traduit différemment en fonction du processeur cible.

À retenir

  • Un processeur ne traite que des instructions binaires.

  • L'assembleur est un langage composé d'instructions basiques et facile à traduire en binaire.

  • Une instruction dans un langage de programmation donné correspond à de multiples instructions en assembleur.

Appliquer la notion

Ordonnez les instructions en assembleur basé sur l'architecture de l'Intel 8086 afin que le programme :

  • incrémente la valeur contenue dans le registre AX,

  • double cette valeur incrémentée,

  • stocke cette valeur doublée dans BX,

  • finisse en remettant à 0 la valeur contenue dans AX.

fr.wikipedia.org/wiki/Jeu d'instructions x86

MOV ax,0 IMUL ax,2 INC ax MOV bx,ax

Ordonnez les instructions en assembleur basé sur l'architecture de l'Intel 8086 afin que le programme :

  • incrémente la valeur contenue dans le registre AX,

  • double cette valeur incrémentée,

  • stocke cette valeur doublée dans BX,

  • finisse en remettant à 0 la valeur contenue dans AX.

fr.wikipedia.org/wiki/Jeu d'instructions x86

INC ax IMUL ax,2 MOV bx,ax MOV ax,0
INC ax
IMUL ax,2
MOV bx,ax
MOV ax,0

Complexité algorithmique

Objectif

  • Découvrir la notion de complexité algorithmique.

Mise en situation

Lorsqu'un développeur écrit un programme, il lui est nécessaire d'estimer si ce programme est coûteux. Coûteux cela signifie par exemple qu'il nécessite beaucoup de calculs de la part du processeur. Cela peut aussi signifier qu'il nécessite beaucoup d'espace mémoire.

Savoir calculer ce coût permet de comparer plusieurs solutions alternatives entre elles. Cela permet aussi de savoir si un programme peut « passer à l'échelle » c'est à dire continuer de fonctionner correctement si on le confronte à la réalité.

Par exemple si un développeur a écrit un programme permettant de vérifier une empreinte de carte de paiement, mais que cette vérification prend plusieurs minutes ou nécessite un ordinateur doté d'une mémoire très importante, il ne sera pas possible de l'utiliser pour du paiement en ligne.

ExempleCompter le nombre d'opérations pour résoudre un problème

Pour créer la table de 2 des n premiers entiers, il faut réaliser n calculs de type multiplication.

De manière générale, on cherche à estimer de manière théorique le nombre d'opérations à effectuer pour résoudre un problème : c'est ici que l'on parle de complexité d'un problème.

DéfinitionComplexité algorithmique

La complexité algorithmique est une estimation du nombre d'opérations élémentaires pour résoudre un problème en fonction de la taille des données d'entrée, notée n.

SyntaxeO()

On note O() l'ordre de grandeur de la complexité d'un algorithme.

  • O(n) signifie que le nombre d'opérations est de l'ordre de n (si on a 1000 données en entrée, on s'attend à environ 1000 opérations).

  • O(n²) signifie que le nombre d'opérations est de l'ordre de n au carré (si on a 1000 données en entrée, on s'attend à environ 1 000 000 d'opérations).

ExempleExemple simple

Ce code fait la somme d'une liste d'entiers.

function somme(number_list) {
  let res = 0;
  for (var i = 0; i < number_list.length; i++) {
      res += number_list[i];
  }
  return res;
}

Étant donné n la taille de la liste, il serait nécessaire d'effectuer n opérations d'addition pour obtenir la somme finale. Ici, on dira que la complexité de l'algorithme est de l'ordre de n et on la notera O(n).

RemarquePourquoi utiliser la complexité algorithmique ?

La complexité algorithmique peut se voir comme l'estimation du "temps d'exécution" d'un algorithme en fonction de la taille des données d'entrée.

On suppose pour ce faire que les opérations de base (affectation, addition, etc.) ont le même temps d'exécution : estimer le temps d'exécution revient alors à estimer le nombre d'opérations de base.

AttentionL'exécution reste proportionnelle à la taille des données

La complexité ne change pas en fonction de la taille des données. En revanche, l’exécution sera évidemment plus longue si la taille des données augmente. Ainsi, pour 100 données, un algorithme en O(n) effectuera de l'ordre de 100 opérations. Pour 1000 données il en effectuera de l'ordre de 1000.

MéthodeEstimer rapidement la complexité

La complexité permet d'avoir une idée grossière de la durée d'un algorithme. Par exemple, si on détermine que pour une liste de n éléments, il faut effectuer 2×n opérations, on simplifiera en disant que la complexité est de l'ordre de O(n).

La raison principale est que les constantes ne changent pas fondamentalement l'ordre de grandeur de la complexité. Par exemple, O(n²) et O(2×n²) sont très proches, et c'est surtout la valeur de n qui influencera la durée finale.

FondamentalComplexités usuelles des algorithmes

On retrouve très régulièrement les complexités suivantes :

  • O(1) : si le nombre d'opérations ne dépend pas de la taille des données. Par exemple, afficher le premier élément d'une liste.

  • O(n) : cette complexité se retrouve souvent quand on a besoin de parcourir les éléments d'une liste, par exemple pour calculer la somme des éléments.

  • O(n²) : par exemple, l'algorithme naïf pour trier une liste de nombre nécessite, pour chaque élément de la liste, de parcourir l'ensemble de la liste.

  • O(n×m) : par exemple, pour trouver les nombres communs de deux listes de taille n et m, il faut pour chaque nombre de la première liste parcourir l'ensemble de la deuxième liste pour vérifier s'il existe.

Complément

La complexité algorithmique permet de dire, qu'à tailles de données égales, un algorithme en O(n) terminera bien avant un second algorithme dont la complexité est O(n²).

Ainsi, pour 100 données, le premier algorithme effectuera environ 100 opérations de bases et le second 10 000 opérations. On comprend que, si la taille des données se compte en millions (ou même en milliards), le second algorithme sera beaucoup plus coûteux que le premier.

Comparaison des complexités

n

O(n)

O(n²)

10

10

100

100

100

10 000

1 000

1 000

1 000 000

10 000

10 000

100 000 000

ComplémentComplexité algorithmique en espace

Le temps de calcul est important mais l'espace nécessaire au calcul l'est aussi. La mémoire d'un ordinateur n'est pas infinie : il est utile d'estimer l'espace mémoire nécessaire pour exécuter un algorithme.

La complexité décrite jusqu'ici se nomme complexité en temps. Ici, on parle complexité algorithmique en espace. La notation sera toujours la même : O(1), O(n), O(n²), etc.

ComplémentComplexité et machine de Turing

Le concept de complexité algorithmique est étroitement lié aux machines de Turing, une des bases théorique des ordinateurs. Elles ont introduit une nouvelle définition de la notion de calcul qui permet également de théoriser sa complexité. Ainsi, aujourd'hui, on peut classer les problèmes de calcul selon la complexité des algorithmes pouvant les résoudre.

On peut distinguer, très schématiquement, trois grands types de problèmes :

  • Problème dont l'algorithme finira en un temps polynomial : O(n), O(n²), etc.

  • Problème dont l'algorithme finira en un temps exponentiel : O(2n), O(n!), etc. On évite que ce type d'algorithme car il suffit que n augmente un tout petit peu pour que le temps d’exécution se compte en mois, en années voire en siècles.

  • Problème dont il n'existe pas de solution (dits indécidables).

À retenir

  • Il est possible d'attribuer une complexité à un algorithme.

  • Estimer la complexité d'un programme permet d'avoir un ordre de grandeur de son temps d’exécution.

  • Comparer la complexité de deux algorithmes permet de déterminer lequel est le plus optimisé pour répondre à un problème donné.

Appliquer la notion

Soit le programme ci-après écrit en JavaScript qui utilise la fonction mystery qui prend en entrée une liste de nombres.

function mystery (numberList) {
  let max = numberList[0]
  for (var i = 1; i < numberList.length; i++) {
    if (max < numberList[i]) max = numberList[i]
  }
  return max
}
console.log(mystery([5, 7, 1, 0, 42, 3]))

La ligne commençant par for crée ce qu'on appelle une boucle : elle permet de parcourir la liste.

Cette fonction permet de trouver :

Le plus petit nombre présent dans la liste.

Le plus grand nombre présent dans la liste.

Quelle est la complexité de cette fonction ?

O(1)

O(n)

O(n²)

O(n³)

O(n⁴)

Cette fonction permet de trouver :

Le plus petit nombre présent dans la liste.

Le plus grand nombre présent dans la liste.

Quelle est la complexité de cette fonction ?

O(1)

O(n)

O(n²)

O(n³)

O(n⁴)

Sa complexité est O(n).

On pourrait dire O(2n) (voire O(4n) en comptant les affectations) pour être plus précis mais cela n'est pas nécessaire ; l'ordre de grandeur O(n) est plus instructif.

Essentiel

Tous les ordinateurs, que ce soit un portable, un poste de travail fixe, un serveur puissant, un téléphone ou même un simple objet connecté qui ne fait que compter des pas, sont construits selon un schéma similaire.

Ce sont des machines de Turing qui exécutent les instructions d'un programme pour modifier l'état d'une mémoire.

La conception technique des ordinateurs repose sur des micro-processeurs, une mémoire vive et des périphériques. Un programme est chargé de récupérer des données depuis les mémoires secondaires (les fichiers), afin de les traiter au sein de la mémoire vive, avant d'enregistrer à nouveau les données modifiées dans les mémoires secondaires.

Tous les programmes, quelque soit le langage dans lequel ils sont écrits (C, Java, Python, JavaScript, PHP) sont en fin de compte transformés en langage machine (ou assembleur). Mais il y a toujours plusieurs façons de résoudre un problème, et donc plusieurs suites d'instructions qui permettent de parvenir au même résultat. Et parmi celles-ci, certaines sont plus simples que d'autres. Le calcul de complexité permet de discriminer les solutions simples des plus coûteuses.

Quiz

Quiz - Culture

Alan Turing a construit une machine physique (nommée Machine de Turing) qui servit d'exemple par la suite.

Vrai

Faux

Lorsqu'on change la taille des données d'un algorithme, celui-ci conserve-t-il la même complexité ?

Oui

Non

L'architecture de Von Neumann partage-t-elle la mémoire pour les données et les instructions ?

Oui

Non

Les processeurs des ordinateurs modernes regroupent les parties suivantes de l'architecture de Von Neumann :

Unité arithmétique et logique

Unité de contrôle

Mémoire

Entrées/Sorties

Une machine de Turing est :

Un diagramme de transition

Un objet mathématique

Un automate

Un ordinateur respectant l'architecture de Von Neumann

Qu'est-ce qui sert à traduire le langage du programmeur en langage machine ?

Interpréteur

Compilateur

Assembleur

Necronomicon

Lequel de ces termes correspond à une optimisation (effectuée par le système d'exploitation) de la mémoire vive ?

swap

ramfs

ssh

Cloud computing

Quiz - Méthode

Que faut-il examiner en premier pour déterminer la complexité arithmétique d'un algorithme ?

La taille des listes de données

Les valeurs des listes de données

Le type d'opérations arithmétiques

L'espace mémoire occupé par les données

Voici le diagramme états-transitions d'une machine de Turing. Que fait cette machine ?

Elle inverse le premier bit de la donnée d'entrée

Elle inverse tous les bits de la donnée d'entrée

Elle inverse le dernier bit de la donnée d'entrée

Que renvoie la machine de Turing correspondant au diagramme états-transitions ci-dessous lorsqu'on lui donne entrée la valeur 1100 ?

Quiz - Code

Quelles instructions assembleur sont incorrectes ?

mov 1,2

inc ax, 1

add ax, bx

inc ax

Quiz - Culture

Alan Turing a construit une machine physique (nommée Machine de Turing) qui servit d'exemple par la suite.

Vrai

Faux

La Machine de Turing est un modèle mathématique permettant de formaliser la notion de calcul et d'algorithme. Sa structure même ne le rend pas possible à construire (ruban infini) même s'il est possible d'assimiler les ordinateurs modernes à des machines de Turing universelles.

Lorsqu'on change la taille des données d'un algorithme, celui-ci conserve-t-il la même complexité ?

Oui

Non

Il conserve en effet la même complexité algorithmique car celle-ci est exprimée en fonction d'un taille abstraite notée n.

L'architecture de Von Neumann partage-t-elle la mémoire pour les données et les instructions ?

Oui

Non

Les données et les instructions sont stockées au même endroit. C'est un des éléments qui sépare l'architecture de Von Neumann de l'architecture Harvard.

Les processeurs des ordinateurs modernes regroupent les parties suivantes de l'architecture de Von Neumann :

Unité arithmétique et logique

Unité de contrôle

Mémoire

Entrées/Sorties

Unité arithmétique et logique

Unité de contrôle

Mémoire

Cette réponse peut également être valable si on considère les « caches » des processeurs modernes qui confèrent une mémoire très petites aux processeurs.

Entrées/Sorties

Une machine de Turing est :

Un diagramme de transition

Un objet mathématique

Un automate

Un ordinateur respectant l'architecture de Von Neumann

Une machine de Turing est un objet mathématique : elle peut être représentée par un diagramme de transition mais ça n'est pas un diagramme de transition, ni un ordinateur.

Qu'est-ce qui sert à traduire le langage du programmeur en langage machine ?

Interpréteur

Compilateur

Assembleur

Necronomicon

Interpréteur

Pour les langages interprétés comme le Python ou le JavaScript.

Compilateur

Pour les langages compilés comme le C/C++

Assembleur

Il s'agit du langage machine lui-même et non pas l'outil qui opère la traduction.

Necronomicon

Lequel de ces termes correspond à une optimisation (effectuée par le système d'exploitation) de la mémoire vive ?

swap

ramfs

ssh

Cloud computing

swap

ramfs

Ce mécanisme permet de stocker des fichiers directement dans la mémoire vive. Ceci peut optimiser un calcul mais pas l'usage de la mémoire vive. Au contraire, cela augmente la charge sur la mémoire vive.

ssh

Il s'agit d'un protocole de communication avec un serveur distant.

Cloud computing

D'une part le cloud computing est effectué par un tiers et non par le système d'exploitation lui-même. D'autre part, il ne s'agit pas d'optimiser la mémoire vive mais de sous-traiter le calcul.

Quiz - Méthode

Que faut-il examiner en premier pour déterminer la complexité arithmétique d'un algorithme ?

La taille des listes de données

Les valeurs des listes de données

Le type d'opérations arithmétiques

L'espace mémoire occupé par les données

Les opérations arithmétiques sont considérées comme étant réalisées en un temps constant. Ni les valeurs effectives ni les opérations n'ont donc d'impact dans le calcul de la complexité arithmétique.

C'est la quantité de données qui détermine la quantité d'opérations et permet de connaître la complexité.

Elle inverse le premier bit de la donnée d'entrée

Elle inverse tous les bits de la donnée d'entrée

Elle inverse le dernier bit de la donnée d'entrée

Le mieux pour s'en rendre compte est de choisir un mot et de suivre le diagramme.

L'analyse permet de constater que la tête de lecture se déplace à droite sans rien modifier jusqu'à arriver à la fin du mot, tant qu'elle rencontre des 0 et des 1.

À la fin du mot, quand la tête de lecture rencontre une case vide, elle se déplace à gauche, pour opérer.

Que renvoie la machine de Turing correspondant au diagramme états-transitions ci-dessous lorsqu'on lui donne entrée la valeur 1100 ?

0010
  • Le premier caractère (1) fait passer dans l'état 2, produit un 0 et se déplace à droite.

  • Le deuxième caractère (1) fait rester dans l'état 2, produit un 0 et se déplace à droite.

  • Le troisième caractère (0) fait passer dans l'état 3, produit un 0 et se déplace à droite.

  • Le dernier caractère (0) fait rester dans l'état 3, produit un 0 et se déplace à droite.

  • La donnée est finie, la tête de lecture rencontre une case vide, on arrive dans l'état final.

La machine de Turing représentée par ce diagramme états-transitions ajoute un caractère à la donnée d'entrée.

Quiz - Code

Quelles instructions assembleur sont incorrectes ?

mov 1,2

inc ax, 1

add ax, bx

inc ax

mov 1,2

Il est nécessaire d'avoir un registre comme destination du déplacement de données.

inc ax, 1

Le principe de l'incrémentation est d'ajouter 1 à un entier. Il n'est donc pas nécessaire d'ajouter une valeur après le registre à incrémenter.

add ax, bx

inc ax

Liste des raccourcis clavier

Liste des fonctions de navigation et leurs raccourcis clavier correspondant :

  • Bloc Suivant : flèche droite, flèche bas, barre espace, page suivante, touche N
  • Bloc Précédent : flèche gauche, flèche haut, retour arrière, page précédente, touche P
  • Diapositive Suivante : touche T
  • Diapositive Précédente : touche S
  • Retour accueil : touche Début
  • Menu : touche M
  • Revenir à l'accueil : touche H
  • Fermer zoom : touche Échap.