Problème compteur incrémentale et reste division euclidienne
Anonymous
-
Utilisateur anonyme -
Utilisateur anonyme -
Bonjour,
Avec le code suivant :
Nous sommes bien d'accord que les résultat on un coefficient 10 d'écart mais voilà la sortie n'est pas ça.
Voici ce que j'ai :
Si vous avez une idée de où cela peut venir.
Bon courage
Avec le code suivant :
using System;
using System.Threading;
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
double a = 0;
int b = 0;
for(int i=0; i<=33;i++)
{
Console.WriteLine("double : "+a);
a = (a + 0.1) % 1.1;
Console.WriteLine("entier : "+b);
b = (b + 1) % 11;
Console.WriteLine(Environment.NewLine);
Thread.Sleep(200);
}
Console.ReadLine();
}
}
}
Nous sommes bien d'accord que les résultat on un coefficient 10 d'écart mais voilà la sortie n'est pas ça.
Voici ce que j'ai :
double : 0
entier : 0
double : 0,1
entier : 1
double : 0,2
entier : 2
double : 0,3
entier : 3
double : 0,4
entier : 4
double : 0,5
entier : 5
double : 0,6
entier : 6
double : 0,7
entier : 7
double : 0,8
entier : 8
double : 0,9
entier : 9
double : 1
entier : 10
double : 1,1
entier : 0
double : 0,0999999999999999
entier : 1
double : 0,2
entier : 2
double : 0,3
entier : 3
double : 0,4
entier : 4
double : 0,5
entier : 5
double : 0,6
entier : 6
double : 0,7
entier : 7
double : 0,8
entier : 8
double : 0,9
entier : 9
double : 1
entier : 10
double : 1,1
entier : 0
double : 0,0999999999999999
entier : 1
double : 0,2
entier : 2
double : 0,3
entier : 3
double : 0,4
entier : 4
double : 0,5
entier : 5
double : 0,6
entier : 6
double : 0,7
entier : 7
double : 0,8
entier : 8
double : 0,9
entier : 9
double : 1
entier : 10
double : 1,1
entier : 0
Si vous avez une idée de où cela peut venir.
Bon courage
Configuration: Windows / Firefox 74.0 / Visual Studio Community 2019
16.4.2
16.4.2
A voir également:
- Division euclidienne word
- Word 2013 - Télécharger - Traitement de texte
- Tableau word - Guide
- Espace insécable word - Guide
- Word et excel gratuit - Guide
- Supprimer page word - Guide
7 réponses
yg_be
Messages postés
24281
Date d'inscription
Statut
Contributeur
Dernière intervention
Ambassadeur
1 585
bonjour, ce serait plus clair si tu montrait le résultat que tu attends, qui est probablement différent du résultat que tu obtiens.
anonymous
Comme je l'ai dit les résultats devraient avoir un coef 10 d'écart. Si b = 1, a = 0.1 et sinon le résultat de a doit s'incrémenté de 0 à 1 par pas de 0.1. Je précise que le résultats b est correct.
Bonjour
et merci à Chris94 d'avoir corrigé ta coloration syntaxique, tu as essayé de t'en servir et c'est bien, mais dans ce petit tuto il est décrit comme bien l'utiliser https://codes-sources.commentcamarche.net/faq/11288-les-balises-de-code
Venons à ta question
Sauf erreur de ma part, si....
Il n'y a que pour le dernier
C'est ça ton problème?
et merci à Chris94 d'avoir corrigé ta coloration syntaxique, tu as essayé de t'en servir et c'est bien, mais dans ce petit tuto il est décrit comme bien l'utiliser https://codes-sources.commentcamarche.net/faq/11288-les-balises-de-code
Venons à ta question
Nous sommes bien d'accord que les résultat on un coefficient 10 d'écart mais voilà la sortie n'est pas ça.
Sauf erreur de ma part, si....
double : 0 entier : 0 //0 * 10 est bien égal à zéro double : 0,1 entier : 1 //0,1 * 10 est bien égal à 1 double : 0,2 entier : 2 //0,2 * 10 est bien égal à 2 double : 0,3 entier : 3 //0,3 * 10 est bien égal à 3 //etc...
Il n'y a que pour le dernier
double : 1,1 // ce résultat est incohérent, puisqu'on divise par 1.1, il ne devrait pas pouvoir y avoir un reste de 1.1 entier : 0
C'est ça ton problème?
L'informatique, n'est jamais juste.
C'est toujours un choix au plus proche possible.
Dans la vraie vie, on peut écrire une infinité de nombres parce « qu’il suffit d’ajouter un chiffre » pour qu’il se concrétise.
L’informatique vient de l’électronique et là ça se complique, un nombre à une taille définit de bits qui est directement lié à la technologie.
Et on fait avec.
Du coup, les nombres à virgule flottantes sont utilisés pour représenter un nombre décimal
Ici https://forums.commentcamarche.net/forum/affich-35846831-erreur-de-calcul#3
J’ai proposé une explication un peu généraliste.
DalFab et Reiverax ont par la suite donné des precisions.
Tu peux aussi lire le paragraphe « l’éternel problème de la virgule qui part en couille » http://sametmax.com/les-nombres-en-python/
Le 0.0999999999 est directement une manifestation de cela.
Il y a fort à parier que le 1.1 aussi, je vais faire quelques tests de mon coté
C'est toujours un choix au plus proche possible.
Dans la vraie vie, on peut écrire une infinité de nombres parce « qu’il suffit d’ajouter un chiffre » pour qu’il se concrétise.
L’informatique vient de l’électronique et là ça se complique, un nombre à une taille définit de bits qui est directement lié à la technologie.
Et on fait avec.
Du coup, les nombres à virgule flottantes sont utilisés pour représenter un nombre décimal
Ici https://forums.commentcamarche.net/forum/affich-35846831-erreur-de-calcul#3
J’ai proposé une explication un peu généraliste.
DalFab et Reiverax ont par la suite donné des precisions.
Tu peux aussi lire le paragraphe « l’éternel problème de la virgule qui part en couille » http://sametmax.com/les-nombres-en-python/
Le 0.0999999999 est directement une manifestation de cela.
Il y a fort à parier que le 1.1 aussi, je vais faire quelques tests de mon coté
pour moi, l'ordinateur est tout-à-fait capable de faire des calculs précis, il est même incapable de faire des approximations.
en choisissant d'utiliser "double" pour le nombre 1,1, le programmeur choisi, peut-être sans s'en rendre compte, de transformer le nombre 1,1 en un autre nombre, légèrement différent. le programmeur fait ce choix sans doute par facilité, et c'est ce choix qui conduit à un résultat correct, mais différent de ce que le programmeur attend.
en choisissant d'utiliser "double" pour le nombre 1,1, le programmeur choisi, peut-être sans s'en rendre compte, de transformer le nombre 1,1 en un autre nombre, légèrement différent. le programmeur fait ce choix sans doute par facilité, et c'est ce choix qui conduit à un résultat correct, mais différent de ce que le programmeur attend.
Bon alors en décomposant le calcul, je n'arrive pas à voir à quel moment le petit epsilon qui nous embête se glisse.
Par contre, si j'applique un simple arrondi à
Je ne sais pas exactement comment est codé l'arrondi sur un double, mais il à un effet de "remise à zéro" de la mantisse et de l'exposant quand une multitude d'opérations finit par la mettre un peu à mal.
Attention cependant, l'arrondi informatique n'est pas l'arrondi mathématique Français.
C'est l'arrondi monétaire international.
Ces 2 arrondis donnent 2.
Dans le cas de 1.5, l'acheteur va payer 2, il perd donc 0.5. Dans le cas de 2.5, il payera 2, c'est le vendeur qui perd 0.5.
Cette règle permet statistiquement de répartir gain et perte équitablement entre acheteur et vendeur.
Elle s'applique quelque soit le nombre de décimales,
1.111111111111115 => 1.11111111111112
1.111111111111125 => 1.11111111111112
On l'appelle aussi l'arrondi au pair le plus proche.
Normalement dans le calcul actuel, il n'y a pas de raison de tomber sur un cas comme cela mais, mieux va le savoir.
double a = 0;
int b = 0;
for (int i = 0; i <= 33; i++)
{
Console.Write("'a': {0}\t\t",a);
a += 0.1;
Console.Write("'a' + 0.1: {0}\t\t",a);
a %= 1.1;
Console.WriteLine("'a' % 1.1: {0}",a);
Console.WriteLine("entier : " + b);
b = (b + 1) % 11;
Console.WriteLine(Environment.NewLine);
}
Console.ReadLine();
Par contre, si j'applique un simple arrondi à
a += 0.1, il n'y a plus d'erreur.
double a = 0;
int b = 0;
for (int i = 0; i <= 33; i++)
{
Console.Write("'a': {0}\t\t",a);
a = Math.Round(a + 0.1, 1);
Console.Write("'a' + 0.1: {0}\t\t",a);
a %= 1.1;
Console.WriteLine("'a' % 1.1: {0}",a);
Console.WriteLine("entier : " + b);
b = (b + 1) % 11;
Console.WriteLine(Environment.NewLine);
}
Console.ReadLine();
Je ne sais pas exactement comment est codé l'arrondi sur un double, mais il à un effet de "remise à zéro" de la mantisse et de l'exposant quand une multitude d'opérations finit par la mettre un peu à mal.
Attention cependant, l'arrondi informatique n'est pas l'arrondi mathématique Français.
C'est l'arrondi monétaire international.
Console.WriteLine("Arrondi de 1.5: {0}", Math.Round(1.5));
Console.WriteLine("Arrondi de 2.5: {0}", Math.Round(2.5));
Ces 2 arrondis donnent 2.
Dans le cas de 1.5, l'acheteur va payer 2, il perd donc 0.5. Dans le cas de 2.5, il payera 2, c'est le vendeur qui perd 0.5.
Cette règle permet statistiquement de répartir gain et perte équitablement entre acheteur et vendeur.
Elle s'applique quelque soit le nombre de décimales,
1.111111111111115 => 1.11111111111112
1.111111111111125 => 1.11111111111112
On l'appelle aussi l'arrondi au pair le plus proche.
Normalement dans le calcul actuel, il n'y a pas de raison de tomber sur un cas comme cela mais, mieux va le savoir.
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question
Hé bien, je ne pensais pas que ce post déchaînerait autant de passion. Je précise que le programme est juste un exemple simple pour bien montrer le problème. Et venant de l'informatique embarquée je n'avais jamais eu ce problème mais là visual studio ne voulait pas que j'utilise un float avec la division euclidienne et ma proposé le double. Mais je vais regarder le décimal qui peut être intéressant. Merci à tous pour vos réponses. Et n'hésitez pas à en donner d'autres, les problèmes ont toujours de multiples solutions.
P.S : C'est toujours anonymous mais le correcteur orthographique en a décidé autrement.
P.S : C'est toujours anonymous mais le correcteur orthographique en a décidé autrement.
je pense qu'en informatique embarquée, personne ne fera jamais un modulo avec un nombre non entier. un peu parce que c'est inutile, beaucoup parce que le résultat est imprévisible, comme tu l'observes.
et, surtout, personne ne s’inquiétera de la différence entre 0,09999999 et 0.1: pourquoi t'en inquiètes-tu, que vas-tu faire avec ces résultats?
et, surtout, personne ne s’inquiétera de la différence entre 0,09999999 et 0.1: pourquoi t'en inquiètes-tu, que vas-tu faire avec ces résultats?
Comme je l'ai précisé en informatique embarquée je n'ai jamais eu ce problème. Et un modulo fait directement avec un nombre décimal m'évite de faire un calcul en plus. Si je fait le calcule directe le résultat est bon. Le problème c'est que à chaque boucle les erreurs s'ajoutent et rapidement j'ai des résultats qui ne correspondent pas à ce que j'attends. Et donc si par exemple je veux créer un signal triangle à une fréquence de 100Hz je vais vite avoir une dérive l'amplitude. Et surtout si je veux 0,1 je ne veux pas 0,09999999. Car après au lieu d'avoir 0 j'ai 1.1 ce qui est la très différents
je pense que tu aurais eu exactement le même résultat si tu avais ainsi incorrectement programmé en informatique embarquée.
si tu veux 0,1, n'utilise pas de double dans des langages tels que le C, à moins de comprendre et contrôler l'impact de l'utilisation de double.
et, surtout, n'utilise pas de modulo avec des nombres (non entiers) dont tu ne maîtrises pas la valeur.
si tu veux 0,1, n'utilise pas de double dans des langages tels que le C, à moins de comprendre et contrôler l'impact de l'utilisation de double.
et, surtout, n'utilise pas de modulo avec des nombres (non entiers) dont tu ne maîtrises pas la valeur.
Avec le float, c'est pire, y'a moins de bits, donc moins de précision.
Faire le calcul avec un entier et diviser le résultat par 10 pour l'affichage (ou la fourniture) reste le meilleur moyen de ne jamais avoir d'erreur de virgule flottante.
Faire le calcul avec un entier et diviser le résultat par 10 pour l'affichage (ou la fourniture) reste le meilleur moyen de ne jamais avoir d'erreur de virgule flottante.
PS, juste pour répondre à
https://www.developpez.com/actu/222280/Un-bogue-informatique-avait-contraint-le-Boeing-787-a-etre-redemarre-tous-les-248-jours-pour-eviter-une-interruption-totale-du-systeme-electrique/
C'est pas le même problème, mais c'est la même raison sous jacente, derrière l'informatique y'a de l'électronique ;)
Et venant de l'informatique embarquée je n'avais jamais eu ce problème
https://www.developpez.com/actu/222280/Un-bogue-informatique-avait-contraint-le-Boeing-787-a-etre-redemarre-tous-les-248-jours-pour-eviter-une-interruption-totale-du-systeme-electrique/
C'est pas le même problème, mais c'est la même raison sous jacente, derrière l'informatique y'a de l'électronique ;)
Alors le float dispose moins de nombre après la virgule certe mais 0 à 1.1 il n'y a qu'un chiffre après la virgule. Deuxièmement ça n'a strictement rien avoir avec un dépassement mémoire. Ton exemple est hors propos. Et si tu as remarqué le code est fait de tel sorte pour qu'il n'y ai jamais de dépassement vu que a ne dépasse jamais 1, enfin si le calcule était juste. Si j'avais fait des opérations mathématiques directement en analogique avec des AOP j'accepterais l'erreur. Surtout que comme je l'ai dit c'est la première fois que ça m'arrive.
Alors le float dispose moins de nombre après la virgule certe mais 0 à 1.1 il n'y a qu'un chiffre après la virgule
c'est incorrect comme raisonnement, d'une parce que le principe même du nombre à virgule flottante c'est de toujours avoir le même nombre de chiffre avant et après la virgule, et d'autre part parce que ça n'est pas codé en base 10 mais en base 2.
D'ailleurs, Dalfab dans le premier lien que je t'ai donné (à se demander si tu es allé voir?) décrit très bien le problème de 0.1 qui n'est pas fini en base 2
Ton exemple est hors proposc'est pour cela que j'ai ajouté
C'est pas le même problème, mais c'est la même raison sous jacente, derrière l'informatique y'a de l'électroniqueet aussi pour donner 2 exemples de bugs connus dans l'informatique embarquée, mais ce ne sont pas les seuls (et loin de là).
La nuit portant conseil, et hier je planchais sur une autre question en même temps.
J'ai négligé un point important de ton symptôme, Console.Write(line) applique un arrondi.
Pour voir la valeur vraie des variables, pas le choix, il faut espionner en pas à pas.
En repartant de ce code
J'ai mis un point d'arrêt et 2 espions (il est possible que cet espion arrondissent aussi, mais on y voit quand même plus de choses
Je t'ai pris 3 captures d'écran

3 ème itération (i == 2) ça commence à se voir

10 ème itérations, y' un 8 à l'avant dernière décimale

11 ème itération, bien que très proche de 1.1 est bien strictement inférieur, le reste est donc proche de 1.1, et arrondi à 1.1 par Console.Write(line)
J'ai négligé un point important de ton symptôme, Console.Write(line) applique un arrondi.
Pour voir la valeur vraie des variables, pas le choix, il faut espionner en pas à pas.
En repartant de ce code
for (int i = 0; i <= 33; i++)
{
Console.Write("'a': {0}\t\t", a);
a = a + 0.1;
Console.Write("'a' + 0.1: {0}\t\t", a);
a %= 1.1;
Console.WriteLine("'a' % 1.1: {0}", a);
Console.WriteLine("entier : " + b);
b = (b + 1) % 11;
Console.WriteLine(Environment.NewLine);
}
J'ai mis un point d'arrêt et 2 espions (il est possible que cet espion arrondissent aussi, mais on y voit quand même plus de choses
Je t'ai pris 3 captures d'écran

3 ème itération (i == 2) ça commence à se voir

10 ème itérations, y' un 8 à l'avant dernière décimale

11 ème itération, bien que très proche de 1.1 est bien strictement inférieur, le reste est donc proche de 1.1, et arrondi à 1.1 par Console.Write(line)