next up previous contents index
suivant: 3. Classes d'objets monter: 2. Variables et instructions précédent: 2.7 Un exemple :   Table des matières   Index


2.8 Représentation des valeurs primitives

De façon informelle, les types permettent de classifier les données manipulées par les programmes : caractères, entiers, flottants, tableaux, etc. Les données, c'est ce qui occupe la mémoire ; c'est ce qui est modifié, selon le point de vue impératif. Cette classification a au moins un intérêt, qui est de pouvoir interpréter et utiliser correctement ces données, alors qu'elles sont représentées en mémoire, de façon uniforme, par des suites de 0 et de 1. Par exemple, la même suite de 0 et de 1 doit être interprétée différemment selon qu'il s'agit d'un nombre entier ou d'un nombre flottant. De plus, ce ne sont pas les mêmes opérations qui seront exécutées sur des entiers ou sur des flottants : ce sont des « unités fonctionnelles » différentes du microprocesseur qui exécuteront une addition sur des entiers et une addition sur des flottants. Cette notion de type est commune à tous les langages : c'est le typage des données. En Java, ce typage répartit les données en deux grandes catégories : les données primitives et les objets.


2.8.0.0.1 Types entiers

Java, comme la plupart des langages, ne dispose pas d'un type primitif représentant des entiers de taille quelconque, mais de quatre types entiers de taille fixe : byte (un octet), short (deux octets), int (quatre octets), long (huit octets), le plus courant étant int. Ce sont tous des types d'entiers signés (c'est-à-dire positifs ou négatifs).

Quand un type entier est codé sur $N$ bits, $2^N$ entiers peuvent être représentés. Pour des types non-signés, on peut ainsi représenter l'intervalle $[0, 2^N-1]$ ; la suite de bits $b_{N-1}\ldots b_{0}$ représente l'entier $b_{N-1}2^{N-1} +\ldots + 2^1 b_{1} + b_{0}$. Pour des types signés, les entiers dans l'intervalle $[-2^{N-1},
2^{N-1}-1]$ sont représentables ; les entiers $\ge 0$ sont représentés de la même façon que dans le cas non-signé et l'on a $b_{N-1} = 0$ ; les entiers $<0$ sont représentés en complément à deux et l'on a $b_{N-1} = 1$; cela signifie que $b_{N-1}\ldots b_{0}$ représente l'entier $-b_{N-1}2^{N-1} + b_{N-2}2^{N-2} +\ldots + 2^1 b_{1} +
b_{0}$ ; par exemple 111..1$_2$ représente $-1$.

La notation décimale peut être utilisée pour noter les valeurs de type int ; un L (ou un l, moins lisible) doit être suffixé pour représenter une valeur de type long : 12 est un int, et 12L est un long.


2.8.0.0.2 Opérations bit à bit

Pour manipuler directement l'écriture binaire d'un entier, on utilise les opérateurs suivants :

Ces opérations sont utilisées pour travailler sur les bits de la façon suivante :

et aussi dans les cas fréquents suivants où elles accélèrent le programme :


2.8.0.0.3 Types flottants

Les flottants sont des représentations en mémoire d'une partie des nombres rationnels ; il est évidemment impossible de représenter des nombres réels quelconques, pour des raisons de cardinalité. Seuls les rationnels dont la forme irréductible est $n/2^q$, peuvent avoir une représentation exacte ; les autres ont nécessairement une représentation approchée (par exemple, le nombre décimal $1/10$ a $0,00011\underline{0011}\ldots$ comme représentation en base 2, la partie soulignée étant répétée indéfiniment). Cette représentation fait l'objet de la norme IEEE 754, proposée par William Kahan (Turing Award 1989), publiée en 1985 et adoptée par la plupart des fabricants d'ordinateurs. Cette norme distingue deux niveaux de précision : simple (sur 4 octets) et double (sur 8 octets), qui sont implantés en Java par les types primitifs float et double. Il est souhaitable que le numéricien programmeur ait une idée de la représentation des flottants, sans qu'il doive nécessairement en connaître tous les détails.

Un nombre flottant est caractérisé par trois blocs de bits, qui déterminent respectivement son signe, son exposant et sa mantisse. Chacun de ses blocs est de taille fixe :

  simple précision double précision
