A apprendre à programmer une HP48

Les derniers trucs auxquels vous avez joué, les derniers ordinateurs que vous avez bidouillés.

Modérateur : Politburo

Ben
Fonctionne à 2400 bauds
Fonctionne à 2400 bauds
Messages : 1549
Enregistré le : 21 août 2016 19:04

A apprendre à programmer une HP48

Message par Ben »

Salut,

Quelques jours en vacance, je me suis dit que c'était le moment d'enfin m'intéresser de plus près à cette HP-48. Le passage de la 41 à la 48 est tout de même un grand pas. Entre autre au niveau de la programmation :-)

Ben
francoisp31
Fonctionne à 2400 bauds
Fonctionne à 2400 bauds
Messages : 2002
Enregistré le : 30 mai 2005 09:48
Localisation : Toulouse
Contact :

Re: A apprendre à programmer une HP48

Message par francoisp31 »

bho avec un peu de patience ...
-----------
ssh debile@stupide.local "docker run -it docker/cowsay \"fortune | cowsay\" "

:ugeek:
Avatar du membre
Gege34
Fonctionne à 1200 bauds
Fonctionne à 1200 bauds
Messages : 1167
Enregistré le : 03 oct. 2014 11:19
Localisation : 31

Re: A apprendre à programmer une HP48

Message par Gege34 »

Très bon choix que la HP48 :D
Après le rpl tu pourras passer au sysrpl pour finir avec l'asm. C'est vraiment une machine intéressante à programmer.
Commodore (64/128/Amiga), HP (28/41/48/50/71/75/200/Prime) et autres (Ti, Canon X07, Psion, Casio, Palm, Thomson, Exl, Amstrad)
billaj
Fonctionne à 1200 bauds
Fonctionne à 1200 bauds
Messages : 383
Enregistré le : 09 avr. 2005 17:48
Localisation : Brest
Contact :

Re: A apprendre à programmer une HP48

Message par billaj »

Ben a écrit : 16 juil. 2017 11:57Le passage de la 41 à la 48 est tout de même un grand pas. Entre autre au niveau de la programmation :-)
Avec un langage structuré penchant vers le Fonctionnel, c'est le programme lui-même qui devient "un grand pas" :P
Bonne découverte :)
Quand Chuck Norris joue à Nintendogs, il a automatiquement armes et munitions infinies.
Chuck Norris peut revenir en arrière dans Super Mario Land.
Chuck Norris utilise exclusiment des calculatrices Texas Instruments.
Ben
Fonctionne à 2400 bauds
Fonctionne à 2400 bauds
Messages : 1549
Enregistré le : 21 août 2016 19:04

Re: A apprendre à programmer une HP48

Message par Ben »

Elle est assez intéressante, effectivement. :-)

Mais je sèche sur des bêtises!
francoisp31
Fonctionne à 2400 bauds
Fonctionne à 2400 bauds
Messages : 2002
Enregistré le : 30 mai 2005 09:48
Localisation : Toulouse
Contact :

Re: A apprendre à programmer une HP48

Message par francoisp31 »

ça s'appelle une core ... à linge
-----------
ssh debile@stupide.local "docker run -it docker/cowsay \"fortune | cowsay\" "

:ugeek:
Ben
Fonctionne à 2400 bauds
Fonctionne à 2400 bauds
Messages : 1549
Enregistré le : 21 août 2016 19:04

Re: A apprendre à programmer une HP48

Message par Ben »

Mon Dieu! :D
Ben
Fonctionne à 2400 bauds
Fonctionne à 2400 bauds
Messages : 1549
Enregistré le : 21 août 2016 19:04

Re: A apprendre à programmer une HP48

Message par Ben »

Pour m'exercer à dominer la bête, j'ai repris le programme de "Carré à chiffres croissants". Voilà ce que ça donne. J'imagine qu'il n'est pas du tout optimale. Je suis preneur de toutes critiques constructives (évidemment)!

Code : Tout sélectionner

<<
-> b c d e f
<<
1 9999 FOR a
   a SQ 'b' STO
   99 'f' STO
   1 'd' STO
   WHILE b 0 > REPEAT
      B 10 /
      FLOOR 'c' STO
      b c 10 * - 'e' STO
      c 'b' STO
      IF e f > THEN 0 'b' STO 0 'd' STO
      ELSE e 'f' STO
      END
   END
   IF d 1 = then a 1 DISP
   END
NEXT
>>
>>


