BASIC pas si simple...

Cette catégorie traite de développements récents destinés à nos vieilles machines, applications, jeux ou démos... Amis programmeurs, c'est ici que vous pourrez enfin devenir célèbres!

Modérateurs : Papy.G, fneck, Carl

Xavier

BASIC pas si simple...

Message par Xavier »

Salut à tous,

Au cours de mes différentes saisies de logiciel Basic, je me suis aperçu que de nombreuses astuces en Basic étaient utilisées pour accélérer son fonctionnement!
Rarement documentées, ces utilisations atypiques sont précieuses pour une meilleure programmation, et un gain appréciable.

Il faut savoir que lors de l'exécution d'un programme basic (pour différentes machines):
- Les retours à la line sont gourmands en cycle processeur (ZX81,SPECTRUM)
- L'emplacement de la routine dans un long programme est différent en tête ou en fin de programme (Ti99a)
- Que la nature des variables joue un grand rôle dans le temps de l'exécution des tâches (commande 'def' Amstrad et Spectrum)
- L'appel de routines assembleur est gourmande en temps ("RAND{omize} USR" du Zx81/Spectrum)

Il va sans dire, que les retard d'exécution sont non négligeable lors de l'affichage ou les routines de calcul.
Je vais vous donner quelques astuces, glanées çà et là...

à noter, que même si ce fil ressemble à un monologue pseudo-tutoriel, le but n'est pas de donner des cours de Basic, mais bel et bien de donner une liste de conseils et d'astuces sans prétention aucune.
:wink:
Dernière modification par Xavier le 20 déc. 2015 20:57, modifié 2 fois.
Xavier

Re: BASIC pas si simple...

Message par Xavier »

ZX81/Spectrum: (optimisation temps/mémoire)

Suppression de lignes:
Soit,

Code : Tout sélectionner

1 LET X=1
2 GOTO 10
5 LET X=0
10 PRINT "RESULTAT : ";
20 IF X=1 THEN PRINT "VRAI" 
30 IF X=0 THEN PRINT "FAUX"
ou
20 IF X THEN PRINT "VRAI"
30 IF NOT X THEN PRINT "FAUX"
(lancement par RUN 1 ou RUN 5)

DONNE:

Code : Tout sélectionner

1 LET X=1
2 GOTO 10
5 LET X=0
10 PRINT "RESULTAT : ";("VRAI" AND X)+("FAUX" AND NOT X)
Dernière modification par Xavier le 20 déc. 2015 16:35, modifié 1 fois.
Xavier

Re: BASIC pas si simple...

Message par Xavier »

Certains Basic: (optimisation temps/mémoire)

Code : Tout sélectionner

1 LET B=0
10 FOR A=1 TO 1000
20 LET B=B+1
30 IF B>500 THEN GOTO 50
40 NEXT A
50 REM SUITE
Remplacé par:

Code : Tout sélectionner

1 LET B=0
10 FOR A=1 TO 1000
20 LET B=B+1
30 IF B>500 THEN NEXT A
40  REM SUITE
Ici, on économise le passage de la ligne 30 à 40, et pas de goto ! (un peu de temps de gagné)
Dernière modification par Xavier le 20 déc. 2015 18:19, modifié 1 fois.
Xavier

Re: BASIC pas si simple...

Message par Xavier »

Certains Basic: (optimisation mémoire)

10 DATA 0,0,0,0,0,0,0

Les '0' peuvent être supprimés sur certains basics.

10 DATA ,,,,,,
Xavier

Re: BASIC pas si simple...

Message par Xavier »

ZX81/Spectrum: (optimisation temps)

La gestion des chaînes de caractère est plus lente avec des variables de grande taille!
Préférer les lectures multiples de courtes chaînes.

10 LET A$="1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ"
>> Traitement...

10 LET A$="1234567890ABCDEFG"
traitement...
20 LET A$="HIJKLMNOPQRSTUVWXYZ"
traitement...

Pour avoir une accélération du traitement, il est possible de réduire la chaîne avec retrait de l'information déjà lue.

100 PRINT A$(1)
110 LET A$=A$(2 TO)
120 GOTO 100
affichage data avec la fonction équivalente de A$=right(LEN A$-1) ou MID$(2,LEN A$-1)
Xavier

Re: BASIC pas si simple...

Message par Xavier »

Certains Basic: (optimisation mémoire)

Code : Tout sélectionner

10 {LET} a=0
20 {LET} b=0
30 {LET} c=0
40 {LET} d=0
50 {LET} e=0
Utilisez plutôt:

