Cette page vous donne les différences entre la révision choisie et la version actuelle de la page.
virgule_fixe [2015/06/30 18:54] gbdivers |
virgule_fixe [2016/07/05 18:53] (Version actuelle) gbdivers |
||
---|---|---|---|
Ligne 1: | Ligne 1: | ||
- | ^ Chapitre précédent ^ [[programmez_avec_le_langage_c|Sommaire principal]] ^ Chapitre suivant ^ | + | ^ [[complex|Chapitre précédent]] ^ [[programmez_avec_le_langage_c|Sommaire principal]] ^ [[ratio|Chapitre suivant]] ^ |
- | ====== Les nombres à virgule fixe ====== | + | ====== [Aller plus loin] Les nombres à virgule fixe ====== |
===== Limitation des nombres réels ===== | ===== Limitation des nombres réels ===== | ||
- | Les nombres réels sont intéressants, puisqu'ils permettent de représenter des nombres plus grands que les nombres entiers. Si par exemple, vous essayez d’exécuter le code suivant, vous obtiendrez une erreur : | + | Les nombres réels sont intéressants, puisqu'ils permettent de représenter des nombres plus grands que les nombres entiers. Si par exemple, vous essayez d’exécuter le code suivant : |
<code cpp main.cpp> | <code cpp main.cpp> | ||
Ligne 16: | Ligne 16: | ||
</code> | </code> | ||
- | affiche (seules les premières erreurs sont copiées ici) : | + | vous obtiendrez une erreur (seules les premières erreurs sont copiées ici) : |
<code> | <code> | ||
Ligne 34: | Ligne 34: | ||
La seconde erreur "ambiguous overload" indique que le compilateur ne sait pas comment afficher ce nombre (plus précisément, il ne sait pas quel opérateur ''<<'' utiliser avec ''std::cout'' pour afficher ce nombre). | La seconde erreur "ambiguous overload" indique que le compilateur ne sait pas comment afficher ce nombre (plus précisément, il ne sait pas quel opérateur ''<<'' utiliser avec ''std::cout'' pour afficher ce nombre). | ||
- | Note : ce nombre n'a pas été choisit au hasard. Il s'agit du plus grand nombre représentable avec les types de base du C++, plus un. Vous verrez par la suite comment obtenir des informations sur les types, comme par exemple la valeur maximal possible. | + | Note : ce nombre n'a pas été choisit au hasard. Il s'agit du plus grand nombre représentable avec les types de base du C++, plus un. Vous verrez par la suite comment obtenir des informations sur les types, comme par exemple la valeur maximale possible. |
- | Si on modifie un tout petit peu ce code (en ajoutant une décimale), pour utiliser des nombres réels, le compilateur ne produit plus d'erreur : | + | Si on modifie un tout petit peu ce code (en ajoutant une décimale), pour utiliser un nombre réel, le compilateur ne produit plus d'erreur : |
<code cpp main.cpp> | <code cpp main.cpp> | ||
Ligne 58: | Ligne 58: | ||
Une littérale est représentée par une valeur et un type. Le compilateur prend en compte les deux, pas uniquement la valeur.</note> | Une littérale est représentée par une valeur et un type. Le compilateur prend en compte les deux, pas uniquement la valeur.</note> | ||
- | Pour autant, les nombres réels ne sont pas parfaits non plus (sinon, on ne s’embêterait pas a faire la distinction entre entiers et réels). Prenons un autre code d'exemple : | + | Pour autant, les nombres réels ne sont pas parfaits non plus (sinon, on ne s’embêterait pas à faire la distinction entre entiers et réels). Prenons un autre code d'exemple : |
<code cpp main.cpp> | <code cpp main.cpp> | ||
Ligne 76: | Ligne 76: | ||
</code> | </code> | ||
- | On a donc deux nombres, représentées dans le premier cas par des entiers et dans le second par des réels (notez la décimale). Ces deux nombres sont grands, mais peuvent être représentée sans problème par des entiers en C++ (plus précisément par le type ''long long int'', que vous verrez ensuite). La différence entre ces deux nombres vaut un. | + | On a donc deux nombres, représentées dans le premier cas par des entiers et dans le second par des réels (notez la décimale). Ces deux nombres sont grands, mais peuvent être représentés sans problème par des entiers en C++ (plus précisément par le type ''long long int'', que vous verrez ensuite). La différence entre ces deux nombres vaut un. |
Dans tous les cas, les nombres en C++ sont représentés par un nombre fini d'octets dans la mémoire des ordinateurs. Il n'est donc pas possible de représenter tous les nombres possibles (ce qui n'aurait de toute façon aucun sens, puisque qu'il existe une infinité de nombres réels). Les nombres réels peuvent représenter des nombres plus grands que les nombres entiers parce qu'ils ne peuvent pas représenter les grands nombres avec la même précision que les nombres entiers. | Dans tous les cas, les nombres en C++ sont représentés par un nombre fini d'octets dans la mémoire des ordinateurs. Il n'est donc pas possible de représenter tous les nombres possibles (ce qui n'aurait de toute façon aucun sens, puisque qu'il existe une infinité de nombres réels). Les nombres réels peuvent représenter des nombres plus grands que les nombres entiers parce qu'ils ne peuvent pas représenter les grands nombres avec la même précision que les nombres entiers. | ||
Ligne 82: | Ligne 82: | ||
Dans le code d'exemple précédent, les nombres entiers ne sont pas arrondis et le calcul est juste. Au contraire, les nombres réels sont arrondis et sont représentées par la même valeur en mémoire. Le calcul se fait donc sur la même valeur et le résultat est nul. | Dans le code d'exemple précédent, les nombres entiers ne sont pas arrondis et le calcul est juste. Au contraire, les nombres réels sont arrondis et sont représentées par la même valeur en mémoire. Le calcul se fait donc sur la même valeur et le résultat est nul. | ||
- | <note>Encore une fois, il est important d'insister la dessus : les types ont une grande importance en C++. Le choix du type peut modifier complètement le résultat d'un calcul. Faites bien attention a cela, c'est une erreur qui revient souvent.</note> | + | <note>Encore une fois, il est important d'insister là-dessus : les types ont une grande importance en C++. Le choix du type peut modifier complètement le résultat d'un calcul. Faites bien attention à cela, c'est une erreur qui revient souvent.</note> |
===== Principe et arithmétique ===== | ===== Principe et arithmétique ===== | ||
Ligne 98: | Ligne 98: | ||
</code> | </code> | ||
- | En C++, il est possible de créer un nouveau type de nombre, qui permet de représenter plus facilement des nombres à virgule fixe, mais vous verrez cela dans la partie sur la programmation objet. Dans ce chapitre, nous allons simplement utiliser un facteur directement dans le code. Ce n'est pas l’idéal en termes de conception, mais c'est suffisant pour le moment, pour étudier le fonctionnement de cette représentation. | + | En C++, il est possible de créer un nouveau type de nombre, qui permet de représenter plus facilement des nombres à virgule fixe, mais vous verrez cela dans la partie sur la programmation objet. Dans ce chapitre, nous allons simplement utiliser un facteur directement dans le code. Ce n'est pas l’idéal en termes de conception, mais c'est suffisant pour le moment pour étudier le fonctionnement de cette représentation. |
- | Définir une représentation n'est pas suffisante, il faut également définir les opérations arithmétiques de base. Pour l'addition et la soustraction, l'utilisation des opérateurs par défaut des entiers fonctionnent sans problème. | + | Définir une représentation n'est pas suffisante, il faut également définir les opérations arithmétiques de base. Pour l'addition et la soustraction, les opérateurs par défaut des entiers fonctionnent sans problème. |
<code> | <code> | ||
Ligne 131: | Ligne 131: | ||
===== Facteurs non multiples de dix ===== | ===== Facteurs non multiples de dix ===== | ||
- | Supposons que vous souhaitez compter de 0 à 10 avec un pas de un tiers (cela signifie que vous incrémenter votre compteur de 1/3 a chaque fois). Pour cela, vous allez écrire un code similaire au code suivant (en pseudo-code, pas en C++) : | + | Supposons que vous souhaitez compter de 0 à 10 avec un pas de un tiers (cela signifie que vous incrémentez votre compteur de 1/3 à chaque fois). Pour cela, vous allez écrire un code similaire au code suivant (en pseudo-code, pas en C++) : |
<code> | <code> | ||
Ligne 140: | Ligne 140: | ||
Remarque : un identifiant comme ''compteur'', qui permet de se souvenir d'une valeur, est appelée une variable. Vous verrez cela dans les prochains cours. | Remarque : un identifiant comme ''compteur'', qui permet de se souvenir d'une valeur, est appelée une variable. Vous verrez cela dans les prochains cours. | ||
- | Si vous répétez ce calcul, la différence entre la valeur calculée et la valeur correcte attendu va progressivement augmenter. Le graphique suivant représente l'erreur de calcul en fonction de la valeur du compteur : | + | Si vous répétez ce calcul, la différence entre la valeur calculée et la valeur correcte attendue va progressivement augmenter. Le graphique suivant représente l'erreur de calcul en fonction de la valeur du compteur : |
{{ :errors.png |}} | {{ :errors.png |}} | ||
- | Note : pour mieux voir le phénomène, j'ai volontairement utilisée des nombres réels sur 32 bits (simple précision). Il existe des types de nombres réels plus précis, mais ce n'est pas important ici. Le problème existe avec tous les types de nombres réels, la seule différence est qu'il met plus de temps a apparaître. | + | Note : pour mieux voir le phénomène, j'ai volontairement utilisé des nombres réels sur 32 bits (simple précision). Il existe des types de nombres réels plus précis, mais ce n'est pas important ici. Le problème existe avec tous les types de nombres réels, la seule différence est qu'il met plus de temps à apparaître. |
Vous voyez que l'erreur devient assez vite importante. Selon vos besoins, vous pouvez accepter les valeurs en dessous de 1000, mais l'erreur devient trop importante au-delà. | Vous voyez que l'erreur devient assez vite importante. Selon vos besoins, vous pouvez accepter les valeurs en dessous de 1000, mais l'erreur devient trop importante au-delà. | ||
- | La solution est assez simple (vous l'aurez devinez, vu que l'on est dans le chapitre sur les nombres à virgule fixe) : il suffit d'utiliser un compteur entier, qui sera incrémenter de 1 a chaque fois. La valeur du compteur réel sera obtenu en divisant par 3. | + | La solution est assez simple (vous l'aurez deviné, vu que l'on est dans le chapitre sur les nombres à virgule fixe) : il suffit d'utiliser un compteur entier, qui sera incrémenté de 1 à chaque fois. La valeur du compteur réel sera obtenue en divisant par 3. |
<code> | <code> | ||
Ligne 155: | Ligne 155: | ||
</code> | </code> | ||
- | Avec un compteur réel, si on compte jusque 10000, il y aura donc 30000 additions réelles, chaque addition ajoutant une erreur (presque infime) de calcul. Ces erreurs vont s'accumuler, jusqu'au point de ne plus être négligeable. | + | Avec un compteur réel, si on compte jusqu'à 10 000, il y aura 30 000 additions réelles, chaque addition ajoutant une erreur (presque infime) de calcul. Ces erreurs vont s'accumuler, jusqu'au point de ne plus être négligeables. |
- | Avec le compteur entier, comme chaque addition est exacte, les 30000 additions ne produisent pas d'erreur de calcul. La seule opération réalisée sur des nombres réels (donc avec une erreur de précision) est la division par 3. L'erreur de calcul finale est donc l'erreur sur une seule opération réelle, ce qui reste négligeable. | + | Avec le compteur entier, comme chaque addition est exacte, les 30 000 additions ne produisent pas d'erreur de calcul. La seule opération réalisée sur des nombres réels (donc avec une erreur de précision) est la division par 3. L'erreur de calcul finale est donc l'erreur sur une seule opération réelle, ce qui reste négligeable. |
- | <note>Le code pour réaliser ce test est relativement simple. Cependant, vous imaginez bien qu'il n'est pas possible de faire cela en écrivant 30000 fois la ligne de code C++ pour faire l'addition. Pour cela, on va utiliser une boucle, qui sera vu par la suite. L’écriture de ce code sera proposée comme exercice.</note> | + | <note>Le code pour réaliser ce test est relativement simple. Cependant, vous imaginez bien qu'il n'est pas possible de faire cela en écrivant 30 000 fois la ligne de code C++ pour faire l'addition. Pour cela, on va utiliser une boucle qui sera vue par la suite. L’écriture de ce code sera proposée comme exercice.</note> |
===== Lecture complémentaire ===== | ===== Lecture complémentaire ===== | ||
- | Voir l'article sur Wikipedia : [[https://en.wikipedia.org/wiki/Fixed-point_arithmeti|Fixed-point arithmetic]]. | + | Voir l'article sur Wikipedia : [[https://en.wikipedia.org/wiki/Fixed-point_arithmetic|Fixed-point arithmetic]]. |
- | ^ Chapitre précédent ^ [[programmez_avec_le_langage_c|Sommaire principal]] ^ Chapitre suivant ^ | + | ^ [[complex|Chapitre précédent]] ^ [[programmez_avec_le_langage_c|Sommaire principal]] ^ [[ratio|Chapitre suivant]] ^ |
{{tag> Cours C++}} | {{tag> Cours C++}} |