J'ai tout de même une question. Il y a un truc qui m'échappe. J'utilise des variables locales, mais je dois mettre dans le stack autant de '0' que de variables. Y a t'il un moyen que l'HP n'initialise pas ces variables par le stack?

Ben
Avatar du membre
bernouilli92
Fonctionne à 14400 bauds
Fonctionne à 14400 bauds
Messages : 5229
Enregistré le : 21 nov. 2012 13:03
Localisation : Ile de France

Re: A apprendre à programme une HP48

Message par bernouilli92 »

Rien ne t'empêche de mettre ces variable sur la pile dans ton programme.
Comme ceci :

Code : Tout sélectionner

<< 
0 0 0 
-> b c d e f
<<
1 9999 FOR a
   a SQ 'b' STO
...
Ici d e et f auront la valeur 0, b et c seront pris depuis la pile.

Il y a une erreur vers la fin, le test d'égalité c'est == et non = :

Code : Tout sélectionner

IF d 1 == THEN
HP, Casio, Sharp, Psion, quelques TI et divers autres
Avatar du membre
C.Ret
Fonctionne à 9600 bauds
Fonctionne à 9600 bauds
Messages : 3405
Enregistré le : 31 mai 2008 23:43
Localisation : N 49°22 E 6°10

Re: A apprendre à programme une HP48

Message par C.Ret »

En fait, il n'y a pas besoin d'initialiser les variables locales au début d'un programme.
Les deux strutures sont là pour simplifier les choses, pas les rendre plus compliquées.


Il y deux structures qui utilisent les variables locales :
- les fonction utilisateurs :

Code : Tout sélectionner

Cas un seul paramètre:
« → x 'sin(x)/x' » 'f' STO  

Cas plusieurs paramètres:
« → n k 'FACT(n)/FACT(k)/FACT(n-k)' » 'C' STO
- les programmes paramétrés:

Code : Tout sélectionner

Cas un seul paramète:
« → x « DEGREE x SIN x /  » 'f' STO  

Cas plusieurs paramètres:
« → n k « n FACT n FACT n k - FACT » » 'C' STO
Dans les deux cas, n k et x sont des 'variables locales' n'existant que dans la structure entre « », qu'il s'agisse d'une fonction utilisateur ou d'un programme.
Elles ne sont pas initialisées par essence, puisque les valeur des ces variables seront prises dans la pile au moment de l'évaluation de la fonction ou de l'exécution du programme. C'est l'opérande → qui est responsable de cette opération. L'ordre des variables à la suite de cet opérateur donne l'ordre dans lequel doivent se trouver les valeurs dans la pile.

Une fois mémorisé, 15 f renverra 1.7254E-2; l'initialisation se fera automatiquement à x=15 puis la structure est évaluée.

Il est possible d'enchâsser les structures contenant des variables locales, les variables locales des niveaux antérieurs restent disponibles dans les structures et disparaissent avec la structure à laquelle elles sont liées.
Il n'y a donc pas d'ambiguïté dans la désignation des variables, si elle portent le même nom, seul l'instance la plus récente (c'est à dire la plus interne) est disponible. De la même façon, dans une struture avec varaible locale portant le nom d'une variable ou d'un registre global masque celui-ci.
D'où d'ailleurs l'habitude prise de nommer les variable locale avec des minuscules, les majuscules étant réservées aux registre mémoire globaux.

Techniquement, les variables locales sont des variables comme les autres, on peut donc rappeler leur contenu par 'n' RCL , ou stocker valeur, fonction, programme ou tout autre objet à l'aide de 'n' STO. Mais elles sont mémorisées dans la zone mémoire de la structure et disparaitront donc dès la fin de l'évaluation de celle-ci.

Par contre, si l'on en arrive à devoir utiliser 'n' STO dans un programme, il faut se poser des questions, car cela est certainement le signe que le programme est mal structuré. En effet, les variables locales servent à transmettre les paramètres ou les données prisent depuis le niveau antérieur. Devoir changer de valeur en cours de route est curieux et un peu contre-nature dans la philosophie générale d'un système RPL.

C'est exactement comme changer la valeur d'une variable d'un compteur dans une boucle FOR To NEXT en BASIC, C'est souvent possible, mais ce n'est pas 'naturel'.
D'ailleurs, en RPL , les boucles utilisent justement une variable locale pour désigner le compteur, c'est notoirement les boucles FOR ..NEXT ou FOR ... STEP, qui sont la troisième et dernière structure contenant des variables locales :

Code : Tout sélectionner

« 0 180 FOR a  
          a SIN a / 
  30 STEP »
  
