La mémoire
Présentation
Le développement en Java ne nécessite pas de connaissances particulières sur la manière dont est organisée la mémoire et sur la manière de stocker différents types d’information dans celle-ci. Néanmoins, la connaissance de la mémoire permet d’une part de mieux comprendre pourquoi certaines choses fonctionnent d’une certaine façon et pas d’une autre. D’autre part, la connaissance du fonctionnement de la mémoire permet de produire des algorithmes astucieux et performants.
Java est un langage multiplateforme. Pour cela, il fonctionne avec une machine virtuelle appelée machine virtuelle Java (JVM). Pour chaque plateforme, une machine virtuelle est créée, permettant de traduire les instructions du programme. Cela est réalisé à la volée, c’est le côté interprété de Java. Néanmoins, pour obtenir des performances meilleures, ce n’est pas directement le code Java qui est interprété. Le code Java est traduit en langage intermédiaire bytecode Java par l’opération de compilation. Java est donc un langage hybride : il est tout d’abord compilé en bytecode, ce qui produit des fichiers .class, puis ces fichiers sont interprétés au moment de l’exécution par la machine virtuelle Java.
Dans...
Les bases
1. Les nombres entiers
a. Les bases utilisées en informatique
En tant qu’humains, nous utilisons dix chiffres différents (0, 1, 2, 3, 4, 5, 6, 7, 8 et 9). En les combinant, nous sommes capables de créer beaucoup plus que dix valeurs différentes.
Nous utilisons donc la base dix appelée également base décimale.
Les ordinateurs sont binaires, c’est-à-dire qu’ils ne connaissent que deux chiffres : 0 et 1. Néanmoins, il existe également une infinité de combinaisons de ces deux chiffres. Il s’agit de la base deux appelée également base binaire.
Enfin, une troisième base est utilisée en informatique, il s’agit de la base seize appelée également base hexadécimale. Elle possède seize chiffres : 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E et F. L’avantage de cette base est qu’elle est très proche de la base deux en étant quatre fois plus concise. Il suffit de grouper la valeur binaire en groupes de quatre chiffres et d’utiliser le chiffre correspondant en base seize :
base 2 |
base 16 |
0000 |
0 |
0001 |
1 |
0010 |
2 |
0011 |
3 |
0100 |
4 |
0101 |
5 |
0110 |
6 |
0111 |
7 |
1000 |
8 |
1001 |
9 |
1010 |
A |
1011 |
B |
1100 |
C |
1101 |
D |
1110 |
E |
1111 |
F |
Considérons par exemple la valeur 1010111011010101110. Celle-ci est découpée en groupes de 4 chiffres en partant de la droite : 101 0111 0110 1010 1110. Le dernier groupe n’est constitué que de trois chiffres, mais il est possible de rajouter devant un zéro sans changer la valeur (cela se nomme un zéro non significatif). Ensuite, chaque groupe est remplacé par la valeur correspondante :
0101 -> 5 |
0111 -> 7 |
0110 -> 6 |
1010 -> A |
1110 -> E |
Ainsi, la valeur en binaire 1010111011010101110 correspond à la valeur 576AE en base hexadécimale. Ce qui est plus court et lisible, vous en conviendrez. C’est pour cette raison que la base hexadécimale est utilisée en informatique.
b. Notation
Un nombre n dans une base b est noté (n)b. Par exemple, (576AE)16 correspond à 576AE en base seize. La base dix étant notre base naturelle, il n’est pas nécessaire de la préciser 1548 = (1548)10.
Soit un nombre en base B constitué des chiffres cn…c1c0. Ce nombre peut être décomposé de la manière suivante :...
Les nombres entiers
Maintenant que vous maîtrisez les bases, intéressons-nous à la manière utilisée par l’ordinateur pour stocker des nombres. Commençons par le plus simple : les nombres entiers.
1. Les octets
a. Les bits et les octets
En binaire, chaque chiffre (0 ou 1) constituant un nombre est appelé un bit. La valeur 1010111011010101110 est un nombre constitué de 19 bits.
Les ordinateurs regroupent les bits par paquets de huit. Chaque paquet est appelé un octet. Ainsi, la valeur précédente utilise trois octets :
00000101 01110110 10101110
Cette manière de procéder permet d’avoir une unité plus appropriée et est bien adaptée pour la base seize, puisque chaque octet est représenté par deux chiffres hexadécimaux.
Exemple :
05 76 AE
La traduction du mot octet en anglais est byte. Attention à ne pas confondre byte et bit !
b. Les multiples
Pour des unités que nous connaissons mieux, le gramme par exemple, il existe des préfixes correspondant à des coefficients multiplicateurs afin d’éviter d’avoir des nombres trop grands. Par exemple, le poids d’une voiture est exprimé en kilogrammes et non en grammes.
Il existe des préfixes multiplicateurs également pour les octets. Néanmoins, comme les octets sont des valeurs en base deux, ce ne sont pas des multiples de mille qui sont utilisés, mais des multiples de 210, c’est-à-dire 1024. Ce qui est la puissance de deux la plus proche de 1000.
Voici les préfixes multiplicateurs :
Nom |
Symbole |
Valeur |
kibioctet |
Kio |
210 |
mébioctet |
Mio |
220 |
gibioctet |
Gio |
230 |
tébioctet |
Tio |
240 |
pébioctet |
Pio |
250 |
exbioctet |
Eio |
260 |
zébioctet |
Zio |
270 |
yobioctet |
Yio |
280 |
Parfois, vous entendez parler de kilooctets. Soit cela correspond à 1000 octets, soit cela est un abus de langage correspondant à Kibioctet.
2. Les entiers naturels
Les entiers naturels sont les nombres entiers positifs ou nuls, c’est-à-dire ceux trouvables dans la nature : il peut y avoir deux arbres, un arbre, aucun arbre, c’est-à-dire zéro, mais il ne peut pas y avoir -2 arbres !
Pour coder ces valeurs, les ordinateurs utilisent directement la valeur en base deux codée avec le nombre d’octets souhaité....
Les nombres réels
Tout comme pour les entiers, il existe une infinité de nombres réels. La différence est que pour les entiers compris entre deux valeurs, il n’existe qu’un nombre fini d’entiers, alors que pour les nombres réels, il existe toujours une infinité de nombres réels entre deux valeurs. Sur un ordinateur, il est donc impossible de coder tous les nombres réels, même compris entre deux bornes. Il peut donc y avoir un arrondi qui est effectué.
1. La forme normalisée
En base dix, un nombre réel peut être représenté sous sa notation scientifique. Cela consiste à transformer la valeur afin qu’elle soit de la forme suivante :
±m × 10exp
où ± correspond au signe et m est une valeur comprise entre un (compris) et dix (non compris). La valeur m s’appelle la mantisse. Afin que la mantisse soit comprise dans cet intervalle, il est nécessaire de décaler la virgule. Ainsi, le décalage de la virgule vers la gauche de n positions oblige à ajouter une multiplication par dix puissance n pour conserver la même valeur. Un décalage de n positions vers la droite nécessite l’ajout d’une multiplication par dix puissance -n.
Exemple :
-98745663,45 = -9,874566345 × 107 |
0,0001254 = 1,254 × 10-4 |
En base deux, il est également possible de mettre un nombre sous sa notation scientifique. Celle-ci est appelée forme normale. Il est nécessaire que la mantisse soit de la forme 1,…
Exemple :
(0,000101101)2 = (1,01101)2× 2-4 |
(-110111100000)2 = (-1,101111)2 × 211 |
2. La norme IEEE-754
Cette norme définit la représentation utilisée par les ordinateurs pour les nombres réels. Les valeurs mises sous leur forme normale possèdent trois informations : le signe, la mantisse et l’exposant. Ce sont ces trois informations qui sont stockées en mémoire.
Exemple :
La norme IEEE 754 propose différents formats, dont deux sont utilisés en Java comme dans la plupart des langages de programmation :
-
la simple précision, utilisant 32 bits (4 octets), est celle utilisée par le type float ;
-
la double précision, utilisant 64 bits (8 octets), est celle utilisée par le type double.
Dans le cas de la simple précision...
Les caractères
Pour coder les caractères, l’idée est d’associer à chaque caractère un nombre entier naturel. Il est ensuite possible de représenter ce nombre sous forme d’une représentation binaire comme cela a été présenté à la section Les entiers naturels de ce chapitre.
Par exemple, à l’entier 65, il est possible d’associer le caractère A. 65 = (1000001)2 = (41)16. Ainsi, pour coder le caractère A, dans la mémoire, il y aura la valeur 41.
1. Le code ASCII
La table ASCII (American Standard Code for Information Interchange) a été créée à cet effet. Ainsi, les caractères utilisés par les Américains ont été positionnés dans cette table afin d’avoir un encodage pour ceux-ci.
Voici la table ASCII :
Pour connaître l’encodage utilisé pour un caractère, il faut additionner la valeur de la ligne avec la valeur de la colonne. Par exemple, pour le caractère M, il faut additionner la valeur 40 avec la valeur 0D. Ainsi, le caractère M est codé 4D en ASCII. La valeur obtenue est directement en hexadécimal, ce qui simplifie le travail !
À l’observation de cette table, plusieurs éléments sont à remarquer. Tout d’abord, les deux premières lignes peuvent sembler étranges puisqu’elles ne sont pas réellement des caractères, mais des caractères de contrôle (retour à la ligne, sonnerie, retour arrière…).
Ensuite la troisième ligne commence par le caractère espace, suivi de caractères spéciaux (caractères de ponctuation et caractères mathématiques). La quatrième ligne contient les dix chiffres, suivis d’autres caractères spéciaux. Les cinquième et sixième lignes contiennent les lettres majuscules dans l’ordre de l’alphabet et d’autres caractères spéciaux. Il en est de même pour les deux dernières lignes pour les lettres minuscules de l’alphabet. Enfin, il est à noter qu’il n’y a pas les caractères accentués, le c avec cédille et les caractères entrelacés (œ et æ). L’ASCII n’a été...
Les différentes zones mémoire
La mémoire de la machine virtuelle Java est répartie en différentes zones mémoire. Pour les variables, il y a deux zones qui interviennent : la pile et le tas. Il y a également le registre compteur de programme permettant à la machine virtuelle de connaître l’instruction en cours d’exécution et la zone des méthodes contenant le code des classes avec leurs méthodes, leurs constantes et leurs attributs de classe.
1. La pile
Les variables de type valeur (boolean, byte, short, int, long, char, float et double) sont stockées directement sur la pile. Les valeurs sont stockées les unes à la suite des autres dans l’ordre dans lequel elles ont été déclarées. Lorsqu’un bloc se termine, les variables qui ont été déclarées à l’intérieur de celui-ci sont détruites. Plus précisément, l’espace est considéré comme disponible et, lors de l’écriture des prochaines variables, leur valeur est écrasée. Les variables sont ainsi "empilées" et "dépilées" au fil des créations de variables et des fins de blocs. C’est pour cette raison que cette partie de la mémoire s’appelle la pile.
Exemple :
private static void testVariablesEtBlocs() {
// 1
char car;
// 2
int a = 27897;
// 3
if(a<Math.sqrt(Integer.MAX_VALUE)) {
int c = a*a;
// 4
System.out.printf("le carré de %d est %d%n", a, c);
}
// 5
car = 'H';
final int TABLE = 4;
// 6
System.out.printf("table de %d :%n", TABLE);
for (int i = 1; i < 10; i++) {
int res = i*TABLE;
// 7
System.out.printf("%d × %d = %d%n", i, TABLE, res);
}
//8
System.out.println("car = " + car);
}...
Exercices
1. Conversion d’une base à une autre
a. Convertir les valeurs suivantes en base 10
(10011000)2 |
(11011011)2 |
(1010101)2 |
(EF)16 |
(B7)16 |
(3C)16 |
b. Convertir les valeurs suivantes en base 2 et en base 16
99 |
187 |
238 |
c. Convertir les valeurs suivantes en base 16
(1010)2 |
(1111)2 |
(10101111)2 |
(1011101101)2 |
d. Convertir les valeurs suivantes en base 2
(C)16 |
(8)16 |
(C8)16 |
(3FE)16 |
e. Convertir les valeurs suivantes en base 10
(0,01101)2 |
(11010, 11)2 |
(1011,1011)2 |
f. Convertir les valeurs suivantes en base 2
132,38 |
47,08 |
1222,77 |
2. Algorithme de conversion
Écrire un algorithme qui convertit un nombre en base 10 dans une base choisie par l’utilisateur en utilisant la méthode des divisions successives.
Affichage et saisies possibles :
Nombre à convertir : 157 |
Base d’arrivée : 2 |
10011101 |
3. Codage de valeurs en byte, short et int
a. Comment sont codées les valeurs suivantes en byte ?
-120 |
99 |
-38 |
b. Comment sont codées les valeurs suivantes en short ?
-1204 |
947 |
-785 |
c. Comment sont codées les valeurs suivantes en int ?
2035684248 |
-74 |
-1147514632 |
4. Codage de valeurs en float
a. Quelles valeurs sont codées par les octets suivants ?
CA 3A C0 CA |
3C DC BA 98 |
b. Comment sont codées les valeurs suivantes en float ?
758,75 |
-0,076171875 |
5. Unicode
À partir de la table des points de code Unicode https://en.wikipedia.org/wiki/Plane_(Unicode), décoder la chaîne suivante, codée en UTF-8 :
D0 B2 30 E1 BC A4 F0 9D 95 81 E1 84 8B 55 C2 AE
Comment cette même chaîne de caractères se code-t-elle en UTF-32 et en UTF-16 ?
Correction des exercices
1. Conversion d’une base à une autre
a. Convertir les valeurs suivantes en base 10
(10011000)2 = 1 × 27 + 1 × 24 + 1 × 23 = 128 + 16 + 8 = 152 |
(11011011)2 = 1 × 27 + 1 × 26 + 1 × 24 + 1 × 23 + 1 × 21 + 1 × 20 = 128 + 64 + 16 + 8 + 2 + 1 = 219 |
(1010101)2 = 1 × 26 + 1 × 24 + 1 × 22 + 1 × 20 = 64 + 16 + 4 + 1 = 85 |
(EF)16 = 14 × 161 + 15 × 160 = 224 + 15 = 239 |
(B7)16 = 11 × 161 + 7 × 160 = 176 + 7 = 183 |
(3C)16 = 3 × 161 + 12 × 160 = 48 + 12 = 60 |
b. Convertir les valeurs suivantes en base 2 et en base 16
99 = (1100011)2 |
187 = (10111011)2 |
238 = (11101110)2 |
99 = (63)16 |
187 = (BB)16 |
238 = (EE)16 |
c. Convertir les valeurs suivantes en base 16
(1010)2 = (A)16 |
(1111)2 = (F)16 |
(10101111)2 = (AF)16 |
(1011101101)2= (2ED)16 |
d. Convertir les valeurs suivantes en base 2
(C)16 = (1101)2 |
(8)16 = (1000)2 |
(C8)16 = (11011000)2 |
(3FE)16 = (1111111110)2 |
e. Convertir les valeurs suivantes en base 10
(0,01101)2 = 1 × 2-2 + 1 × 2-3 + 1 × 2-5 = 0,25 + 0,125 + 0,03125 = 0,40625 |
(11010, 11)2 = 1 × 24 + 1 × 23 + 1 × 21 + 1 × 2-1 + 1 × 2-2 = 16 + 8 + 2 + 0,5 + 0,25 = 26,75 |
(1011,1011)2 = 1 × 23 + 1 × 21 + 1 × 20 + 1 × 2-1 + 1 × 2-3 + 1 × 2-4 = 8 + 2 + 1 + 0,5 + 0,125 + 0,0625 = 11,6875 |
f. Convertir les valeurs suivantes en base 2
132,375
Partie entière :
Partie décimale :
132,375 = (10000100,011)2 |
47,076171875 = (101111,000100111)2 |
1222,7705078125 = (10011000110,1100010101)2 |
2. Algorithme de conversion
Algo convertirB10versBx
# Convertit un nombre écrit en base 10 en une autre base
Variable n, base : entier
Début
n <- saisir("Nombre à convertir : ")
base <- saisir("Base d'arrivée : ")
écrire("Conversion avec la méthode des divisions successives")
convertirB10versBxDiv(n, base)
écrire()
Fin
Procédure afficher(chiffre : entier)
# Affiche un chiffre dans une base < 36
Début
...