|
|||||||||||||||||||||||||||||||||||||||||||
|
Nous vous proposons aujourd'hui, un excellent article de complément sur les bibliothèques mathématiques écrit par le non moins excellent Dominique Genot. Cet article fait suite à celui de Commodore Revue de mai 1990 (n°23) sur les bibliothèques mathématiques. Dans le susdit article étaient abordées les bibliothèques "mathffp" et "mathtrans". Quelques précisions seront utiles pour les conversions envisagées aujourd'hui : il s'agit de transformer une chaîne alphanumérique en nombre et lycée de Versailles... Que veut dire FFP ? Ces deux bibliothèques permettent de manipuler des nombres entiers ou décimaux qui sont pour cela stockés sous une forme particulière dite FFP : Fast Floating Point (ou encore flottant en simple précision). Cela signifie que le nombre n'est pas stocké sous une forme immédiatement compréhensible. Chaque nombre est codé avec un mot long (4 octets) dont les bits ont la signification suivante : ![]() J'en vois qui toussent... Prenons un exemple en base 10. Le nombre 41,25 peut aussi s'écrire 0,4125x10 exp 2. Dans cette dernière expression, 0,4125 sera appelée la mantisse du nombre et 10 exp 2 est la puissance de 10 associée. Cette écriture signifie que pour retrouver le nombre, il faut prendre la mantisse 0,4125 dans laquelle on décale la virgule deux fois vers la droite. Dans le cas général, la mantisse est un nombre compris entre 1/10 et 1, donc la mantisse est supérieure ou égale à 0,1 et inférieure à 1 et l'exposant indique le nombre de décalages que la virgule a subi en base 10. Or, notre génial microprocesseur calcule en base 2, et il écrira donc les nombres sous la forme : mantisse x 2 exp n. Dans ce cas, la mantisse est un nombre compris entre 1/2 et 1, donc un nombre supérieur ou égal à 0,5 et inférieur à 1 et l'exposant indiquera le nombre de décalages que la virgule a subi quand le nombre est écrit en base 2 (cette écriture est repérée en assembleur par le signe %). Exemple : le nombre 5 peut s'écrire %101, on aura donc comme mantisse %0,101 dans les bits 8 à 31 (en complétant à droite avec des 0), le bit 7 sera mis à 0, et l'exposant +3 (décaler trois fois la virgule à droite pour retrouver le nombre) est codé avec les bits 0 à 6. Remarque : dans tous les cas, il faut coder le signe de l'exposant, c'est-à-dire le sens de décalage de la virgule. En réalité, l'exposant est codé en notation "excess-64" : ce terme aussi barbare qu'intraduisible signifie que l'exposant peut varier de -64 (-$40) à +63 (+$3F) et il sera codé de 0 à 127($7F) (NDLR : l'exposant -$40 est codé par 0 et l'exposant +$3f est codé par 127). Dans l'exemple du nombre 5, l'exposant 3 sera codé avec $43 (%100 0011) donc % (0,) 10100000 00000000 00000000 01000011 soit $ A0000043 C'est cette valeur que l'on obtient (dans D0) en appelant SPFIt avec 5 dans D0 en mode trace... (NDLR : par mode trace, l'auteur entend le suivi pas à pas du programme avec un débogueur quelconque (Seka Devpac...), rien à voir avec le mode trace du 68000). Cette connaissance est-elle vraiment nécessaire ? Elle ne l'est pas pour faire des calculs, car les bibliothèques ont des routines qui convertissent automatiquement (voir cet article : les décalages SPFixet SPFIt). Ces détails sont pourtant utiles pour connaître la précision du calcul effectué. En effet, le plus grand nombre manipulable est calculé en fixant tous les bits à 1 (sauf les bits de signes), ce qui donne : ![]() Ce qui limite davantage, c'est le codage de la mantisse car on ne lui accorde que 24 bits soit au maximum le nombre 0,16777215 soit huit chiffres significatifs dans le meilleur des cas... Ceci explique certaines bizarreries où un calcul donne 12,239999... au lieu de 12,24. Comment remédier à cela ? En accordant davantage de bits à la mantisse, c'est le mode IEEE. Que veut dire IEEE ? C'est l'autre façon de coder un nombre flottant et on l'appelle parfois "double précision" dans un souci de clarté bien compréhensible... Le nombre est alors stocké sur deux mots longs (8 octets) sous la forme suivante : ![]() Cette notation autorise tous les nombres entre -1,8x10 exp 307 et 1,8x10 exp 307 et surtout elle est beaucoup plus précise car la mantisse peut aller jusqu'à $F FFFF FFFF FFFF ! (ce qui autorise 16 chiffres significatifs). Attention : des erreurs d'approximation peuvent se produire si le nombre comporte plus de 16 chiffres... Bien sûr, d'autres bibliothèques sont à utiliser pour ce mode IEEE. Voici un tableau récapitulatif : ![]() Pour simplifier les choses :
![]() Dans la pratique, il suffit de nommer les décalages le plus simplement possible, IEEEDPFIt -> FIt par exemple, et de régler A6 sur une bibliothèque FFP ou IEEE suivant le type de calcul à effectuer (ou utiliser bien sûr des fichiers "include"). Important : une remarque cependant sur les bibliothèques IEEE : toute tâche qui les utilise doit les ouvrir elle-même (et non pas récupérer ailleurs un pointeur sur l'adresse de base) car ces bibliothèques sont reliées à la structure de la tâche qui les a ouvertes. Changement de mode On peut désirer convertir un nombre FFP en nombre IEEE ou l'inverse. D'après le ROM Kernal Manual "Libraries and Devices", il semble qu'il existe un mode hybride appelé "ieee simple précision" codé sur un registre seulement... Il existe en tout cas deux décalages de traduction dans les mathtrans...library : ![]() ![]() Une dernière chose avant de passer à la pratique : pour les programmeurs en C, le mode FFP correspond à la déclaration "float" et le mode IEEE correspond à la déclaration "double". Le C possède bien les fonctions float=afp (chaîne) et fpa (float,chaine) mais ces fonctions travaillent en mode FFP et sont imprécises si le nombre comporte une dizaine de chiffres. Conversion ASCII -> flottant Dans ce qui suit, on suppose que le nombre à convertir est stocké sous forme ASCII dans une chaîne terminée par un octet 0 (voir l'étiquette "ascii" dans le source-exemple). La chaîne est considérée comme formée de quatre parties :
![]() ![]() ![]() ![]() ![]() Je vous laisse découvrir les limites de ce mode en essayant plusieurs chaînes ASCII de la forme : "-4578,5","458.67849", etc. Pour la conversion en mode IEEE, les routines sont légèrement compliquées car il faut considérer des paires de registres, mais le principe est le même : ![]() ![]() ![]() ![]() ![]() Le principe est très peu différent, les opérations étant effectuées en sens inverse. L'exemple suivant convertit un nombre IEEE en une chaîne ASCII, il est à modifier (assez peu) pour convertir un nombre FFP en une chaîne ASCII. ![]() ![]() ![]() ![]() ![]() Applications Un des avantages de la routine DPtoA est qu'elle permet de vérifier en mode trace la validité d'un calcul : il suffit de l'appeler pour traduire le nombre calculé D0/D1 en chaîne ASCII que l'on visualise à l'aide du traceur (fenêtre 3 de Devpac en mode trace = "monam2"). Elle pourrait aussi permettre de déboguer un programme de calcul vicieux qui méditerait trop souvent si vous voyez ce que je veux dire... Par exemple, et pour répondre à la question d'un GL (Gentil Lecteur) du club "Mais-dis-tu-rame-hé", supposons que l'on soit pris d'un désir irrépressible de calculer le carré de e=2,718, on remplacerait la partie "run" du programme précédent par celle-ci : ![]()
|