Code : Tout sélectionner

10 {LET} a=0
20 {LET} b=a
30 {LET} c=a
40 {LET} d=a
50 {LET} e=a
Car sur certains basic (zx81,Spectrum,Amstrad...), les chiffres en virgules flottantes prennent plus de place mémoire qu'un valeur variable (1octet au lieu de 6 dans ce cas là!).

Sur Zx81:
10 LET A=0
Encodé en 6 octets.
10 LET A=VAL "0"
Encodé en 4 octets.
Possibilité d'utiliser la fonction CODE (asc sur certains basics)
Dernière modification par Xavier le 20 déc. 2015 18:24, modifié 2 fois.
Xavier

Re: BASIC pas si simple...

Message par Xavier »

Certains Basic: (optimisation vitesse)

Oubliez définitivement les BIN 00010010 ou &H0023 !
Pratique pour le codage, ils ralentissent l'exécution des routines avec des appels de routines en ROM...
De plus, certaines routines de décodages peuvent boguer et retourner des valeurs fantaisistes (CPC).

Donc, une fois codé, les remplacer par des valeurs converties.


Dans le même genre, évitez les calculs non utiles du style:

Code : Tout sélectionner

10 FOR A=1 TO 1000+8
20 POKE A+255+32,255+12
30 NEXT A
Même si le calcul de 1000+8 n'est effectué qu'une fois, ça fais pas très PRO!

Par contre, pour la ligne 20, ce calcul est répété "1000+8" fois...
Des poignées de secondes perdues à cause d'une paresse intellectuelle, que vous ferai subir aux utilisateurs, à chaque exécution de cette routine.
Dernière modification par Xavier le 20 déc. 2015 18:17, modifié 2 fois.
Xavier

Re: BASIC pas si simple...

Message par Xavier »

Tous les Basic: (optimisation mémoire)

