Problème opérateur logique

Résolu/Fermé
CrazyGeekMan Messages postés 871 Date d'inscription dimanche 1 novembre 2015 Statut Membre Dernière intervention 29 octobre 2022 - 13 oct. 2016 à 17:47
CrazyGeekMan Messages postés 871 Date d'inscription dimanche 1 novembre 2015 Statut Membre Dernière intervention 29 octobre 2022 - 17 oct. 2016 à 14:18
Bonjour,

Je demande votre aide puisque j'ai trouvé "l'erreur" dans mon programme mais je suspecte un bug du compilateur puisque tout semble correct... (je compile avec gcc) :
Voici le fragment de mon programme :
//i est remis à zéro dans ce qui précède
printf("value[n] %f : sommeinter : %f\n",value[num],sommeinter);	
		while(sommeinter>=value[num])
		{
			sommeinter-=value[num]; //On s'en fiche ici :)
			i++; //i donnera le nombre de pièces || billets
		}
			//Je prend soin de bien afficher i ne vous en faite pas :)

Je vous ai donné le résultat de tout le programme en pièce jointe ; le i représente : "i billet de *" ou "i pièces de*".
Comme vous pouvez l'apercevoir, à la dernière étape value{n]=someinter et pourtant le programme n'est pas rentré dans la boucle, je m'attend à '1 pièces de 0.01 euros".

Je vous prie de me prêter main forte :)

3 réponses

Utilisateur anonyme
13 oct. 2016 à 19:08
Bonjour

Il n'y a pas de bug dans le compilateur, ni de problème d'opérateur logique.
Le problème vient de ce que la plupart des nombres décimaux n'ont pas une représentation exacte dans le type de variable que tu utilises.
J'ignore d'où viennent les deux 0.01 que tu essayes de comparer, mais il y en a certainement au moins un des deux qui vaut en fait quelque chose du style 0.009999999 ou 0.010000001.

C'est pourquoi les comparaison "simple" entre flottants est à proscrire en programmation. Quand deux nombres sont très voisins, on n'est jamais sûr de rien.

Ceci n'est pas un bug mais vient du fait que la taille mémoire allouée à un nombre étant limitée, tous les nombres ne sont pas représentables exactement.
pour plus de détails : https://fr.wikipedia.org/wiki/Virgule_flottante#Norme_IEEE_754
0
CrazyGeekMan Messages postés 871 Date d'inscription dimanche 1 novembre 2015 Statut Membre Dernière intervention 29 octobre 2022 136
13 oct. 2016 à 22:06
D'accord merci pour votre réponse, mais alors que me conseillez vous pour pouvoir comparer deux chiffres décimaux?
0
Utilisateur anonyme
13 oct. 2016 à 22:51
0
CrazyGeekMan Messages postés 871 Date d'inscription dimanche 1 novembre 2015 Statut Membre Dernière intervention 29 octobre 2022 136
14 oct. 2016 à 00:24
Si on en as déjà pas mal parlé.mais je ne pensait pas que ce problème me traquerait dans chaque programme.
Une explication en direct est toujours plus compréhensible qu'une conversation par message c'est pourquoi j'ai demandé à mes profs d'informatique de l'aide sur la question. Ce qui est assez marrant c'est qu'ils ne comprennent pas ce décalage et qu'ils disent d'utiliser le double pour une meilleur précision. Un des prof m'a dis que pourquoi vous convertissez d'un nombre hexa et non binaire. Et encore un autre m'a dis que ce n'était pas au programme, quelle justification pertinente pour répondre à une question !
Grace a vous je me suis bien rendu compte du pourquoi meme si je galère avec les calculs.
En revenant au sujet présent, j'ai donc essayer ceci :
double x;
scanf("%f", & x) ;

Mais une erreur disant que la variable possède deux formats s'affiche...
0
Utilisateur anonyme
14 oct. 2016 à 07:18
Bonjour

alors utiliser un double évitera la majeur partie des cas ou un pouillème, viendrait perturber un test.
Cependant si tu veux du 100%, il faut faire autrement.
Je voies 2 options,
  • si tu as besoin de comparer sur 2 ou 3 chiffres après la virgule, tu arrondies à une décimale de plus avant de comparer
  • si tu as besoin d'aller plus loin derrière la virgule, tu définis un écart acceptable, tu soustrais tes deux nombres et vérifie que le résultat est situé à +/- l'écart (le signe dépendant du fait que A-B = - B- A). Pour simplifier un poil, tu peux vérifier que la valeur absolue du résultat est inférieure ou égale à l'écart acceptable.


Ensuite, le c n'est pas et de loin mon langage de prédilection, ce que je te dis ici, et aussi dans la précédente discussion est valable pour le cas général, chaque langage pouvant avoir des subtilités.

