Programmation/Abstraction
Un programme à son niveau le plus fondamental est une suite de 0 et de 1, que le système interprète grâce au processeur qui effectue les opérations correspondantes : lecture et écriture de données (mémoire, fichier, ...), calculs, transfert de données, ...
Mais entre les composants électroniques au cœur du système et le mode de pensée du cerveau humain, il y a une succession de couches développées tout au long de l'histoire informatique destinées à traduire dans sa globalité nos pensées (abstraites) en instructions (concrètes) au sein de ce système de manière fiable et intuitive.
Le bit.
Le terme bit est la contraction du terme anglais binary digit (nombre binaire). En électronique numérique les signaux et les composants ne peuvent généralement se stabiliser que sur 2 états, habituellement 0 et 5 volts, auxquels on attribue arbitrairement la valeur 0 pour l'un et 1 pour l'autre. Ainsi, les composants informatiques rassemblent des millions de transistors qui ne peuvent fonctionner que selon une "logique à deux états". Pour simplifier si on applique une tension de valeur binaire 1 à un transistor, celui-ci laisse passer le courant, si on lui applique une tension correspondant à la valeur binaire 0, il bloquera le courant. Le rôle des transistors est, rappelons-le, de contrôler le courant afin de l'utiliser précisément là où on en a besoin. Le courant lui même, s'il véhicule une information est bi-stable (stable sur deux états).
De même pour la représentation et stockage de données, toute image, toute information doit d'abord être convertie en une succession de 0 et de 1 pour que l'information puisse circuler dans les systèmes électroniques d'abord, puis stockée ou rendue.
Notion de "mot binaire".
Un mot binaire est un ensemble de bits qui sera interprété par le microprocesseur ou stocké dans une mémoire. Ces mots sont quantifiés par le nombre de bits que peut contenir un mot binaire. Par exemple 10110101 est un mot de 8 bits. Par définition un mot binaire de 8 bits est appelé octet. Cette façon d'assembler ces bits rend plus rapide le traitement et la circulation des données dans un calculateur. Chaque organe du calculateur est relié par un bus de données où circulent ces mots binaires de façon parallèle.
Notion de poids.
En base 10 (décimal) le nombre 2453 est composé de différents chiffres ayant des valeurs différentes. Le 3 représente les unités, le 5 les dizaines, le 4 les centaines et le 2 les milliers. On peut dire que le 2 sur ce nombre en base 10 a plus de valeur (poids) que le 3.
En binaire c'est pareil : dans 100101010, le 1 est appelé MSB pour Most Signifiant Bit qui est le bit représentant le poids le plus fort du mot. Ainsi le 0 est appelé LSB pour Least Signifiant Bit le bit à la valeur la plus faible.
Représentation des nombres.
Historiquement on a utilisé les ordinateurs pour manipuler des nombres décimaux, autrement dit pour faire des calculs. Le bit étant lui même un nombre, la conversion entre un nombre décimal (en base 10) en un nombre binaire (en base 2) peut se faire avec des procédures relativement simples.
La notion de base arithmétique.
Dans un système numérique « basé », chaque chiffre d'un nombre est multiplié par la valeur de sa base, valeur qui elle-même est mise à une puissance correspondant à sa position dans le nombre par rapport au séparateur « décimal » (la virgule selon la norme française, le point selon la norme britannique).
Ainsi le nombre en base 10
formula_1
veut dire
formula_2
c'est à dire
formula_3
ou encore
formula_4
Le binaire pur.
Pour savoir à quoi correspond formula_1 en base 2 (c'est à dire savoir à quoi ressemble une telle quantité dans une suite de chiffres compris entre 0 et 1) on modifie la base de calcul d'abord.
Ainsi en binaire, formula_1 voudrait (improprement) dire
formula_7
Sauf que 7, 6, 5... ne sont pas des chiffres binaires à proprement parler. En décompte décimal on reporte une unité sur la rangée suivante lorsqu'on arrive à 9, en binaire on le fait dès qu'on arrive à 1, c'est à dire que 0 en base 10 correspond bien à 0 en base 2, de même que 1 en base 10 correspond bien à 1 en base 2 ; mais 2 en base 10 correspond à 10 en base 2 (si vous avez suivi), et ainsi de suite 3 correspond à 11, 4 à 100, 5 à 101... À titre indicatif voici le tableau de correspondance en binaire des 9 chiffres décimaux :
Mais un 7 à la deuxième rangée d'un nombre décimal est fondamentalement différent d'une quelconque équivalence binaire à 7 à la même rangée. Le 7 de la base 10 est le résultat de 70 groupements de 10, on voit donc que si le groupement n'était pas fait sur une base 10, on n'aurait tout simplement pas de 7 ici : traduire un chiffre « basé » en tant que tel n'a tout simplement pas de sens mathématiquement parlant (bien que cela puisse en avoir informatiquement parlant comme on le verra plus loin). Il faut au contraire savoir combien de groupements de 2 peut on faire avec 765, en suivant un décompte binaire. Le moyen le plus rapide est d'effectuer des divisions successives par 2 en retenant la présence d'une partie fractionnée.
Ainsi
formula_8 
formula_9 
formula_10 
formula_11 
formula_12 
formula_13 
formula_14 
formula_15 
formula_16 
formula_17 
finalement formula_18 pour la partie entière. Mais comment représenter la partie fractionnée ?
La virgule idéale, fixe et flottante.
Dans le meilleur des mondes la fraction est bien une subdivision d'une unité, où plus on monterait dans les rangées, plus la subdivision serait précise. À strictement parler on représenterait la partie fractionnaire suivant la même logique que la partie entière, c'est à dire qu'à chaque fois qu'on descend d'une rangée dans le nombre, on réduit la puissance.
Ainsi en base 10
formula_19 veut dire formula_20 donc formula_21, 
formula_22 veut dire formula_23 donc formula_24, ...
Et en base 2
formula_19 veut dire formula_26 donc formula_27,
formula_22 veut dire formula_29 donc formula_30, ...
Ainsi pour convertir une partie fractionnée, on décompose la fraction en correspondances entre subdivisions décimales et binaires.
Donc avec formula_1 pour trouver le correspondance binaire de formula_32 on y soustrait toutes les équivalences possibles en veillant à ne pas dépasser la valeur recherchée. Ainsi formula_33.
Une autre manière est de multiplier récursivement la partie fractionnée par 2 en reportant la partie entière résultante dans le nombre binaire.
Ainsi
formula_1 vaut donc en binaire approximativement 1011111101,011011... Il s'agit d'un nombre à fraction continue vu que ce que représente 765,432 en base 10 ne peut être représenté que par approximations successives en base 2.
On voit que pour la partie fractionnée des nombres, la notion de base est elle même biaisée. Par exemple si on voulait stocker la valeur réelle de formula_35 en base 10, il faudrait théoriquement un disque dur infini pour contenir tous les chiffres de la fraction récurrente (0,333333...). En base 3 la valeur réelle de formula_35 serait 0,1 et un simple Ruban perforé suffirait.
Pour éviter de générer des approximations qui n'existaient pas dans une base précédente, on adopte donc une solution plus pragmatique pour manipuler et stocker ce qui se trouve « après la virgule ». Dans un environnement binaire il est de toutes façons impossible de représenter autre chose qu'un 0 ou un 1, donc à fortiori les notions de virgule, de fraction, de signe et de tout autre symbole graphique que l'on grave sur du papier sont obligatoirement abstraits.
En informatique la virgule est en réalité une « étiquette » que l'on place dans une suite de chiffres finis dont les valeurs sont absolues. formula_37 valant 3,33333333333... devient donc 333333333333 (très exactement 12 « trois », ni un de plus, ni un de moins) et on déclare d'une manière ou d'une autre qu'après le premier chiffre se trouve le séparateur entre partie entière et fractionnée. La notion de subdivision disparait, on ne garde que les valeurs brutes de chaque chiffre composant le nombre, dans les limitations du matériel qui ne permettra jamais de stocker toutes les décimales d'un nombre irrationnel par exemple.
Dans le cas d'un nombre à « virgule fixe » la virgule peut soit ne simplement pas être stockée en mémoire. C'est au programmeur seul qu'incombe la tâche de déclarer la présence d'une virgule entre deux chiffres de ce nombre. C'est le rôle notamment de l'indicateur « V » utilisé en COBOL par exemple. Ou bien le nombre peut être enregistrée sous une forme dite "décimale codée binaire" (ou DCB), qui décompose le nombre binaires en chiffres et leur associe à chacun soit un quartet en DCB condensé, soit un octet en DCB étendu. Sachant que 4 bits sont nécessaires pour représenter tous les chiffres décimaux, cela veut dire qu'en étendu 4 bits vides seront consommés pour chaque chiffre stocké. Il est donc rapidement apparu la nécessité de trouver un moyen moins gourmand en ressources pour traiter les « nombres à virgules ».
Une solution fut d'utiliser le principe de nombre à « virgule flottante ». On y considère tous les chiffres comme un seul nombre appelé "mantisse" qui sera converti en binaire (dans sa valeur globale, et non chiffre par chiffre) et stocké dans un jeu de valeurs. La puissance à laquelle la base est élevée (grossièrement la position de la virgule), appelée "exposant", est stockée dans un autre jeu de valeurs. Enfin un dernier jeu de valeurs indique le signe du nombre (un simple bit qui à 0 caractérise un nombre positif, à 1 un nombre négatif). L'ordonnancement de ces jeux de valeur varie selon la norme IBM ou IEEE (la première stocke le signe puis l'exposant puis la mantisse ; la deuxième stocke l'exposant puis le signe puis la mantisse).
Ce mécanisme de séparation décimale est majoritairement utilisé par les langages de programmation et permet de stocker des nombres allant de formula_38 à formula_39 environ. Les mots-clés "real" en PASCAL, "float" en C par exemple sont utilisés pour demander un stockage sous cette forme. Mais il faut néanmoins un processeur taillé sur mesure pour traiter les nombres à virgule flottante, et encore de nos jours il peut arriver qu'un constructeur en fasse l'économie et utilise le mécanisme à virgule fixe.
Les valeurs signées.
Comme dit précédemment les deux seules choses concrètes que peut représenter un système informatique sont les deux états stables qu'on fait correspondre à 0 et 1. La notion de signe doit donc également être abstraite.
On l'a vu, avec les nombres flottants le signe est stocké dans un jeu de valeurs dédié. En DCB on utilise soit un quartet supplémentaire dans le cas du condensé, soit les 4 bits vides de l'octet le moins significatif dans le cas de l'étendue. Le signe est codé 0000 pour le signe + et 1111 pour le signe - (ou l'inverse), mais plus souvent 1011 pour le + et 1101 pour le - : 1011 et 1101 valant respectivement B et D en hexadécimal, sachant que les valeurs 2B et 2D codent respectivement les caractères + et - en ASCII.
Mais le système DCB est extrêmement gourmand en ressources, si bien que lorsqu'on veut représenter le signe d'un entier naturel sans aller jusqu'à utiliser les ressources demandées par un nombre à virgule flottante, on réserve un seul bit au sein du mot pour représenter le signe, et tous les autres bits pour stocker la valeur absolue du nombre. On utilise par convention le bit de poids le plus fort et on considère que si il vaut 0 le nombre est positif, sinon le nombre est négatif.
Ainsi avec un octet
 0 0 0 0 0 0 1 0
