Autres articles / Other articles

Les nombres entiers avec eFORTH

publication: 2 mars 2023 / mis à jour 2 mars 2023

Read this page in english

 

Empilage et dépilage des nombres entiers

Le langage FORTH stocke les nombres sur une pile nommée pile de données ou pile paramétrique. L'empilage d'un nombre est très simple:

55 

empile le nombre 55. Pour dépiler ce nombre, il y a plusieurs méthodes. La plus simple consiste à afficher le contenu du dernier élément empilé. Le mot . (point) affiche 55.

55      \ display ok 
.       \ display 55 ok 

Si vous déposez plusieurs nombres sur la pile de données, voici ce qui se passe:

11 45 6543 
?>

Les nombres sont mis sur la pile de données dans l'ordre de frappe. Le dernier nombre entré est toujours au sommet de la pile:

valeur empilée haut -- pile -- fond
11 11
45 45 11
6543 6543 45 11

Le dépilage successif des nombres affiche ceux-ci dans l'ordre inverse de leur empilage:

11 45 6543      \ display ok 
.               \ display 6543  ok 
.               \ display 45  ok 
.               \ display 11  ok 

Pour mieux visualiser le mécanisme d'empilage et de dépilage des nombres, pensez à une pile d'assiettes: la dernière assiette déposée sur la pile sera la première reprise.

A tout moment vous pouvez prendre connaissance du contenu de la pile de données sans avoir à provoquer le dépilage des valeurs qui y sont stockées en utilisant le mot .S:

  1 2 3 .S affiche 1 2 3

Ce principe de rangement est appelé également pile LIFO (Last In, First Out) dans certains ouvrages écrits en anglais pour désigner une pile dont le mécanisme est: "dernier entré, premier sorti".

Avec la majorité des versions du langage FORTH, la quantité de nombres empilables est assez élevée, mais reste limitée. Si vous empilez trop de nombres, vous saturerez la pile de données. De même, toute tentative pour dépiler un nombre alors que la pile de données est vide, affichera un message d'erreur.

Chaque nombre empilé ne peut être qu'un nombre entier au format simple précision. Selon les cas, ce nombre peut être considéré signé ou non signé:

En format simple précision signé, le bit de poids le plus fort indique le signe du nombre.

La valeur -1, déposée sur la pile en tant que valeur entière a la représentation binaire suivante:
  11111111111111111111111111111111 (simple précision 32 bits).

Cette même valeur peut être affichée en valeur absolue en utilisant le mot U. à la place du mot . (point):

-1 U.   \ affiche 4294967295 

Opérations arithmétiques élémentaires

Les opérateurs arithmétiques + - * et / agissent sur les deux valeurs situées au sommet de la pile de données. Les valeurs traitées sont toujours des entiers simple précision signés.

Somme de deux nombres entiers

Pour additionner deux nombres, il faut d'abord les déposer sur la pile de données:
  22 44 + . affiche 66

Une fois empilés 22 et 44, le mot + opère l'addition de ces deux valeurs et le mot . affiche le résultat:

55 1 + 3 + .   \ affiche 59 et peut aussi s'écrire 
55 1 3 + + . 

L'addition est commutative: les valeurs peuvent être déposées sur la pile de données dans n'importe quel ordre:

55 22 + 
22 55 + 

Ce principe de calcul est appelé NOTATION POLONAISE INVERSE (RPN dans la littérature anglaise, pour Reverse Polish Notation). On peut aussi additionner deux nombres entiers non signés, à condition de visualiser le résultat à l'aide du mot U. au lieu de .:

35000 10 + U. 

Il est également possible de faire la somme de deux nombres de signe différent:

10 -5 + .    \ affiche       5 
-5 10 + .    \ affiche aussi 5 

Selon que l'on traite des valeurs considérées comme signées ou non, les intervalles de définition des résultats doivent respectivement se situer dans [- 32768..32767] ou [0..65535]. Tout résultat situé hors de ces intervalles n'aurait aucun sens.