taille 32 bits 64 bits
signe 1 bit, $b_{31}$ 1 bit, $b_{63}$
exposant 8 bits, $b_{30}\ldots b_{23}$ 11 bits, $b_{62}\ldots b_{52}$
mantisse 23 bits, $b_{22}\ldots b_{0}$ 52 bits, $b_{51}\ldots b_{0}$

La valeur d'un flottant $(s,e,m)$ est $(-1)^s \times f \times
2^e$, où, dans le cas de la simple précision :

Figure: Flottants
\begin{figure}\ \begin{center}
\ \leavevmode
\ \fbox{
\ \epsfig{file=fig/float.eps}
\ }\ \ \ \end{center}\ \end{figure}

Dans l'exposant, soustraire 127 permettrait de représenter le plus petit exposant, $-127$, par les bits 0000 0000 et le plus grand exposant, $128$, par les bits 1111 1111 ; $2^0$ est par exemple représenté par 0111 1111. En fait, 0000 0000 et 1111 1111 ont des significations spéciales, pour représenter 0, $+/- \infty$, et NaN (c'est-à-dire Not a Number) ; les exposants extrêmes des flottants normalisés sont donc $-126$ (environ $10^{-38}$, par 0000 0001) et $127$ (environ $10^{38}$, par 1111 1110). La valeur de la mantisse étant toujours $1+\ldots$, zéro n'est pas représentable dans ce schéma ; par convention, le bit de signe suivi de 31 bits nuls représentent la valeur $(-1)^s\times 0$ (et non $(-1)^s\times 2^{-127}$)2.3. Si les bits d'exposant valent 1, et les bits de mantisse valent 0, la valeur est $(-1)^s \infty$, qui est obtenue dans le cas d'une division par 0. Enfin, si les bits d'exposant valent 1, et les bits de mantisse ne sont pas tous nuls, la valeur est NaN, qui peut être obtenue comme le résultat d'opérations illicites, comme $0/0$ , $\log (-1)$, ou $\infty-\infty$.

Bien que portant les mêmes noms (addition, multiplication), les opérations flottantes ne sont pas ces opérations mathématiques et n'ont pas les mêmes propriétés. Par exemple, l'addition n'est pas associative : on peut vérifier que $(10000003.0 -10000000.0)+7.501 = 10.501$, tandis que $10000003.0 + (-10000000.0 +7.501) = 11.0$. Autre exemple : la série $1.0+1.0+1.0+\cdots$ converge !

Les valeurs de type double peuvent être notées avec un signe, un point décimal et un exposant optionnel, par exemple -2.3e+4. Pour le type float, la constante doit être terminée par F (ou f) : 3.141592653 est un double, 6.02e23F est un float.


2.8.0.0.4 Caractères

Les caractères sont représentés par les valeurs du type char, codé sur deux octets. La plupart des alphabets des langues occidentales peuvent être représentés dans un jeu de caractères codés sur un octet, mais un même jeu de caractères ne peut pas coder simultanément tous les alphabets existants ; dans un souci d'internationalisation, rendu nécessaire à cause de l'Internet, Java utilise deux octets pour coder les caractères : c'est le codage Unicode, qui autorise $2^{16} = 65\,536$ caractères.

Les constantes de type caractère sont notées entre deux apostrophes (en anglais single quote) : 'A', 'Z', 'a', ';', '4', etc. S'y ajoutent des caractères spéciaux comme '\n' pour le retour à la ligne et '\t' pour une tabulation.

2.8.0.0.5 Précédences

Compte-tenu de ces nouveaux opérateurs, la table définissant les précédences est la suivante ; les opérateurs sont rangés par lignes ; les opérateurs sur la même ligne ont la même précédence et sont associés comme indiqué dans la seconde colonne. Les opérateurs d'une ligne ont une précédence plus élevée que les opérateurs des lignes suivantes.


Opérateurs Associativité
() [] . gauche à droite
! ~ ++ - + $_{\mathsf{un}}$ - $_{\mathsf{un}}$ (type) droite à gauche
* / % gauche à droite
+ - gauche à droite
« » »> gauche à droite
< <= > >= gauche à droite
== != gauche à droite
& gauche à droite
^ gauche à droite
| gauche à droite
&& gauche à droite
|| gauche à droite
? : droite à gauche
= += -= /= %= &&= ||=  
&= ^= |= «= »= »>= droite à gauche


next up previous contents index
suivant: 3. Classes d'objets monter: 2. Variables et instructions précédent: 2.7 Un exemple :   Table des matières   Index
Rene' LALEMENT 2001-11-07