La redondance ! (exemple trouvé dans l'Hebdogiciel!)

Code : Tout sélectionner

10 LET SALLE=INT(RND*5)+1
20 ON SALLE GOSUB 100,110,120,... 
50 GOTO 10
100 PRINT "TU ES DANS LA SALLE DU TRESOR"
105 RETURN
110 PRINT "TU ES DANS LA SALLE DE TORTURE"
115 RETURN
120 PRINT "TU ES DANS LA SALLE VERTE"
125 RETURN
130 PRINT "TU ES DANS LA SALLE D'ARMES"
135 RETURN
:shock:

Quatre fois "TU ES DANS LA SALLE " !
Des GOSUB et des RETURN provocateurs d'embrouilles...
M'énerve de voir ça... Surtout, qu'au bout du compte, il faudra supprimer des salles pour tout faire tenir dans 16k de RAM!

Première chose, tu vires les redondances textuelles...

Code : Tout sélectionner

10 LET SALLE=INT(RND*5)+1
15 PRINT "TU ES DANS LA SALLE ";
20 ON SALLE GOSUB 100,110,120,... 
50 GOTO 10
100 PRINT "DU TRESOR"
105 RETURN
110 PRINT "DE TORTURE"
115 RETURN
120 PRINT "VERTE"
125 RETURN
130 PRINT "D'ARMES"
135 RETURN
Seconde chose, tu trouves un moyen de nommer les SALLEs, sans faire d'allez et retour!

Code : Tout sélectionner

10 LET S$(1)= "DU TRESOR"
11 LET S$(2)= "DE TORTURE"
12 LET S$(3)= "VERTE"
13 LET S$(4)= "D'ARMES"
100 LET SALLE=INT(RND*5)+1
105 PRINT "TU ES DANS LA SALLE ";S$(SALLE)
Déjà mieux...

Mais! l'initialisation des variables S$(x) mange de la mémoire à l'exécution, car stockée en RAM!
Donc, les informations sont dupliquée dans la mémoire basic et dans la mémoire variable.
Cela encombre l'espace vital du programme, lors de son exécution (memory full en plein programme!).

Donc, cette alternative est plus appropriée:

Code : Tout sélectionner

100 RESTORE 100:FOR SALLE=1 TO INT(RND*5)+1:READ S$:NEXT SALLE:DATA  "DU TRESOR", "DE TORTURE",VERTE, "D'ARMES"
105 PRINT "TU ES DANS LA SALLE ";S$
Pour les DATAs, les guillemets ne sont nécessaire que dans le cas d'espaces ou de présence de virgule. tout dépend du basic.
Les retirers donne des octets en plus!

Pour le fun, ça donne ça:

Code : Tout sélectionner

100 RESTORE 50:FOR SALLE=1 TO INT(RND*5)+1:READ S$:NEXT S:PRINT "TU ES DANS LA SALLE ";S$:DATA  "DU TRESOR", "DE TORTURE",VERTE, "D'ARMES"
Donc, programmer en basic est très facile... Mais, bien le programmer est un Art.

Pour les machines sans FONCTION DATA, Il est toujours possible de tout mettre en une seule REM, et de faire pointer une lecture mémoire sur cette même REM, puis indiquer à la routine une caractère particulier pour la fin de la lecture d'une phrase... mais c'est assez long, car il doit tout lire si la phrase est en fin de REM.
Donc, en début, on mets la taille de la première phrase, puis le texte. Les sauts ce feront de taille en taille de phrase... ce qui est plus rapide.
25,ABCDEFGHIJKLMNOPQRSTUVWXY
26,ABCDEFGHIJKLMNOPQRSTUVWXYZ
5,ABCDE
3,FIN
Donc Phrase 1=X, Phrase 2=X+25,Phrase 3=X+25+26,...
Avec des FOR la localisation de la phrase est plus rapide.
Xavier

Re: BASIC pas si simple...

Message par Xavier »

Tous les Basics: (optimisation vitesse)

opérateur booléen:
AND, OR et NOT.

Rappel:
"OR" (ou) symbolisé par "+" et AND (et) symbolisé par "." [edité car "+"/"." inversés (1+0=1 et 1.0=1)].
N'importe quelle variable peut être utilisée en variable Booléen.
Elle prend souvent la valeur de 0 pour Faux (false) et 1 pour vraie (true)
Sauf, sur certains basic, ou False= -1.

Pour une condition OR, on remplace "OR" par "Si on a * ou * " : A OR B = 1 Si on a A ou B en TRUE (<>0)
Pour une condition AND, on remplace "AND" par "Si on a * et * " : A AND B = 1 Si on a A et B sont en TRUE (<>0)
LET A=1
LET B=1
LET C= A OR B = 1 (car A est à 1; B est à 1; Si A ou B est à 0 même résultat. C=1)
LET C= A AND B = 1 (car A est à 1; B est à 1; C=1 sauf si A ou B changent d'état.)
Bon, c'est simple...

NOTA : On oublie la fonction XOR, qui ne peut être utilisée sur une fonction booléen, car le XOR de A= NOT A !

J'en viens à mon exemple!
On prend des coordonnées fixes sur l'écran de 21x32 caractères.
Utilisées si l'on passe avec un bonhomme (curseur) sur ces coordonnées, ça fait quelque chose... un "Booom!" pour rester ludique.

Donc, test en X (lignes) et Y(colonnes). x(de 0 à 20) y(0 à 31)
Ligne Y n°1: X coordonnées 7, 14 et 20 piégées!
Ligne Y n°2: X coordonnées 3, 10 et 15 piégées!
Ligne Y n°3: X coordonnées 7,13 et 15 piégées!

Voici donc les conditions:

Code : Tout sélectionner

100 IF X=7 AND Y=1 OR  X=14 AND Y=1 OR  X=20 AND Y=1 THEN GOTO 200
110 IF X=3 AND Y=2 OR  X=10 AND Y=2 OR  X=15 AND Y=2 THEN GOTO 200
120 IF X=7 AND Y=3 OR  X=13 AND Y=3 OR  X=15 AND Y=3 THEN GOTO 200
180 GOTO 50
200 PRINT "BOOM!!"


Comme on l'a vu, trop de codes ralenti le basic, donc, il faut simplifier et effacer les redondances!
On va résonner par ligne... si on est en ligne 1 tester les points X des colonnes!

Donc,

Code : Tout sélectionner

100 IF Y=1 AND (X=7 OR X=14 OR X=20) THEN GOTO 200
110 IF Y=2 AND (X=3 OR X=10 OR X=15) THEN GOTO 200
120 IF Y=3 AND (X=7 OR X=13 OR X=15) THEN GOTO 200
180 GOTO 50
200 PRINT "BOOM!!"
Ca fait cela de moins à tester!

Mais, pourquoi tester toutes les ligne quand X n'a qu'une valeur possible?

Donc,

Code : Tout sélectionner

95 ON Y+1 GOSUB 100,110,120,130,... (Y+1 car y commence à 0)
98 GOTO 50
100 REM
110 IF X=7 OR X=14 OR X=20 THEN GOTO 200
115 RETURN
120 IF X=3 OR X=10 OR X=15 THEN GOTO 200
125 RETURN
130 IF X=7 OR X=13 OR X=15 THEN GOTO 200
135 RETURN
200 PRINT "BOOM!!"
[GOSUB 100+Y*10 pour Spectrum/Zx81]

Nota: Il est possible de faire une réduction plus pointue grâce au tableau de Karnaugh
Mais, l'exécution sera forcement trop gourmande en temps, même si réduite en une seule ligne.

Donc, dans ce cas, les conditions ne passent pas forcement par des IF !

A l'inverse, si le code comprend un trop grand nombre de conditions redondantes...
Il est parfois utile d'utiliser une condition booléenne via une variable.

110 IF (X=7 OR X=14) AND (X=20 OR X=12) THEN GOTO 200
120 IF (X=5 OR X=4) AND (X=20 OR X=12) THEN GOTO 200

Au lieu de répéter (X=20 OR X=12), placez le déclencheur (trigger) dans une variable!

100 LET trig=(X=20 OR X=12)
110 IF (X=7 OR X=14) AND trig THEN GOTO 200
120 IF (X=5 OR X=4) AND trig THEN GOTO 200

La condition est ainsi calculée qu'une fois.
Dernière modification par Xavier le 22 déc. 2015 19:47, modifié 1 fois.
Xavier

Re: BASIC pas si simple...

Message par Xavier »

Tous les Basics: (optimisation vitesse)

"erreur" courante dans de nombreuse routines, les sauts inutiles!

Exemples:

Code : Tout sélectionner

100 LET trig= X AND 1
110 IF trig THEN GOTO 200
120 IF NOT trig THEN GOTO 200
200 GOTO 100
Suggestion:

Code : Tout sélectionner

100 LET trig= X AND 1
110 IF trig THEN GOTO 100
120 IF NOT trig THEN GOTO 100
200 GOTO 100
Idem pour les sauts sur les RETURNs.
Xavier

Re: BASIC pas si simple...

Message par Xavier »

Tous les Basics: (optimisation vitesse)

Evitez d'inclure une routine d'affichage non utile dans un calcul cyclique!
(trouvé dans un programme de labyrinthe)

Code : Tout sélectionner

300 D=INT(RND*5)+1
305 COLOR0,15:locate12,24:PRINT"  Patientez...  ";
310 on D GOTO320,350,380,410,380
400 GOTO300
L'affichage ce renouvellera à chaque cycle de calcul.

Suggestion:

Code : Tout sélectionner

299 COLOR0,15:locate12,24:PRINT"  Patientez...  ";
300 D=INT(RND*5)+1
310 on D GOTO320,350,380,410,380
400 GOTO300
L'affichage de "Patientez...", s'effectue une seule fois et pas à chaque calcul de données aléatoires.
Avatar de l’utilisateur
Totor le Butor
Messages : 2237
Inscription : 07 sept. 2011 16:14
Localisation : Paris - Mezels

Re: BASIC pas si simple...

Message par Totor le Butor »

Super sympa, les trucs pour optimiser le code :D .

Quand on lit, on se dit "c'est une évidence" et puis on regarde le dernier truc qu'on a programmé et là... on pleure :mrgreen: .
Born to bricole
[Rch] Vieux composants électroniques et circuits intégrés toute époque et vieilles cartes .
Xavier

Re: BASIC pas si simple...

Message par Xavier »

Comme tu le dis, cela semble une évidence de nos jours, mais à l'époque, sans imprimante, il était impossible de voir le programme dans sa globalité!
En effet, il était difficile de s'y retrouver dans un listing car il fallait constamment faire des "list" et des "edit"!
De nos jours, les textes défilent avec les barres de déplacement, et il est possible de faire des recherches facilement.
Donc, ce qui nous parait faux, nous saute au yeux plus facilement.
Personnellement, créer un jeux directement sur émulateur ou vrai machine, me stress.
Tout bon programme réalisé à l'époque se préparait sur papier, avant de l'entrer sur la machine.
Sans cette préparation, le programme devient rapidement un programme déstructuré et qui part dans tous les sens!
En mode texte, des copiers, des collers, des déplacements et renumérotations!
Il n'était pas rare de trouver des lignes en doublon dans les programmes, car déplacées ou renumérotées.
C'est pour cela que certaines erreurs semble évidentes, facilement évitables et ridicules.
Daniel
Messages : 17426
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: BASIC pas si simple...

Message par Daniel »

Quelques suggestions supplémentaires :

- Si le Basic permet de choisir les types de variables, n'utilisez pas de nombres en virgule flottante, sauf absolue nécessité. Définissez des variables entières. Par exemple X% au lieu de X en Basic Microsoft, ou, en début de programme :

Code : Tout sélectionner

DEFINTA-Z


- Dans les boucles FOR ... NEXT, si le Basic le permet, ne mettez pas le nom de la variable de boucle après le NEXT. Ecrivez

Code : Tout sélectionner

FOR I%=1 TO 100: NEXT
plutôt que

Code : Tout sélectionner

FOR I%=1 TO 100: NEXT I%
La première forme s'exécute plus rapidement.


- Partout où c'est possible supprimez les espaces. Exemple

Code : Tout sélectionner

IFX%=0THENPRINT"TOTO"ELSEPRINT"TATA":GOTO100
- Evitez de créer des chaînes inutiles, ou de rallonger des chaînes existantes. Par exemple n'écrivez pas

Code : Tout sélectionner

FORI%=0TO9:A$"A"+RIGHT$(STR$(I%),1):PRINTA$:NEXT
mais

Code : Tout sélectionner

A$="A ":FORI%=0TO9:MID$(A$,2)=RIGHT$(STR$(I%),1):PRINTA$:NEXT
L'espace réservé aux chaînes de caractères se remplit quand une chaîne provisoire est créée. L'espace n'est pas récupéré immédiatement, mais seulement quand la fin de l'espace réservé est atteinte. Le Basic réorganise alors les chaînes pour récupérer les trous, et c'est très long, au moins avec le Basic Microsoft. Pour les autres je ne sais pas.
Daniel
L'obstacle augmente mon ardeur.
Xavier

Re: BASIC pas si simple...

Message par Xavier »

J'aimerais ajouter des infos sur ce que Daniel vient d'écrire, pour les basics Sinclair...

Code : Tout sélectionner

IFX%=0THENPRINT"TOTO"ELSEPRINT"TATA":GOTO100
La suppression des espaces n'est une optimisation pour la vitesse, car plus court à lire, mais au niveau de la taille d'encombrement.
Les programmes non sauvegardés en mode texte (option trouvées sur Amstrad, msx, Apple2 etc...) sont encodés en "tokens".

Cela consiste à donner une valeur ASCII en dehors des valeurs d'affichage. Cette méthode permet d'associer une valeur binaire d'un ou de deux octets à un commande, fonction ou signe mathématique.

Par exemple sur Amstrad: "gosub"= 159 ; "input"= 163; "merge"= 171
Ce système rend la mémoire basic impossible à décoder visuellement, mais la taille du programme et réduit à un ou deux octet par commande ou fonction.
Ajouter des espaces ajoute des octets supplémentaire au programme à chaque fois!

Dans le cas de certains Basic, comme le ZX81 et le Spectrum, les espaces sont inclus dans les commandes affichées!
Résultat, l'ajout d'espaces ajoute un espace supplémentaire à la commande.

Code : Tout sélectionner

L'espace réservé aux chaînes de caractères se remplit quand une chaîne provisoire est créée.
Très important pour les Basics avec une "mémoire de variable" flottante.
Sur Zx81 et Spectrum, la mémoire est placée après le basic (écran pour le ZX81), et est dynamique, car ils placent les valeurs des variables dans l'ordre d'initialisation.
Donc, si une variable chaîne est dimensionnée à 3 caractères en début de mémoire "variable" (VARS) (en début de programme), la routine en ROM doit déplacer toutes les valeurs suivantes pour donner de la place à cette donnée.
Résultat, un très court moment d'attente est à prévoir, mais qui peut être répétée.
Le mieux est de créer une valeur de variable non utilisée, juste avant le traitement de la chaîne, pour que le déplacement soit en fin de mémoire incluant les variables.
Sur ZX81 et Spectrum, il existe deux types de variables chaînes: les fixes de taille prédéfinies et les dynamiques.
La fonction DIM a$(1,10) permet de créer une variable simple de dix caractères (dix espaces à l'initialisation) où la fonction a$=a$+"*" est interdite.

Ce qui est "marrant", sur Zx81, c'est que la mémoire écran est placée juste avant la mémoire "variables".
Mais la taille de l'encombrement de la mémoire écran est variable...et a chaque redimensionnement de celui-ci, les données des variables sont automatiquement déplacées... et parfois, un CLS est pénible, car peut durer près d'une seconde!
Répondre