<?xml version="1.0" encoding="UTF-8" ?>
<!-- RSS generated by PHPBoost on Sun, 12 Apr 2026 09:40:29 +0200 -->

<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title><![CDATA[Wiki MSX Village]]></title>
		<atom:link href="https://msxvillage.fr/syndication/rss/wiki/126" rel="self" type="application/rss+xml"/>
		<link>https://msxvillage.fr</link>
		<description><![CDATA[Derniers articles de la catégorie Programmation]]></description>
		<copyright>(C) 2005-2026 PHPBoost</copyright>
		<language>fr</language>
		<generator>PHPBoost</generator>
		
		
		<item>
			<title><![CDATA[Nombre à virgule fixe]]></title>
			<link>https://msxvillage.fr/wiki/nombre-a-virgule-fixe</link>
			<guid>https://msxvillage.fr/wiki/nombre-a-virgule-fixe</guid>
			<description><![CDATA[Un <strong>nombre à virgule fixe</strong>, c'est simplement un nombre réel (par ex. 3,14) qu'on va coder sur un nombre entier en lui appliquant un facteur (un multiplicateur).<br />
L'intérêt est de pouvoir manipuler de nombres avec une précision inférieur à 1, tout en gardant les bonnes performances de manipulation de nombre entier.<br />
<br />
<h2 class="formatter-title wiki-paragraph-2" id="paragraph-principe">Principe</h2><br />

<br />
Pour comprendre le principe, il suffit d'imaginer un programme qui utiliserait le mètre comme unité finale mais qui aurait besoin à un moment de pouvoir déplacer un objet de moins d&#8217;une unité, disons 0,2 m.<br />
Vu qu'il serait bien trop lourd pour nos vénérables MSX de travailler avec de vrais nombres à virgule flottante (comme les float du C), l'astuce pourrait simplement être de stocker les nombres et de faire ses calculs sous la forme Val = mètres * 100 (en cm donc), puis de convertir en mètre quand c'est nécessaire (mètres = Val / 100). Du coup, pour ajouter 0,2 m, on ajouterait la valeur entière 0,2 * 100 (c-à-d 20). À l'inverse, le nombre entier <strong><span style="color:#0000FF;">42</span><span style="color:#F04343;">13</span></strong> représenterait en fait 42,13 m.<br />
Un tel format serait un nombre à virgule fixe de 2 décimales (100).<br />
Simple. <img src="https://msxvillage.fr/images/smileys/sourire.gif" alt=":)" title=":)" class="smiley" /><br />
<br />
<h2 class="formatter-title wiki-paragraph-2" id="paragraph-format-qm-n">Format Qm.n</h2><br />

<br />
Comme les divisions/multiplications par 100 sont coûteuses, on va plutôt utiliser des facteurs puissance de 2 (1, 2, 4, 8, 16, etc.) comme base pour la partie fractionnelle. Du coup, les divisions/multiplications peuvent être remplacés par des décalages de bits qui sont énormément moins coûteux.<br />
Sur un entier 8 ou 16-bits (les 32-bits sont souvent trop coûteux pour nos Z80), on va donc décider du nombre de bits qui serviront à coder la partie entière et de ceux (le reste) qui serviront à coder la partie fractionnelle.<br />
C&#8217;est le format Q ! Ou plutôt « Qm.n ». (cf. <a href="https://en.wikipedia.org/wiki/Q_(number_format)">Article "Q" sur Wikipédia</a>)<br />
<br />
Par ex., un nombre 8-bits codé au format Q4.4, utilise 4-bits pour l&#8217;entier et 4-bits pour la fraction. Pour convertir une valeur en Q4.4, il suffit de décaler le nombre 4 fois vers la gauche (x << 4), Pour convertir un Q4.4 en valeur, il suffit de décaler le nombre 4 fois vers la droite (x >> 4). Si on l&#8217;utilise pour stocker un nombre non signé, on pourra coder dans un Q4.4 des nombres allant de 0 à 15,9375 (255/16) avec une précision de 0,0625 (1/16).<br />
On peut utiliser avec le Q4.4 n&#8217;importe quelles opérations mathématiques de base tant que tous les termes sont au même format.<br />
<br />
A noter que pour les entiers signés, certains excluent le bit de signe dans la notation.<br />
Du coup, Q7.8 ⇒ 1-bit de signe, 7-bits entier, 8-bits fractionnel.<br />
<br />
<h3 class="formatter-title wiki-paragraph-3" id="paragraph-exemples">Exemples</h3><br />

<br />
Il existe autant de Q qu&#8217;ils y a de combinaisons de bits (ne pas sortir cette phrase de son contexte, hein <img src="https://msxvillage.fr/images/smileys/clap.gif" alt=":oups" title=":oups" class="smiley" />).<br />
Voici quelques exemples que j&#8217;utilise :<br />
- Q2.6 : Entier 8-bits qui permet de coder des chiffres entre -1,0 et 1,0 avec une précision de 0,015625. Très utile pour stocker des vecteurs de direction par ex.<br />
- Q8.8 : Entier 16-bits avec partie entière et fractionnelle sur 8 bits. Très performant à utiliser avec un nombre non-signé. Sinon, il faut prendre qq précautions.<br />
- Q6.10 : Entier 16-bits avec partie entière de 6 bits et fractionnelle sur 10 bits. Permet de manipuler les données en Ko (avec un facteur 1024). Utile pour les petits nombre ayant besoin d&#8217;une très grande précision (~0,001).<br />
<br />
<h3 class="formatter-title wiki-paragraph-3" id="paragraph-conversion">Conversion</h3><br />

<br />
On peut évidemment passer d'un Q à l'autre avec de simple décalage de bits (<img src="https://msxvillage.fr/images/smileys/clap.gif" alt=":oups" title=":oups" class="smiley" />).<br />
Par ex. :<br />
- Q4.4 << 2 ⇒ Q2.6<br />
- Q8.8 >> 4 ⇒ Q12.4<br />
(en cas de valeur signée négative c'est un peu plus compliqué car il faut préserver le signe)<br />
<br />
<h3 class="formatter-title wiki-paragraph-3" id="paragraph-liste-exhaustive">Liste exhaustive</h3><br />

<br />
Voici l'ensemble des format Qm.n possibles pour les entiers 8 et 16-bits avec leur valeur de précision et leurs bornes :<br />
<!-- START HTML -->
<img src="http://msxvillage.fr/upload/qm_n.png" width="600px" />
<!-- END HTML --><br />
<br />
Dispo aussi au format PDF <a href="https://msxvillage.fr/upload/qm_n.pdf">Qm.n.pdf</a><br />
<br />
<h2 class="formatter-title wiki-paragraph-2" id="paragraph-exemple-d-utilisation">Exemple d'utilisation</h2><br />

<br />
Imaginons qu'on doive calculer l'expression 'a x cos(b)', avec 'a' un entier 8 bits.<br />
<br />
On sait que cos(b) est un nombre réel compris entre -1 et 1. On va utiliser une simple table qui va nous donner la valeur de cos(b) pour b. Partons du principe que les valeurs exactes -1 et 1 seront gérées séparément (par exemple à l'aide d'un test avant le calcul), et que l'on ne gère que les angles de 0° à 90°. Donc, on doit stocker des valeurs comprises entre 0 et 0,999999. Pour stocker ce genre de valeurs, le format <strong>Q0.8</strong> non signé est parfait.<br />
<br />
Prenons par exemple cos(45°) = racine carrée (2)/2 = 0.70710678118<br />
Pour coder ce nombre en Q0.8 non signé, il suffit de le multiplier par 256 : 0.70710678118 x 256 = 181.019335984<br />
On ne peut évidemment pas prendre les décimales, donc on ne stocke que la valeur entière : 181 (entier 8 bit).<br />
<br />
Plaçons nous au moment du calcul, lorsqu'on veux faire, par exemple, 33 x cos(45°) = <strong><span style="color:#0000FF;">23.3345237792</span></strong> :<br />
- on prend la valeur de la table pour 45° (181)<br />
- on la multiplies par 33<br />
- on obtient donc un entier 16 bits dont la valeur est 5973<br />
<br />
Cet entier 16 bits est le résultat, codé en <strong>Q8.8</strong>.<br />
Normal, puisqu'en fait, on a multiplié les 2 membres de l''expression par 256 : a x (256 x cos(b)) = 256 x résultat<br />
5973 / 256 = <strong><span style="color:#0000FF;">23.33203125</span></strong>, on a donc une erreur de 0,002, ce qui est acceptable.<br />
<br />
Et pour obtenir la valeur entière, il suffit de garder l'octet haut du résultat.<br />
5973d = 1723h, la valeur entière est donc : 17h = 23d.<br />
<br />
<br />
<h2 class="formatter-title wiki-paragraph-2" id="paragraph-assembleur">Assembleur</h2><br />

<br />
<h3 class="formatter-title wiki-paragraph-3" id="paragraph-exemple">Exemple</h3><br />

<br />
Par ex., lorsqu'un programmeur voudra récupérer la valeur d'un entier 8-bits au format Q4.4, il lui suffit de faire >>4 sur la valeur.<br />
Avec en bonus, la possibilité d'utiliser le dernier bit sorti vers la droite pour faire l'arrondi.<br />
<br />
Imaginons que le résultat d'une série d'opérations donne le nombre 58, soit en format binaire <strong><span style="color:#FF0000;">0011</span></strong><strong><span style="color:#0000FF;">1010</span></strong>b. Ce nombre est en fait la représentation de 3,625 en <strong>Q4.4</strong> (puisque 58/16=3,625). Lorsque l'on va faire >>4 sur cette valeur pour récupérer la valeur entière, il restera bien 3 dans le nombre (<strong>0011</strong>b), et le dernier bit sorti à droite sera 1. Ce qui peut être alors utilisé pour décider de faire l'arrondi vers l'entier supérieur (ou pas).<br />
<br />
Exemple de l'arrondi vers l'entier supérieur en Q4.4 d'une valeur contenue dans 'a' :<br />
<br />
<div class="formatter-container formatter-code"><span class="formatter-title">Code :</span><div class="formatter-content"><code><span style="color: #000000">
<br />;&nbsp;valeur&nbsp;de&nbsp;a&nbsp;>>&nbsp;4<br />srl&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a<br />srl&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a<br />srl&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a<br />srl&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a<br />;&nbsp;ajout&nbsp;du&nbsp;carry&nbsp;(qui&nbsp;contient&nbsp;le&nbsp;dernier&nbsp;bit&nbsp;sorti&nbsp;à&nbsp;droite)<br />adc&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0</span>
</code></div></div><br />
<br />
<h3 class="formatter-title wiki-paragraph-3" id="paragraph-code-optimal">Code optimal</h3><br />

<br />
Voici les façons optimales (en nombre de cycles) pour faire les décalages de bits en Z80 :<br />
<div class="formatter-container formatter-code code-ASM"><span class="formatter-title">Code ASM :</span><div class="formatter-content"><pre style="display:inline;"><pre class="asm" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">; a >> 1 (10cc)</span>
srl    a
<span style="color: #666666; font-style: italic;">; a >> 2 (18cc)</span>
rrca
rrca
<span style="color: #00007f; font-weight: bold;">and</span> a<span style="color: #339933;">,</span> #<span style="color: #ff0000;">0x3F</span>
<span style="color: #666666; font-style: italic;">; a >> 3 (23cc)</span>
rrca
rrca
rrca
<span style="color: #00007f; font-weight: bold;">and</span> a<span style="color: #339933;">,</span> #<span style="color: #ff0000;">0x1F</span>
<span style="color: #666666; font-style: italic;">; a >> 4 (28cc)</span>
rlca
rlca
rlca
rlca
<span style="color: #00007f; font-weight: bold;">and</span> a<span style="color: #339933;">,</span> #<span style="color: #ff0000;">0x0F</span>
<span style="color: #666666; font-style: italic;">; a >> 5 (23cc)</span>
rlca
rlca
rlca
<span style="color: #00007f; font-weight: bold;">and</span> a<span style="color: #339933;">,</span> #<span style="color: #ff0000;">0x07</span>
<span style="color: #666666; font-style: italic;">; a >> 6 (18cc)</span>
rlca
rlca
<span style="color: #00007f; font-weight: bold;">and</span> a<span style="color: #339933;">,</span> #<span style="color: #ff0000;">0x03</span>
<span style="color: #666666; font-style: italic;">; a >> 7 (13cc)</span>
rlca
<span style="color: #00007f; font-weight: bold;">and</span> a<span style="color: #339933;">,</span> #<span style="color: #ff0000;">0x01</span>
<span style="color: #666666; font-style: italic;">; a << 1 (5cc)</span>
<span style="color: #00007f; font-weight: bold;">add</span> a<span style="color: #339933;">,</span> a
<span style="color: #666666; font-style: italic;">; a << 2 (10cc)</span>
<span style="color: #00007f; font-weight: bold;">add</span> a<span style="color: #339933;">,</span> a
<span style="color: #00007f; font-weight: bold;">add</span> a<span style="color: #339933;">,</span> a
<span style="color: #666666; font-style: italic;">; a << 3 (15cc)</span>
<span style="color: #00007f; font-weight: bold;">add</span> a<span style="color: #339933;">,</span> a
<span style="color: #00007f; font-weight: bold;">add</span> a<span style="color: #339933;">,</span> a
<span style="color: #00007f; font-weight: bold;">add</span> a<span style="color: #339933;">,</span> a
<span style="color: #666666; font-style: italic;">; a << 4 (20cc)</span>
<span style="color: #00007f; font-weight: bold;">add</span> a<span style="color: #339933;">,</span> a
<span style="color: #00007f; font-weight: bold;">add</span> a<span style="color: #339933;">,</span> a
<span style="color: #00007f; font-weight: bold;">add</span> a<span style="color: #339933;">,</span> a
<span style="color: #00007f; font-weight: bold;">add</span> a<span style="color: #339933;">,</span> a
<span style="color: #666666; font-style: italic;">; a << 5 (23cc)</span>
rrca
rrca
rrca
<span style="color: #00007f; font-weight: bold;">and</span> a<span style="color: #339933;">,</span> #<span style="color: #ff0000;">0xE0</span>
<span style="color: #666666; font-style: italic;">; a << 6 (18cc)</span>
rrca
rrca
<span style="color: #00007f; font-weight: bold;">and</span> a<span style="color: #339933;">,</span> #<span style="color: #ff0000;">0xC0</span>
<span style="color: #666666; font-style: italic;">; a << 7 (13cc)</span>
rrca
<span style="color: #00007f; font-weight: bold;">and</span> a<span style="color: #339933;">,</span> #<span style="color: #ff0000;">0x80</span>
&nbsp;</pre></pre></div></div><br />
<br />
Chaque format <em>Qm.n</em> a donc un coup de conversion différents.<br />
Temps de conversion in/out :<br />
- Q7.1 : 15cc<br />
- Q6.2 : 28cc<br />
- Q5.3 : 38cc<br />
- Q4.4 : 48cc<br />
- Q3.5 : 46cc<br />
- Q2:6 : 36cc<br />
- Q1:7 : 26cc<br />
<br />
<h2 class="formatter-title wiki-paragraph-2" id="paragraph-langage-c">Langage C</h2><br />

<br />
Et pour les utilisateurs de C, il est conseillé de passer par des macros de conversion.<br />
<br />
Par ex. :<br />
<div class="formatter-container formatter-code code-C"><span class="formatter-title">Code C :</span><div class="formatter-content"><pre style="display:inline;"><pre class="c" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// Unit conversion (Pixel <> Q10.6)</span>
<span style="color: #339933;">#define UNIT_TO_PX(a)                (u8)((a) / 64)</span>
<span style="color: #339933;">#define PX_TO_UNIT(a)                (i16)((a) * 64)</span>
&nbsp;</pre></pre></div></div>a<br />
On laisse les multiplications/divisions par 64 pour permettre au compilateur de pouvoir adapter ses opérations en fonction du type de data qu'on lui donne.<br />
Si on prend une variable <em>int16 x</em> qui contient un nombre au format Q10.6, on peux faire ce genre d'opérations :<br />
<div class="formatter-container formatter-code code-C"><span class="formatter-title">Code C :</span><div class="formatter-content"><pre style="display:inline;"><pre class="c" style="font-family:monospace;">&nbsp;
<span style="color: #339933;">#define PI PX_TO_UNIT(3.14159265f) // Le compilateur va faire la conversion en float, puis convertir en int (précision optimale)</span>
<span style="color: #993333;">uint8</span> nbPixel <span style="color: #339933;">=</span> <span style="color: #0000dd;">10</span><span style="color: #339933;">;</span>
x <span style="color: #339933;">+=</span> PX_TO_UNIT<span style="color: #009900;">&#40;</span>nbPixel<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// Le compilateur va faire la conversion via des décalages de bits (vitesse optimale)</span>
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>x <span style="color: #339933;">></span> <span style="color: #0000dd;">2</span><span style="color: #339933;">*</span>PI<span style="color: #009900;">&#41;</span> <span style="color: #666666; font-style: italic;">// A noter une petite perte de précision car le x2 va être fait après la conversion en int</span>
    x <span style="color: #339933;">=</span> PI<span style="color: #339933;">;</span>
&nbsp;</pre></pre></div></div><br />
<br />
L'autre gros avantage, c'est qu'on peux ainsi changer la précision de son unité sans devoir retoucher tout son code.]]></description>
			<pubDate>Thu, 01 Sep 2022 22:17:27 +0200</pubDate>
			
		</item>
		
		<item>
			<title><![CDATA[Programmation]]></title>
			<link>https://msxvillage.fr/wiki/programmation</link>
			<guid>https://msxvillage.fr/wiki/programmation</guid>
			<description><![CDATA[Liste des articles sur la programmation]]></description>
			<pubDate>Fri, 26 Feb 2021 21:35:17 +0100</pubDate>
			
		</item>
		
	</channel>
</rss>