La variable de boucle a est une variable locale comme les autres et suit les même règles.


Donc, dans le programme ci-dessus, il y certainement pas besoin d'autant de STO, il faut juste tenter de structurer les choses différemment.
Modifié en dernier par C.Ret le 23 juil. 2017 07:36, modifié 1 fois.
SHARP PC-1211 PC-1360 EL-5150 PC-E500 | Commodore C=128D | Texas Instruments Ti-57LCD Ti-74BASICalc Ti-92II Ti-58c Ti-95PROCalc Ti-30XPROMathPrint | Hewlett-Packard HP-28S HP-41C HP-15C HP-Prime HP-71B | CASIO fx-602p | NUMWORKS | Graphoplex Rietz Neperlog | PockEmul | Sommaire des M.P.O. | Ma...dov'il sapone.
Ben
Fonctionne à 2400 bauds
Fonctionne à 2400 bauds
Messages : 1549
Enregistré le : 21 août 2016 19:04

Re: A apprendre à programme une HP48

Message par Ben »

bernouilli92 a écrit : 22 juil. 2017 18:49 Rien ne t'empêche de mettre ces variable sur la pile dans ton programme.
Comme ceci :

Code : Tout sélectionner

<< 
0 0 0 
-> b c d e f
<<
1 9999 FOR a
   a SQ 'b' STO
...
Ici d e et f auront la valeur 0, b et c seront pris depuis la pile.
Effectivement, ça permet d'initialiser les variables. Mais le truc, c'est que plus loin dans le programme, elles prennent les bonnes valeurs.
bernouilli92 a écrit : 22 juil. 2017 18:49 Il y a une erreur vers la fin, le test d'égalité c'est == et non = :

Code : Tout sélectionner

IF d 1 == THEN
Merci, je me suis trompé dans le transcription ;-)
Ben
Fonctionne à 2400 bauds
Fonctionne à 2400 bauds
Messages : 1549
Enregistré le : 21 août 2016 19:04

Re: A apprendre à programmer une HP48

Message par Ben »

C.Ret a écrit : 22 juil. 2017 19:11 par contre, si l'on en arrive à devoir utiliser 'n' STO dans un programme, il faut se poser des questions, car cela est certainement le signe que le programme est mal structuré. En effet, les variables locales servent à transmettre les paramètres ou les données prisent depuis le niveau antérieur. Devoir changer de valeur en cours de route est curieux et un peu contre-nature dans la philosophie générale d'un système RPL.
Je ne comprends pas bien ce que tu veux dire. Les variables locales sont un peu comme les variables dans un programme BASIC, non? Dans mon exemple, elles servent à enregistrer les valeurs intermédiaires pour les calculs
Avatar du membre
bernouilli92
Fonctionne à 14400 bauds
Fonctionne à 14400 bauds
Messages : 5229
Enregistré le : 21 nov. 2012 13:03
Localisation : Ile de France

Re: A apprendre à programmer une HP48

Message par bernouilli92 »

D'après c.ret, ton programme devrait être plutôt comme ceci :

Code : Tout sélectionner

<<
-> c e 
<<
1 9999 FOR a
   a SQ 99 1 -> b f d <<
     WHILE b 0 > REPEAT
        B 10 /
        FLOOR 'c' STO
        b c 10 * - 'e' STO
        c 'b' STO
        IF e f > THEN 0 'b' STO 0 'd' STO
        ELSE e 'f' STO
        END
     END
     IF d 1 = then a 1 DISP
     END 
   >>
NEXT
>>
>>
Sauf qu'en réalité un programme comme celui là sera plus lent que le programme initial. La création/destruction de variables locales prend du temps.
HP, Casio, Sharp, Psion, quelques TI et divers autres
Avatar du membre
C.Ret
Fonctionne à 9600 bauds
Fonctionne à 9600 bauds
Messages : 3405
Enregistré le : 31 mai 2008 23:43
Localisation : N 49°22 E 6°10

Re: A apprendre à programmer une HP48

Message par C.Ret »

Oui c'est bien cela, tu as bien compris.


Et la nouvelle version du programme est beaucoup mieux (merci bernouilli) !
Il manque juste peut-être un niveau supplémentaire autour de la zone utilisant la variable locale 'c' ?



Les variables locales ont été crées en RPL pour faciliter la référence des paramètres et données entre les structures antérieurs tout au long d'une structure donnée et locale (d'où le nom de ces variables).

Maintenant, comme se sont des registres mémoire comme les autres elles peuvent aussi, comme dans ton programme servir de 'variables' au sens des langages procéduraux comme le BASIC où les variables sont modifiées plusieurs fois dans une ligne et d'une ligne à l'autre.