vaut 2 tandis que
 1 0 0 0 0 0 1 0
vaut -2
Pour utiliser ou non ce mécanisme les langages à typage statique utilisent des mots clés ; codice_1 et codice_2 pour le C par exemple.
Le système hexadécimal.
Comme on l'a vu dans le tableau représentant les correspondances entre les chiffres décimaux et leur valeur en binaire toutes les combinaisons possibles de 4 bits ne sont pas présentes avec le système décimal (à savoir 1010, 1011, 1100, 1101, 1110 et 1111). C'est pour pallier ce manque que le système hexadécimal a été créé : il regroupe toutes les valeurs que peuvent prendre un quartet (groupe de 4 bits). Ainsi une plage de chiffres binaires découpées en blocs successifs de 4 bits peut devenir « lisible » tout en prenant moins de place à être représentée. Pour désigner les quartets manquants on a choisi arbitrairement les 6 premières lettres de l'alphabet.
Le système hexadécimal couvre donc toutes les combinaisons de 4 bits possible entre 0000 et 1111.
Astuces de conversion entre bases.
Le nombre d'états en fonction du nombre de bits est calculé par la formule 2n.
Le bit le plus à droite est de poids faible. Le bit Le plus à gauche est celui de poids fort.
Pour convertir un nombre binaire en décimal, il suffit d'additionner chaque poids des bits à 1.
Exemple :
De la base 2 (binaire) vers la base 10 (décimal) :
 10010101 -> 1 * 128 + 0 * 64 + 0 * 32 + 1 * 16 + 0 * 8 + 1 * 4 + 0 * 2 + 1 * 1
 -> 128 + 16 + 4 + 1
 -> 149