FORTH dispose également du mot 1+ qui incrémente la valeur située au sommet de la pile de données de 1 unité:

10 1+    \ est équivalent à 
10 1 + 

Soustraction de deux nombres entiers

Soit deux nombres a et b. La différence de deux nombres sera écrite en FORTH sous la forme:
  a b - pour a-b

La soustraction n'est pas commutative:

10 3 - .       \ affiche      7
3 10 - .       \ affiche      -7

Le mot 1- décrémente la valeur située au sommet de la pile de données de 1 unité:

10 1-    \ est équivalent à 
10 1 - 

Produit de deux nombres entiers

Soit deux nombres a et b. Le produit de deux nombres sera écrit en FORTH sous la forme:
  a b * pour a*b

La multiplication est commutative:

7 5 * .    \ ou 
5 7 * .    \ affiche    35 

Le mot 2* multiplie la valeur située au sommet de la pile de données par deux:

5 2*        \ est équivalent à
5 2 *

Quotient de deux nombres entiers

Pour la division, seul le quotient entier est conservé sur la pile de données:

22 7 / .   \  affiche    3 

La division n'est pas commutative:

15 5 / .    \ affiche    3 
5 15 / .    \ affiche    0 

Le reste de la division peut être obtenu en appliquant la fonction modulo:

22 7 MOD .    \ affiche    1 

La fonction modulo peut servir à déterminer la divisibilité d'un nombre par un autre:

: DIV? ( n1 n2 ---) 
    OVER OVER MOD CR 
    IF 
        SWAP . ." n'est pas " 
    ELSE 
        SWAP . ." est " 
    THEN 
    ." divisible par " . ; 

Le mot /MOD combine les actions de / et de MOD:

22 7 /MOD . .    \ affiche    3 1 

Produit et quotient de trois nombres

valable seulement pour les piles simple précision

Si on essaye une opération du type suivant:

30000 3 * 10 / . 

on risque d'être quelque peu surpris par le résultat. Mais tout s'explique, car le produit calculé en premier délivre une valeur dont la capacité est supérieure à celle admise par les valeurs simple précision signées. Pour traiter ces cas particuliers, on utilisera de préférence le mot */ qui combine les opérations de multiplication et de division, mais traite le résultat transitoire de la multiplication au format double précision.

Exemple, soit à calculer le prix TTC d'une marchandise (TVA à 20 %), on définira le mot TTC comme suit:

: TTC ( n1 --- n2) 
    DUP 200 1000 */ + ; 
442 TTC .   \ affiche    530 

Les valeurs traitées étant exprimées en centimes.

Le mot */MOD a les mêmes propriétés que */, mais délivre le quotient et le reste de l'opération.

A titre d'exemple, pour donner une application immédiate et pratique des notions déjà exprimées, est la conversion des degrés Fahrenheit et Celsius:

: C>F ( °C --- °F) 
    9 5 */ 32 + ; 
: F>C ( °F --- °C) 
    32 - 5 9 */ ; 
37 C>F .    \ affiche    98 (les résultats sont arrondis) 

Cet exemple fonctionne sur toutes les versions du langage FORTH.

Traitement des expressions algébriques

Les opérations peuvent être chaînées, mais une opération en notation algébrique comportant des parenthèses doit être convertie en notation RPN en tenant compte de l'ordre de priorité des opérations. FORTH n'utilise pas les parenthèses dans les opérations arithmétiques:

soit l'expression algébrique ( 2 + 5 ) * ( 7 - 2 )

elle s'écrit en FORTH2 5 + 7 2 - *

Lors d'une opération de conversion de notation algébrique infixée en notation polonaise inverse, commencez toujours par le niveau de parenthèse le plus imbriqué et par la gauche. Ecrivez la transcription en notation polonaise inverse de chaque opération sur des lignes séparées, successivement de haut en bas, en les mettant dans le prolongement de l'expression algébrique exprimée dans la formule initiale:

En reprenant chaque niveau dans l'ordre, on réécrit la formule:<
  2 5 + 7 2 - * 5 2 + 3 * /

C'est choquant? Mais tous les interpréteurs/compilateurs travaillent ainsi lorsqu'ils ont à évaluer une formule algébrique. En notation algébrique, les parenthèses ne servent qu'à isoler une expression sous forme de sous-expression qui devient membre d'une expression plus générale.

En informatique comme en arithmétique, un opérateur travaille toujours sur deux opérandes et seulement deux opérandes simultanément. Le résultat d'une opération portant sur deux opérandes délivre une valeur qui peut devenir à son tour opérande d'un autre opérateur. L'ordre d'exécution des opérandes et des opérateurs est fondamental:

notation algébrique polonaise inverse
(2+3)*5 2 3 + 5 *
2+(3*5) 2 3 5 * + or 3 5 * 2 +

Tous les problèmes arithmétiques peuvent être résolus de cette manière, ce n'est qu'une question d'habitude. L'exemple donné précédemment illustre parfaitement la rigueur dont doit faire preuve le programmeurs Forth. Cette rigueur garantit un fonctionnement sans ambiguïté des programmes, quel que soit leur niveau de complexité.

Manipulation des données sur la pile

La pile de données est l'élément fondamental du langage FORTH pour le traitement de données. Son fonctionnement est identique à celui de la pile gérée par le micro-processeur. Dans certaines situations, les données traitées par les différentes définitions doivent être réordonnées ou dupliquées.

Le mot DUP duplique le contenu du sommet de la pile de données:

10 DUP . .   \ affiche   10 10
5 DUP * .    \ affiche   25

Le mot OVER duplique le second élément de la pile de données:

5 15 OVER . . .   \ affiche   5 15 5 

Le mot SWAP inverse les deux éléments du sommet de la pile de données:

1 3 SWAP . .   \ affiche   1 3

Le mot ROT effectue une rotation sur les trois éléments situés au sommet de la pile de données:

1 2 3 ROT . . .   \ affiche   1 3 2

Le mot -ROT effectue une rotation inverse sur trois éléments. Son comportement est similaire à l'exécution de deux ROT successifs.

Le mot PICK dépose au sommet de la pile de données le nième élément de la pile de données, n non compris. La base de départ pour le comptage des éléments à traiter est 0 et non 1, l'élément numéro zéro étant situé immédiatement après le paramètre traité par PICK. La séquence 0 PICK est similaire à DUP, 1 PICK à OVER. Il n'y a pas de traitement d'erreur si n est supérieur au nombre d'éléments déposés sur la pile de données. Exemple:

1 2 3 4 5 6    4 PICK    \ empile 2 car 6 est l'élément n°0, 5 l'élément n°1, etc... 

Le mot ROLL effectue une rotation sur les n premiers éléments de la pile de données, n non compris. Comme pour PICK, la base de départ pour le comptage des éléments à traiter est 0:

1 2 3 4 5 6 4 ROLL . . . . . .   \ affiche    2 6 5 4 3 1 

Voici quelques exemples d'utilisation de ces manipulateurs de pile de données:

: AU-CARRE ( n --- n2) 
    DUP * ; 

Le mot AU-CARRE élève un nombre entier quelconque au carré:

2 AU-CARRE .   affiche   4 
3 AU-CARRE .   affiche   9 
4 AU-CARRE .   affiche  16 
 
: AU-CUBE ( n --- n3) 
   DUP DUP * * ; 

Le mot AU-CUBE élève un nombre entier quelconque au cube:

    2 AU-CUBE .   affiche   8 
    3 AU-CUBE .   affiche  27 