pour ton scanf, un petit tour sur wikipédia
https://fr.wikipedia.org/wiki/Scanf
Pour le float ou le double il faut mettre %lf. (L en minuscule et F en minuscule)
0
CrazyGeekMan Messages postés 871 Date d'inscription dimanche 1 novembre 2015 Statut Membre Dernière intervention 29 octobre 2022 136 > Utilisateur anonyme
14 oct. 2016 à 11:04
On nous dit que le langage c est un langage très prisé dans le monde professionnel c'est pourquoi on nous l'apprend.
Merci je vais voir la technique de la valeur absolue, mais ce que je trouve dommage dans ce langage c'est que même dans un cas pareil on cherche une erreur qui en réalité n'existe pas.
Merci pour toutes vos réponses à mes posts :)
Je vais suivre le cours sur OpenClassrooms en plus de mon cours d'informatique, je pense que ça peut aussi aider.
Mais connaissez vous un site qui regroupe toutes les commandes en c ? Un genre de man sous unix pour le cas du shell?
0
Utilisateur anonyme > CrazyGeekMan Messages postés 871 Date d'inscription dimanche 1 novembre 2015 Statut Membre Dernière intervention 29 octobre 2022
Modifié par le père. le 14/10/2016 à 11:12
Le problème de vient pas du langage C, mais de la représentation des nombres qui est dans une large mesure indépendante du langage. Tu aurais le même problème en java, basic, PHP ou javascript.
0
CrazyGeekMan Messages postés 871 Date d'inscription dimanche 1 novembre 2015 Statut Membre Dernière intervention 29 octobre 2022 136 > Utilisateur anonyme
14 oct. 2016 à 14:56
Oui donc cela se classifie dans un chapitre sur le stockage des données sur la machine.
Merci.
0
CrazyGeekMan Messages postés 871 Date d'inscription dimanche 1 novembre 2015 Statut Membre Dernière intervention 29 octobre 2022 136
15 oct. 2016 à 16:47
Comment dois-je faire pour corriger cette erreur de précision dans mon programme ? :

//Décomposition_somme.c
 #include <stdio.h>
int main()
{
	float somme,sommeinter;
	int i,num;
	float value[10]={10,5,2,1,0.5,0.2,0.1,0.05,0.02,0.01};
	printf("Somme en euros :\n");
	scanf("%f",&somme);
	//num allant de 0 à 9 pour englober valeurs de value[num]
	for(num==0;num<10;num++)
	{	
		i=0;
		sommeinter=somme; //Création d'une somme intérmédiaire afin de ne pas modifier la somme du début lors des succession des soustrations
		printf("value[n] %f : sommeinter : %f\n",value[num],sommeinter);
		while(sommeinter>=value[num])
		{
			sommeinter-=value[num];
			i++; //i donnera le nombre de pièces || billets
		}
		somme-=value[num]*i; //La boucle reprendra valeur de la somme après la soustraction
		if(value[num]>=5)
		{
		printf("%d billets de %.2f euros\n",i,value[num]);
		}
		else
		{
		printf("%d pièces de %.2f euros\n",i,value[num]);
		}
	}	
	return(0);
}	


J'ai cherché avec la valeur absolue mais je réussie uniquement avec le le comparateur "=".
Je ne vois pas comment arrondir au centième, le %.2f sert que pour printf.
0
CrazyGeekMan Messages postés 871 Date d'inscription dimanche 1 novembre 2015 Statut Membre Dernière intervention 29 octobre 2022 136
16 oct. 2016 à 14:18
Je m'excuse pour uper le topic mais j'ai peur qu'il tombe dans l'oubli.
J'aurai bien besoin de voir une résolution de ce cas qui m'aidera par la suite à résoudre d'autres problèmes similaires.
0
Utilisateur anonyme > CrazyGeekMan Messages postés 871 Date d'inscription dimanche 1 novembre 2015 Statut Membre Dernière intervention 29 octobre 2022
Modifié par le père. le 17/10/2016 à 00:13
Je ne sais pas s'il existe une manière systématique de contourner le problème qui s'applique à tous les cas. Ça dépend fortement de l'ordre de grandeur des nombres manipulés.
Ici, le mieux est de travailler en centimes, car tu n'as alors à manipuler que des entiers, du moins avec les exemples de somme dont tu parles. Éventuellement, tu fais une division par 100 (en flottant, cette fois) au moment de l'affichage.

Une autre possibilité sans passer par les entiers. On tient compte du fait qu'on ne descend pas en dessous du centime et qu'on ne manipule pas de trop grands nombres, et qu'il s'agit d'une inégalité, consiste à décaler légèrement (c'est ce 'légèrement' qui est à adapter en fonction du problème) la valeur utilisée pour la comparaison :
while(sommeinter>=value[num]-0.002)
0
CrazyGeekMan Messages postés 871 Date d'inscription dimanche 1 novembre 2015 Statut Membre Dernière intervention 29 octobre 2022 136 > Utilisateur anonyme
17 oct. 2016 à 09:53
D'accord donc il faut prendre une marge d'erreur;
Mais faut avouer que dans des programmes plus sophistiqué cela peut être un vrai problème.
Merci en tout cas!
0
C'est rarement un vrai problème, quand on en est averti.
Quand tu as besoin de faire une comparaison précise, c'est généralement que tu manipules des entiers, et là il n'y a pas de problème. C'est ton cas : tu manipules des nombres entiers de centimes, mais tu as choisi un type flottant parce que la représentation usuelle est en euros, donc un nombre à virgule. Mais si tu y réfléchis bien, il s'agit d'un problème d'entiers.
Quand tu manipules un nombre (non entier) qui vient du monde physique, l'erreur due à la représentation informatique est presque toujours complètement négligeable devant celle due à la mesure qui est à l'origine de ce nombre.
0
CrazyGeekMan Messages postés 871 Date d'inscription dimanche 1 novembre 2015 Statut Membre Dernière intervention 29 octobre 2022 136 > Utilisateur anonyme
17 oct. 2016 à 13:08
Dans tous les cas ll est préférables de manipuler des entiers pour coder.
Connaissez vous une commande en langage c pour arrondir par exemple au centième un nombre flottant.
S on a :
float a=1.234567

Pour que le programme mette 1.23 dans a.
Si c'étais possible ça aurait simplifier l'erreur de précision.
%.2f ne marche qu'avec printf.
0