Mais, le RPL est comme le RPN; utiliser les variables locales d'une structure, c'est comme utiliser les registres pour faire les calculs. Ca peut le faire, mais ce n'est pas fait pour fonctionner comme cela. Comme le RPN, le RPL utilise les niveaux de la pile opérationnelle pour faire les calculs et recevoir les résultats de ceux-ci.

Par exemple, pour calculer 'sin(x)/x', on peut utiliser pour chaque calcul les registres. Dans cet exemple simple, ce sera par exemple à l'aide du registre 00 :
30 STO 00 RCL 00 SIN RCL 00 / on aura bien calculer 'sin(30)/30'

Mais on peut aussi utiliser la pile directement :
30 SIN LastX /
Cela conduit strictement au même résultat, tout en étant plus court et en préservant le contenu mémorisé dans le registre 00

Le RPL fonctionne de la même façon :
En utilisant le registre A : 30 'A' STO A SIN A /
En utilisant la pile : 30 SIN LAST /
En utilisant une variable locale : 30 -> a « a SIN a / »
En utilisant l'héritage du FORTH : 30 DUP SIN SWAP /

Cette dernière façon et intéressante. c'est la plus directe, mais aussi la plus illisible. On utilise pour mémoriser les valeur intermédiaire un container invisible dans lequel on place les objets que l'on a besoin pour mener à bien son calcul et on organise son déroulement en fonction du fonctionnement de ce container, cette liste, cette pille d'objet sur laquelle on peut faire les opérations.

Cette façon de faire existe aussi en RPN, mais elle est limité, grandement limité par la taille du container. Mais en RPL, ce container est infini (ou presque car uniquement limité par la taille de la mémoire restante). C'est ce container invisible qui fait du RPL un langage aussi puissant, mais aussi un langage impossible à relire, car même l'auteur d'un programme trop complexe, perd vite ses repères et ne saura bientôt plus pourquoi ou comment sa propre création fonctionne.

Ce container donne vite des habitudes bizarre. Par exemple, on copie tout de suite la valeur 30 en réserve pour effectuer plus tard la division. d'où le DUP, puis le SWAP pour 'récupérer' la valeur 30.

C'est pourtant bien ce que l'on a fait aussi avec les trois premières méthodes. Soit explicitement en effectuant en quelque sorte une copie de 30 dans le registre A ou dans la variable locale a, mais aussi de façon invisible en utilisant SIN qui a fait une copie du registre x: dans le registre de sauvegarde L:

On voit donc la filiation entre le RPL et le RPN et le problème que pose la pile de taille infinie qui fait ressembler du code RPL comme le FORTH à une sorte de charabia : 30 DUP SIN SWAP / ou 30 DUP OVER / si l'on veut conserver la valeur de l'argument dans la pile.

Comme la pile est infinie, l'habitude en RPL est d'y laisser tout ce qui au long du calcul ou de la procédure change et de ne mettre dans les variables que les paramètres et les valeurs immuables que l'on veut conserver ou transmettre. Un peu comme l'on mémorise les programmes, on aime laisser dans les variables globales que des objets utiles ou des résultats et dans les variable locale des paramètres ou arguments qui la traverse.

Mais ce n'est pas une obligation. Par exemple, ton le code en question, utiliser une variable pour mémoriser la valeur entière de b/10 n'est pas une nécessité, c'est juste un choix de l'auteur du programme. Surtout que cela sert à calculer un module qui lui sera mémorisé dans une nouvelle variable 'e'
Tout cela ne sont que des objets temporaire et volatile, pourquoi ne pas simplement les laisser dans la pile. Le container invisible est lui aussi un bon moyen de garder, le temps d'un calcul ou d'un programme en mémoire les valeurs intermédiaire ou fugaces.