Attention, n'utilisez pas des valeurs trop élevées, car un résultat supérieur à 32767, pour une pile de données 16 bits, devient faux. Ayez toujours à l'esprit que les données traitées sont des entiers simple précision, donc de capacité limitée. Nous verrons ultérieurement comment traiter des nombres plus importants.

Passage de paramètres par la pile de retour

A coté de la pile de paramètres, il existe dans FORTH une deuxième pile, appelée pile de retour parce qu'elle sert à l'interpréteur interne à retrouver l'adresse de retour à chaque appel d'une procédure.

Il y a parfois des cas extrêmes où l'on peut être amené à stocker un ou plusieurs paramètres ailleurs que sur la pile de données, ceci pour simplifier quelque peu certaines manipulations scabreuses. la solution la plus commode, parmi d'autres, est la pile de retour. Cette pile est accessible par les mots >R et R> moyennant quelques précautions pour ne pas compromettre le fonctionnement de cette pile interne.

Le mot >R transfère un nombre entier de la pile de données vers la pile de retour.

Le mot R> transfère un nombre entier de la pile de retour vers la pile de données.

Une opération >R R> est nulle. En fin de définition, il doit y avoir autant de >R que de R> sous peine de perturber quelque peu le déroulement normal de votre définition. Exemple d'utilisation:

: AU-CARRE ( n --- n^2)             \ élévation au carré 
    DUP >R                          \ transfert de la copie sur pile de retour 
    CR ." Le carré de " .           \ affichage valeur initiale 
    ." est " R> DUP * .  ;          \ récupération valeur déposée sur pile retour 
                                    \ et affichage de son carré 
////

Contrôle de l'affichage des nombres entiers

En FORTH, les entiers simple précision déposés sur la pile de données peuvent être affichés par exécution du mot . (point). Mais d'autres mots permettent d'exécuter un affichage plus présentable.

Le mot .R affiche un nombre simple précision signé cadré à droite dans un champ de n caractères. Exemple:

  3 10 .R  affiche  3 (3 précédé de 9 espaces)
  101 10 .R  affiche  101 (101 précédé de 7 espaces)

Et dont voici une application très pratique:

: C>F ( °C --- °F)       \ Conversion Celsius en Fahrenheit 
    9 5 */ 32 + ; 
: .TREMPE ( °C ---)      \ Affiche °C et °F formatés 
    DUP 6 .R ." °C " 
    C>F 6 .R ." °F" ; 
: TREMPE-ACIER ( ---)       \ Table des températures de trempe 
    CR ." COULEURS DE TREMPE DE L'ACIER:" CR 
    CR ." rouge foncé......... "   680 .TREMPE 
    CR ." rouge cerise foncé.. "   740 .TREMPE 
    CR ." rouge cerise........ "   770 .TREMPE 
    CR ." rouge cerise clair.. "   800 .TREMPE 
    CR ." rouge clair......... "   850 .TREMPE 
    CR ." rouge très clair.... "   900 .TREMPE 
    CR ." rouge jaune......... "   950 .TREMPE 
    CR ." jaune............... "  1000 .TREMPE 
    CR ." jaune clair......... "  1100 .TREMPE 
    CR ." jaune blanc......... "  1200 .TREMPE 
    CR ." blanc............... "  1300 .TREMPE 
    CR CR ; 

On exécute TREMPE-ACIER:

trempe-acier
COULEURS DE TREMPE DE L'ACIER:

rouge foncé.........    680°C   1256°F
rouge cerise foncé..    740°C   1364°F
rouge cerise........    770°C   1418°F
rouge cerise clair..    800°C   1472°F
rouge clair.........    850°C   1562°F
rouge très clair....    900°C   1652°F
rouge jaune.........    950°C   1742°F
jaune...............   1000°C   1832°F
jaune clair.........   1100°C   2012°F
jaune blanc.........   1200°C   2192°F
blanc...............   1300°C   2372°F

Legal: site web personnel sans commerce / personal site without seling