De la base 2 (binaire) vers la base 16 (hexadécimal) :
 1001 0101 -> 95
La conversion de la base binaire vers la base hexadécimale est plus facile que vers la base décimale. C'est la raison pour laquelle la base hexadécimale est beaucoup plus utilisée que les autres.
Il est également possible d'utiliser la base 8 (23) c'est à dire la base octale, où les bits sont regroupés par 3 ; ou toute autre base puissance de 2 (base 64 ou 128 pour encoder les fichiers binaires dans un texte, base 32, ...).
Représentation des données.
Cependant les ordinateurs ne sont pas de simples calculatrices : ils peuvent afficher du texte, des images, des animations... autant de types de données qui demandent des codes de conversion entre leur existence binaire et leur restitution à l'écran.
Au contraire des nombres qui peuvent être convertis entres différentes bases de manière équivalente et absolue (du moins en théorie), les informations non numériques demandent l'usage d'un code de communication qui fixe arbitrairement les correspondances entres les informations et leur équivalent numérique. Pour que l'émetteur et le récepteur puissent se comprendre, il est nécessaire que chacun utilise le même code : la nécessité de standardisation est donc primordiale ici. Il y a de nombreux exemples de standards de communication tout au long de l'histoire, du Morse au code Popham, du code Baudot au code Fieldata. Nous ne nous arrêterons que sur ceux qui sont effectivement utilisés dans le cadre de l'informatique, et plus précisément ceux qui sont rencontrés par les programmeurs.
Texte.
L'esprit humain retient mieux des bouts de textes que des suites de chiffres, si bien que même dans les endroits les plus arides de l'informatique on en a tendance à en mettre partout : dans les codes source des programmes pour les rendre plus lisibles, dans les bulles d'aide, les interfaces... L'ordinateur est également utilisé pour contenir des documents écrits, qu'on a rédigé au moyen d'un clavier ou numérisé avec un scanner et un logiciel ocr. Une fois numérisée il devient possible de modifier le texte, de l'imprimer, de le dupliquer à l'infini...
ASCII.
Pour restituer un texte, la quasi-totalité des système informatiques utilisent le standard ASCII, ou un dérivé de celui-ci. Constitué en 1963 puis complété en 1967 il permet de coder sur 7 bits l'alphabet latin sans les diacritiques, en majuscules et en minuscules, les 10 chiffres du système décimal, des caractères de ponctuation, des symboles mathématiques et financiers ($%&), et des codes de contrôle destinées à superviser la communication.
ISO 646 et ISO 8859.
L'ascii se trouva rapidement limité pour représenter les caractères accentués et autres symboles non américains. L'ISO 646 fut la première tentative pour augmenter le nombre de caractères codables mais elle posa des problèmes d'incompatibilité car le système restait basé sur 7 bits, ne créant pas de nouveaux codes mais réassignant ceux existants, les codes de contrôle servant à définir quel jeu de caractères s'appliquait à tel morceau de texte. Mais ces codes étaient souvent omis, ou bien les traitements de texte n'étaient pas conçus pour les prendre en charge si bien qu'un programmeur non américain était dès lors souvent confronté à :
codice_3
au lieu de 
codice_4
L'autre solution adoptée fut d'utiliser un bit supplémentaire afin d'obtenir 128 combinaisons supplémentaires (l'ascii n'utilise que 7 bits). La norme ISO 8859 propose 16 jeux de caractères différents couvrant chacun un ensemble linguistique plus ou moins local : l'ISO 8859-1 pour les langues européennes occidentales, l'ISO 8859-5 pour le cyrillique, l'ISO 8859-11 pour le thaï... l'ISO 8859-15 ajoute le support du symbole Euro (€) et de quelques diacritiques manquantes du français (Œ, œ, et Ÿ).
Cependant devant l'extension mondiale de l'informatique et la limitation d'un système à 8 bits qui ne permet pas d'utiliser par exemple plusieurs alphabets différents dans un même document, l'ISO travaille depuis 1988 à l'élaboration d'un code universel : l'Unicode.
L'Unicode (ISO 10646).
L'Unicode définit actuellement plus de caractères en utilisant jusqu'à 31 bits pour chacun.
L'UTF-8 (Unicode Transformation Format - 8 bits) permet d'encoder les caractères par groupe de 8 bits (un octet). Le nombre de bits employé pour chaque caractère est fonction de son numéro. Il existe 6 plages, la première occupant 1 octet, la dernière en utilisant 6. La première plage se reconnaît à ce que le premier bit de l'octet est positionné à 0, les 7 bits suivants respectent la norme ASCII. Un caractère Unicode de cette plage est donc de la forme 0xxxxxxx et se trouve entièrement compatible avec un système ASCII. Les plages suivantes se reconnaissant à ce que le bit de poids fort de chaque octet est positionné à 1, les bits de poids fort du premier octet permettent de connaître la plage (110xxxxx pour la plage à deux octets, 1110xxxx pour celle à 3, 11110xxx pour 4, 111110xx pour 5 et 1111110x pour 6), et les deux bits de poids fort des octets suivant sont systématiquement positionnés à 10 afin d'indiquer leur appartenance à une suite d'octets Unicode. Un caractère de la deuxième plage est donc de la forme suivante : 110xxxxx 10xxxxxx ; et propose donc 11 bits utiles, ce qui permet formula_40 caractères différents.
Images.
L'image est une ressource beaucoup moins souple que le texte.
Sons.
Le son est représenté par un signal analogique. Pour le numériser, on l'échantillonne :
Le signal est enregistré sous forme numérique selon deux principales méthodes :
Certains changements de niveau sonore ne sont pas perceptibles par l'oreille humaine. Les codages µ-Law et A-Law exploitent cette propriété pour encoder les niveaux en utilisant moins de bits.
Paradigmes.
Un paradigme en programmation est la manière dont le programmeur conçoit son ouvrage pour que celui-ci corresponde à ses besoins. Un programme peut être conçu comme une simple suite d'instructions où le but est d'effectuer un traitement sur une ressource donnée en fonction d'un environnement donné. On parle alors de "programmation impérative" car le programme est une suite d'instructions précises fournies par l'auteur qui manipulent des objets simples comme des chiffres, des images ou des caractères. 
Cependant les besoins de l'informatique ont amené la nécessité de pouvoir agir sur des objets plus complexes, comme le pointeur de la souris présente dans l'interface graphique des systèmes d'exploitation tels que Windows, MacOS ou Linux et de pouvoir par exemple agir dessus depuis plusieurs sources dans le cas d'un réseau ou d'agir dessus d'une manière qui dépende davantage de l'environnement crée par l'utilisateur lorsqu'il déplace la souris, appuie sur une touche du clavier… que de la succession d'évènements planifiées par le programmeur.
Ainsi ces différentes manières d'appréhender la programmation influent directement sur la manière dont la discipline est enseignée, et sur la manière dont les programmes sont conçus et fabriqués.
Code source.
Le code source d'un programme est ce que le programmeur rédige avec ses propres moyens ou avec l'assistance d'un éditeur de programme. Il est soit compilé, soit interprété. Pour cette raison, le code doit être rédigé dans un langage qui soit à la fois compatible avec le compilateur ou l'interpréteur (respecter la syntaxe), mais également compréhensible par un être humain (lisibilité, présentation, commentaires), en utilisant les caractères familiers (lettres, chiffres, ponctuation) plutôt que des caractères étendus (caractères de contrôles, caractères spéciaux).
Technologies de langages.
Il existe de très nombreux langages de programmation différents qui obéissent chacun à une syntaxe et à une logique propres. Certains langages sont conçus pour être accessibles et pédagogiques, d'autres pour être efficaces et fiables, d'autres pour être rapides à l'exécution. Selon le programme que l'on souhaite réaliser, le choix du langage peut être un critère décisif.
Langage machine.
Il s'agit du niveau d'abstraction le plus bas que peut appréhender le programmeur, si on excepte les premiers ordinateurs où un groupe de personnes salariées modifiaient elles-mêmes le contexte électronique de l'ordinateur selon les instructions qu'on leur communiquait. Il s'agit d'une suite de que comprend le . Par exemple l'équivalent binaire de la suite de chiffres telle que codice_5 peut être comprise par le processeur comme la douzième instruction parmi les actions préimplantées par le constructeur que peut effectuer le processeur appliquée à l'élément situé à l'adresse numéro 3 du support visé par le processeur. De fait chaque instruction en langage machine correspond à une et une seule action du processeur et de fait l'augmentation de l'abstraction des langages de programmation correspond à l'augmentation du nombre d'actions du processeur correspondant à une instruction.
Langages assemblés.
Ce langage est une traduction mot à mot du langage machine en une suite d'instructions dont le premier mot est un mot mnémotechnique de l'opération effectuée, suivi des opérandes, c'est à dire des paramètres de l'opération. Ce langage est donc également spécifique à un modèle de processeur.
La traduction est assurée par un programme d'assemblage appelé un .
Les langages assembleurs les plus évolués ont des fonctionnalités supplémentaires comme l'utilisation de labels pour les sauts, les adresses de variables, ce qui évite de calculer l'adresse exacte à utiliser ; l'utilisation de pseudo-instructions traduits en une séquence d'instructions équivalente,
encore appelées ; ou encore la définition de sections de code, de sections de données, afin d'organiser le programme en blocs spécialisés.
Langages de haut niveau.
Les langages de haut niveau sont soit des langages compilés, soit des langages interprétés.
Ils permettent de s'abstraire davantage voire complètement de l'implémentation bas niveau et de programmer sans trop se soucier de l'architecture cible. Le code source produit ne peut être interprété directement par la machine qui a besoin d'un compilateur le traduisant en langage compréhensible par la machine, ou d'un interpréteur exécutant les instructions directement.
Différentes générations de langages haut niveau ont été créées :
Technologies d'exécution.
Selon le langage, le code source rédigé par le programmeur peut être exécuté de différentes manières par l'ordinateur.
Langages interprétés.
Le code source d'un langage interprété est traduit en langage machine de manière éphémère lors de son exécution par un programme interpréteur qui lit le code source instruction après instruction et effectue la conversion à la volée. Un langage interprété est donc portable sur divers types de plateformes à condition qu'elles possèdent un interpréteur pour ce langage qui sache convertir le code source en langage machine compatible avec la plateforme.
Certains langages interprétés modernes (Java, C#, et les autres langages .Net) possèdent un semi-compilateur traduisant le programme en un langage plus proche des machines en général. C'est-à-dire un langage pour une machine virtuelle dont l'interprétation par une machine concrète demande moins d'effort que l'interprétation directe.
Langages semi-interprétés.
Également appelés langages semi-compilés, ils se caractérisent par une étape de compilation rapide du code source produisant du "bytecode" qui est ensuite exécuté par l'interpréteur de manière plus rapide que si il avait à interpréter le code source directement. Ces langages autorisent des possibilités inédites comme la modification du code source à la volée lors de l'exécution du programme et généralement une très grande abstraction des contraintes imputées à la programmation système, en pâtissant de performances moindres en terme de vitesse par rapport aux langages compilés. Ce sont les langages apparus le plus récemment.
Langages compilés.
Un langage compilé définit une syntaxe qui lui est propre et indépendante du processeur. Cette syntaxe peut permettre l'utilisation d'instructions plus complexes, de structures de code (condition, boucle), de structures de données complexes (tableaux, structures, listes, …) et peut fournir des types de données plus évolués (chaînes de caractères, dates, ...).
Un programme dans un tel langage nécessite une phase de compilation pour valider la syntaxe et effectuer la traduction en langage machine. Cette phase est assurée par un compilateur qui traduit le programme pour un ou plusieurs modèles de processeur particuliers.