Evidemment, il faut alors organiser (ou à défaut suivre l'organisation de la pile ) et noter à part comment tout cela est organisé. Au moins les HP-48 permettent éventuellement d'utiliser des étiquettes( je n'ai plus en tête le nom de la commande * mais c'est bien pratique pour débugger) pour suivre plus facilement ce qui se passe.

C'est tout l'inverse du BASIC, où l'on précise systématiquement les 'containers'.

Par exemple le code RPL suivant calcule l'aire d'un disque : « SQ PI * » mais rien dans le code n'indique de quoi il s'agit, ni ce qui se passe (ce qui d'après moi est un manque gravissime qui explique la disparition du RPL de l'avant-scène des langages performants); rien ne dit qu'un argument est pris de la pile et qu'un autre vient le remplacer. Rien n'informe l'utilisateur qu'il faut saisir un rayon.

En BASIC, on aurait quelque chose comme :

Code : Tout sélectionner

10 INPUT "Rayon ";R : A = PI * R^2 : PRINT "AIRE DISQUE";A :END 
Cela donne bien plus d'information sur ce qui se passe dans la machine et plus d'indice sur la nature du calcul etde ce qu'il faut saisir.
A chaque instruction on donne le registre 'container' à utiliser : R dans leque on met le résultat de lasaiei de l'utilisateur ; A danslequel on met le résultat du calcul de l'aire effectué à partir de R, on affiche à l'écran le résultat, etc.

Le RPL ne fonctionne pas de cette façon, le container est implicitement la pile, sauf à avoir une raison technique ou philosophique à utiliserun autre container.
D'une certaine façon, la structure

Code : Tout sélectionner

« → r 'PI*SQ(R)' » 'ADSK' STO
et déjà plus informative que le code RPL natif.
N'oublions pas, le RPL est comme le RPN un langage dédié à des machines qui devaient tenir dans la poche d'une chemise !

Alors,comment interpréter un code qui serait :

Code : Tout sélectionner

« 0 0 0 → r c p a « r SQ 'c' STO PI 'p' STO 'p*c' 'a' STO  a 1 DISP a →NUM »
?
Est-il toujours aussi 'informatif' ?
Un certain nombre de variables locales ne sont que des chimère, des valeurs intermédiaire, que le container invisible et iné au RPL peut contenir sans autre artifice :

Code : Tout sélectionner

                        1:     10  // Le rayon est en haut de la pile
« → r                              // variable locale mémorise rayon r
   «   PI               1: 3.1415  // PI est placé dans la pile
        r   2: 3.1415   1:     10  // le rayon est placé dans la pile
       SQ   2: 3.1415   1:    100  // le carré du rayon est caclulé
        *               1: 314.15  // le produit est effectué    
   »
»                       1: 314.15  // Aire du disque de rayon 10 
SHARP PC-1211 PC-1360 EL-5150 PC-E500 | Commodore C=128D | Texas Instruments Ti-57LCD Ti-74BASICalc Ti-92II Ti-58c Ti-95PROCalc Ti-30XPROMathPrint | Hewlett-Packard HP-28S HP-41C HP-15C HP-Prime HP-71B | CASIO fx-602p | NUMWORKS | Graphoplex Rietz Neperlog | PockEmul | Sommaire des M.P.O. | Ma...dov'il sapone.
Avatar du membre
gege
Fonctionne à 14400 bauds
Fonctionne à 14400 bauds
Messages : 7141
Enregistré le : 31 janv. 2008 14:24
Localisation : Banlieue Paârisienne
Contact :

Re: A apprendre à programmer une HP48

Message par gege »

Bonjour,
Pour résumer oui tu es obligé de mettre les zéros.
Et non, il n'y a pas de GOTO ce qui empêche de créer tout une classe de programmes bien utiles (hop petit troll ;-) ).
Pour les variables locales, il y a aussi un gag : si a est une variable locale de b et que b appelle c, alors pour accéder à a depuis c il faut la préfixer par une flèche vers la gauche.
Et encore, sur certaines versions les plus récentes... sinon ben pas de chance...
Ce genre de gags et l'impossibilité (par design) de garder le formattage de ton code ou de mettre des vrais commentaires (oui oui je sais), m'a fait abandonner le RPL après des années de pratique.
Je trouve que le RPL est un langage "write only", après 2 semaines même le concepteur a du mal à se relire.
Les langages qui ressemblent plus au C sont plus reposants, question de goût bien sûr.
A noter que le gag de a,b et c ci-dessus n'est correctement résolu par aucun langage sauf que sur TI "Basic" on peut inclure une fonction dans une autre et... il faudrait que j'essaye.
A noter aussi que 30 SIN LAST / ne marche que si l'utilisateur n'a pas désactivé le LAST X, ce qu'il est imprudent de supposer.
A noter (enfin ?) que l'existence de la syntaxe FOR a montre que des choses comme -> a auraient été possibles au lieu du monstrueux 'a' STO, au prix d'un sacrifice à l'orthodoxie RPL... qui a quand même été fait puisqu'on ne fait pas le (moche) 'a' FOR !?
G.E.
Répondre

Retourner vers « A quoi t'as joué hier ? »