Signaler

Problème opérateur logique [Résolu]

Posez votre question CrazyGeekMan 523Messages postés dimanche 1 novembre 2015Date d'inscription 8 décembre 2016 Dernière intervention - Dernière réponse le 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 :)
Afficher la suite 
Utile
+0
moins plus
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
CrazyGeekMan 523Messages postés dimanche 1 novembre 2015Date d'inscription 8 décembre 2016 Dernière intervention - 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?
Répondre
Ajouter un commentaire
Utile
+0
moins plus
Bonsoir

on n'en a pas déjà parlé?
http://www.commentcamarche.net/forum/affich-33972004-probleme-avec-le-float
CrazyGeekMan 523Messages postés dimanche 1 novembre 2015Date d'inscription 8 décembre 2016 Dernière intervention - 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...
Répondre
Whismeril 8502Messages postés mardi 11 mars 2003Date d'inscription 8 décembre 2016 Dernière intervention - 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)
Répondre
CrazyGeekMan 523Messages postés dimanche 1 novembre 2015Date d'inscription 8 décembre 2016 Dernière intervention - 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?
Répondre
le père. 5707Messages postés mardi 15 mai 2012Date d'inscription 8 décembre 2016 Dernière intervention - 14 oct. 2016 à 11:11
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.
Répondre
CrazyGeekMan 523Messages postés dimanche 1 novembre 2015Date d'inscription 8 décembre 2016 Dernière intervention - 14 oct. 2016 à 14:56
Oui donc cela se classifie dans un chapitre sur le stockage des données sur la machine.
Merci.
Répondre
Ajouter un commentaire
Utile
+0
moins plus
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.
CrazyGeekMan 523Messages postés dimanche 1 novembre 2015Date d'inscription 8 décembre 2016 Dernière intervention - 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!
Répondre
le père. 5707Messages postés mardi 15 mai 2012Date d'inscription 8 décembre 2016 Dernière intervention - 17 oct. 2016 à 11:30
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.
Répondre
CrazyGeekMan 523Messages postés dimanche 1 novembre 2015Date d'inscription 8 décembre 2016 Dernière intervention - 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.
Répondre
le père. 5707Messages postés mardi 15 mai 2012Date d'inscription 8 décembre 2016 Dernière intervention - 17 oct. 2016 à 13:23
Le programme ne peut pas mettre exactement 1.23 (ni 1.234567) dans a, car 1.23 n'a pas de représentation exacte.

Par contre, pour faire "comme si" (mais il faut rester conscient que ce n'est qu'une approximation), tu peux multiplier a par 100, utiliser une fonction de troncature ou d'arrondi, et diviser le résultat par 100.
fonctions d'arrondi : http://www.gnu.org/software/libc/manual/html_node/Rounding-Functions.html
Il existe peut-être une manière plus intelligente en C, je connais très mal les fonctions disponibles.
Répondre
CrazyGeekMan 523Messages postés dimanche 1 novembre 2015Date d'inscription 8 décembre 2016 Dernière intervention - 17 oct. 2016 à 14:18
Bon comme je n'ai pas encore abordé les fonctions je vais multiplier par 100 puis je vais le convertir en int ^^
D'accord merci pour vos réponses! :)
Répondre
Ajouter un commentaire

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes.

Le fait d'être membre vous permet d'avoir des options supplémentaires.

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !