Types, constantes et variables
Les types intrinsèques
Le langage fortran 90 possède les types intrinsèques ou prédéfinis suivants :
– CHARACTER : chaîne de caractères 1
– LOGICAL : booléen
– types numériques :
– type numérique représenté exactement :
– INTEGER : entier
– types numériques représentés approximativement :
– REAL : réel en virgule flottante
– DOUBLE PRECISION : flottant en précision étendue (à éviter : lui préférer une variante de type déterminée de façon plus portable, grâce à l’attribut KIND, cf. 2.5.2, p. 15)
– COMPLEX : nombre complexe flottant
La représentation des types numériques
Les entiers sont représentés en mémoire de façon exacte, donc sans perte de précision, mais leur domaine est limité par le nombre de bits choisi pour les représenter.
Au contraire, les réels ne peuvent pas, en général, être représentés exactement en mémoire : c’est pourquoi on évitera les tests d’égalité sur les réels ; c’est aussi ce qui explique l’impossibilité d’appliquer à des expressions réelles des tests de type énumération de valeurs 2.
Pour plus de détail sur la représentation des nombres et l’implémentation des opérations arith-métiques, on consultera le chapitre 9 « Arithmétique des ordinateurs » de Stallings (2003).
Représentation des entiers
Si la représentation la plus courante des entiers positifs est celle de la base 10 (qui utilise 10 symboles de 0 à 9), la plupart des ordinateurs utilisent une représentation en base 2 ne nécessitant que 2 symboles (0 et 1) ; en réprésentation binaire, l’équivalent du chiffre de la représentation décimale est le bit. La représentation en octal (base 8) utilise les 8 symboles de 0 à 7 alors que la représentation hexadécimale 3 (base 16) utilise 16 symboles : 0,1, …, 9, A, B, …F.
Représentation des entiers positifs
La représentation des entiers positifs utilise des codes à poids dont les poids sont les puissances décroissantes de la base b.
n = q−1 où 0 6 pi < b (2.1)
pi bi
X
i=0
En fortran, un caractère est stocké dans une chaîne de type CHARACTER et de longueur 1, contrairement à ce qui se passe en langage C, où seul le type caractère est natif et les chaînes ne sont que des tableaux de caractères.
select case en fortran ou switch … case en C.
La base 16 a été utilisée sur certains calculateurs ibm
Réciproquement, les q coefficients pi peuvent être obtenus par des divisions entières successives par b : p0 est le reste de la division de n par b, p1 le reste dans la division par b2 , … Dans le cas où b = 2, chaque coefficient pi peut être représenté par un bit. Par exemple, pour l’entier 13 :
13 = 1 × 101 + 3 × 100 noté 1310 en base 10
13 = 1 × 23 + 1 × 22 + 0 × 21 + 1 × 20 noté 11012 en base 2
Si on consacre q bits à la représentation d’un entier positif, on peut couvrir le domaine [0, 2q − 1].
Représentation des entiers négatifs
Les entiers négatifs sont représentés habituellement avec le symbole complémentaire « − » qu’il va falloir traduire par un bit complémentaire appelé bit de signe en codage binaire.
En binaire, un entier relatif est donc représenté sur q + 1 bits. On choisit de coder le signe sur le bit de plus fort poids avec 0 pour les entiers positifs et 1 pour les négatifs. Mais si on codait simplement la valeur absolue en binaire de n sur les q bits restants, une opération arithmétique élémentaire comme l’addition entre entiers de signes différents ne s’effectuerait pas comme celle de deux entiers de même signe.
On choisit au contraire de réprésenter l’entier n négatif par un bit de signe à 1 suivi des bits du complément à 2q+1 de |n|, c’est-à-dire ceux de l’entier positif 2q+1 − |n|. On parle alors (abusive-ment) de complément à deux, obtenu en inversant tous les bits puis en ajoutant 1 avec perte de la retenue. L’arithmétique entière ainsi mise en œuvre fonctionne modulo 2q+1. Le domaine couvert va donc de −2q à 2q −1 (voir par exemple 2.2.3, page 12). Par exemple, les entiers codés sur 8 bits, soit 1 octet (q = 7) couvrent le domaine −27 = −128 à 27 − 1 = +127
Traditionnellement, comme en décimal, on range les bits par poids décroissant, le plus fort poids
gauche. Mais des variantes dans l’ordre de stockage 4 des octets ou des groupes de deux octets existent : on distingue les conventions little-endian où les octets de poids fort sont stockés en fin et big-endian où les octets de poids fort sont stockés en tête.
Représentation des réels en virgule flottante
Si on codait les réels en virgule fixe 5, la précision absolue de la représentation serait fixe ; mais la précision relative dépendrait de l’ordre de grandeur. Pour conserver une précision relative plus indépendante de l’ordre de grandeur, c’est-à-dire pour travailler avec un nombre fixe de chiffres significatifs, on préfère une représentation en virgule flottante 6, avec une mantisse, représentant la partie fractionnaire et un exposant (cf. (2.2), p. 10). Par exemple en base 10, avec 4 chiffres après la virgule, on peut comparer les deux représentations approchées (par troncature et non par arrondi, pour simplifier)
où
– s = ±1 est le signe ;
– e est un entier qualifié d’exposant ;
– la partie fractionnaire m est la mantisse.
Afin de choisir parmi les combinaisons de mantisse et d’exposant (par exemple 1, 23410−1 ; 0, 1234100 ou 0, 01234101 en décimal), on impose que la mantisse soit comprise entre 1/b inclus et 1 exclus soit p1 =6 0 (donc la deuxième combinaison en décimal).
Chaque variante du type réel (déterminée via le paramètre de codage KIND) est caractérisée par :
– un nombre q de symboles (chiffres décimaux en base 10 et bits en base 2) de la mantisse qui fixe la précision relative des réels ;
– un nombre de symboles pour l’exposant qui fixe le domaine de valeurs couvert.
Dans cette représentation, en décimal, les réels en virgule flottante sont répartis en progresssion arithmétique dans chaque décade avec un nombre fixe de valeurs par décade et un pas multiplié par 10 à chaque changement de décade. En binaire, c’est dans chaque octave (intervalle de type [2n, 2n+1[) qu’ils sont en progression arithmétique avec un nombre 2q−1 de valeurs par octave ; le pas double à chaque changement d’octave. (cf. Annexe C, p. 140 sur le codage ieee).
Domaine et précision des types numériques
Les nombres étant stockés sur un nombre de bits fixe, ne sont représentés que dans un domaine fini. De plus, seul le type entier permet une représentation exacte des valeurs numériques, alors que les nombres réels ne sont en général représentés en virgule flottante qu’approximativement 7.
Fonctions d’interrogation sur le codage des types numériques
Plusieurs fonctions intrinsèques 8 permettent de caractériser la représentation du type numé-rique de leur argument du point de vue :
– du nombre de digits utilisés pour le représenter : DIGITS(x) donne le nombre de symboles (c’est-à-dire de bits dans le cas usuel de la base 2) consacrés au stockage de la mantisse de x dans le type de x. Plus précisément :
– si x est un entier, DIGITS(x) est le nombre q de bits sur lesquels l’entier est stocké hors bit de signe. Il détermine donc le domaine couvert par ce type. Dans le cas entier, BIT_SIZE(x) rend le nombre total de bits utilisés pour le stocker (bit de signe inclus).
– si x est un réel en virgule flottante, DIGITS(x) est le nombre de bits (ici q) 9 sur lesquels est stockée sa mantisse. Il détermine alors la précision relative de la représentation de x.
– du domaine couvert par un type donné :
– HUGE(x), la plus grande valeur (entière ou réelle) représentable dans le type de x.
– TINY(x), la plus petite valeur absolue flottante représentable 10 dans le type de x.
– RANGE(x) qui donne :
– la puissance de 10 du plus grand entier défini dans le type de x s’il s’agit d’un entier : ainsi tout entier x tel que |x| 6 10r où r est la valeur de RANGE est représentable dans ce type et RANGE(x) = INT(LOG10(HUGE(x))
– la plus petite des valeurs absolues des puissances de 10 du plus petit et du plus grand des réels dans le type de x, si x est un flottant ; ainsi tout réel x s’écrivant sous la forme x= ± 0.????? 10k avec k entier et |k| 6 r où r est la valeur de RANGE, est représentable dans ce type ; RANGE(x) = INT(MIN(LOG10(HUGE(x)), -LOG10(TINY(x))))
– de la précision de la représentation en virgule flottante :
Plus précisément, ne peuvent éventuellement être exactement représentés que les rationnels dont le dénomina-teur est une puissance de la base, donc en pratique du type n/2p avec des contraintes sur n et p. Ainsi les entiers de valeur absolue assez faible, et certains nombres rationnels de dénominateur 2p sont représentés exactement en virgule flottante. En revanche la majorité des nombres décimaux, 0.1 par exemple, ne sont pas représentables exactement.
Seul le type et non la valeur de l’argument de ces fonctions d’interrogation a une importance.
Dans le cas d’une mantisse normalisée, son premier bit, toujours égal à 1, n’est pas stocké, ce qui permet gagner » un bit, mais il est pris en compte dans la fonction DIGITS.
On se limite ici aux représentations normalisées, cf. annexe C, page 140, sachant qu’il est possible de représenter des valeurs absolues plus petites au prix d’une perte de précision.
– PRECISION(x) donne le nombre de chiffres décimaux significatifs d’un réel du type de x.
– EPSILON(x) donne la plus petite valeur réelle positive qui n’est pas négligeable devant 1. dans le type de x. C’est la plus petite valeur positive qui, ajoutée à 1., donne le flottant successeur de 1. (le plus proche de 1. par excès, dans la représentation de x).
Si un entier i est stocké sur q+1 bits, BIT_SIZE(i) vaut q+1, DIGITS(i) vaut q et HUGE(i) vaut 2q − 1.
D’autres fonctions intrinsèques d’interrogation permettent de préciser la représentation des types numériques :
– RADIX(r) donne la base b (en général 2) employée dans la représentation (2.1) pour les entiers ou (2.2) pour les réels du type de r ;
– EXPONENT(r) rend un entier donnant l’exposant e de r de la représentation (2.2) ;
– FRACTION(r) rend un réel donnant la mantisse m de r de la représentation (2.2) ;
– NEAREST(r, s) rend le réel le plus proche de r mais distinct de r dans la représentation (2.2) selon la direction fixée par le signe de s (successeur ou prédécesseur de r) ;
– SPACING(r) rend la plus petite distance entre r et son voisin le plus proche ; (successeur ou prédécesseur sont en général à égale distance qui est le pas de la progression arithmétique des réels dans une octave, sauf si r est une puissance entière de 2).
Caractéristiques des types numériques prédéfinis
Les caractéristiques des types numériques prédéfinis dépendent à la fois du processeur et des compilateurs (souvent au travers d’options spécifiques). Le programme suivant affiche quelques caractéristiques des entiers et des réels par défaut.
PROGRAM precision_numerique
IMPLICIT NONE
INTEGER :: i ! type entier par défaut (en général 32 bits)
REAL :: r ! type réel par défaut (en général 32 bits)
WRITE(*,*) ’entiers par défaut, kind = ’, KIND(i)
WRITE(*,*) ’digits =’ , DIGITS(i), ’ huge = ’, HUGE(i), ’range = ’, RANGE(i)
WRITE(*,*) ’réels par défaut, kind = ’, KIND(r)
WRITE(*,*) ’digits = ’, DIGITS(r), ’ précision = ’, PRECISION(r), &
’epsilon = ’, EPSILON(r), ’ tiny = ’, TINY(r), &
’ huge = ’, HUGE(r) END PROGRAM precision_numerique
Types entiers par défaut Sur un processeur 32 bits, les entiers par défaut sont stockés sur 4 octets donc 31 bits pour la valeur absolue plus un bit de signe. La variante de type (KIND) des entiers représente généralement le nombre d’octets sur lesquels est codé cet entier 11.
Sur un processeur de type PC 64 bits, les entiers par défaut peuvent être stockés sur 8 octets, (même si ce n’est pas forcément la règle), donc 63 bits pour la valeur absolue plus un bit de signe. Des options de compilation permettent d’imposer les entiers sur 64 bits (cf. Annexe E.7.1 p. 155).
1 Introduction
1.1 Historique du fortran
1.2 Les étapes de mise en oeuvre d’un programme
1.3 Les éléments du langage
1.4 Les formats du fortran
2 Types, constantes et variables
2.1 Les types intrinsèques
2.2 La représentation des types numériques
2.3 Déclaration
2.4 Les constantes
2.5 Initialisation
2.6 Fonctions de conversion de type
3 Opérateurs et expressions
3.1 Les opérateurs numériques
3.2 Les opérateurs de comparaison
3.3 Les opérateurs booléens
3.4 Opérateur de concaténation des chaînes de caractères
4 Structures de contrôle
4.1 Structures IF
4.2 Structure SELECT CASE
4.3 Structures de boucles
4.4 Autres instructions de contrôle
5 Entrées–sorties, fichiers
5.1 Introduction : entrées et sorties standard
5.2 Généralités et terminologie
5.3 Instructions d’entrées-sorties
5.4 Descripteurs de format
5.5 Exemples d’entrées-sorties formatées
5.6 Exemples de fichiers en accès direct
6 Procédures
6.1 Introduction
6.2 Sous-programmes et fonctions
6.3 Procédures internes et procédures externes
6.4 Les modules
6.5 Fonctionnalités avancées
7 Tableaux
7.1 Généralités
7.2 Sections de tableaux
7.3 Opérations sur les tableaux
7.4 Fonctions intrinsèques particulières aux tableaux
7.5 Tableaux et allocation dynamique
8 Chaînes de caractères
8.1 Le type chaîne de caractères
8.2 Expressions de type chaîne de caractères
8.3 Les fonctions opérant sur les chaînes de caractères
8.4 Les entrées-sorties de chaînes de caractères
8.5 Les tableaux de chaînes de caractères
8.6 Chaînes et procédures
9 Types dérivés ou structures
9.1 Définition d’un type dérivé
9.2 Référence et affectation des structures
9.3 Imbrication et extension de structures
9.4 Structures et tableaux
9.5 Types dérivés à composantes allouables dynamiquement
9.6 Procédures et opérateurs agissant sur les structures
10 Généricité, surcharge d’opérateurs
10.1 Procédures génériques et spécifiques
10.2 L’interface-opérateur
10.3 L’interface-affectation
11 Pointeurs
11.1 Pointeurs, cibles et association
11.2 Pointeurs sur des tableaux
11.3 Tableaux de types dérivés contenant des pointeurs
11.4 Manipulation de listes chaînées
12 Inter-opérabilité avec le C
12.1 Interopérabilité des types intrinsèques
12.2 Inter-opérabilité des types dérivés
12.3 Inter-opérabilité avec les pointeurs du C
12.4 Inter-opérabilité des procédures
12.5 Inter-opérabilité des tableaux
Bibliographie