Calculatrice qui fait des erreurs.

KyroKyro Membre
02:18 modifié dans Vos applications #1
Bonjour à  tous,
tout d'abord désolé si j'ai posté mon topic dans la mauvaise section, je suis nouveau ici.


Je débute en Obj-c est viens de réaliser une calculatrice toute bête avec Xcode/Application builder.

Tout fonctionne .. sauf ... sauf ... sauf, les calcules sur des chiffres à  virvules.

Par exemple 2.33 + 2.33 me revoit 4.6599999999

Je n'ai aucune idée d'où cela peut venir. Sachat que je génère mes nombres de la manière suivante :

* entier :  entier*10+unité
* flotant : entier+chiffre/10^une_puissance


Quelqu'un saurait-il d'où pourrait venir mon problème ?

Réponses

  • CéroceCéroce Membre, Modérateur
    janvier 2011 modifié #2
    Comme tu gères tes nombres sous la forme mantisse | exposant, tu es donc conscient de la manière sont codés les types float et double, j'imagine.

    Le problème vient sans doute de la manière dont tu effectues les calculs. Donne-nous un exemple de code.


  • 02:18 modifié #3
    <br /><br />+ (NSString*)resultAsStringFromDouble:(double)aRes<br />{<br />	NSDecimalNumber* decNumber = [NSDecimalNumber numberWithDouble:aRes];<br />	NSDecimalNumberHandler *roundingStyle = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode: NSRoundBankers scale:10 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO];<br />	NSDecimalNumber *roundedNumber = [decNumber decimalNumberByRoundingAccordingToBehavior:roundingStyle];<br />	return [roundedNumber descriptionWithLocale:[NSLocale currentLocale]];<br />}	<br /><br />
    
  • AliGatorAliGator Membre, Modérateur
    02:18 modifié #4
    C'est un problème de C pur que tu as là , en effet vu comme tu construis tes nombres sous forme mantisse/exposant en base 10 alors que la représentation interne des float IEEE754 est mantisse/exposant mais en base 2, si tu fais ça directement sans contrôle il y a des erreurs d'arrondis qui vont intervenir.
  • KyroKyro Membre
    02:18 modifié #5
    J'utilise un automate  pour gérer ma calculette

    voici comme je génère mes nombres :

    if ( flotant == 0 ) {<br />	&nbsp; [output setDoubleValue: [output doubleValue]*10+val];<br />	} else {<br />	&nbsp; [output setDoubleValue: [output doubleValue] + (val/(pow(10,flotant++)))];<br />	}
    



    les opérations je les obtient tout bêtement avec cette fonction :
    double Calcul (double opG, double opD, int operateur) {<br />&nbsp; NSLog(@&quot;opG : %f&nbsp; opD : %f&quot;, opG, opD);<br />&nbsp; switch (operateur) {<br />	case 0 :<br />	&nbsp; return (opG + opD);<br />	&nbsp; break;<br />	case 1 :<br />	&nbsp; return (opG - opD);<br />	&nbsp; break;<br />	case 2 :<br />	&nbsp; return (opG * opD);<br />	&nbsp; break;<br />	case 3 :<br />	&nbsp; return (opG / opD);<br />	&nbsp; break;<br />	default:<br />	&nbsp; return opD;<br />	&nbsp; break;<br />&nbsp; }&nbsp; <br />}
    

  • CéroceCéroce Membre, Modérateur
    janvier 2011 modifié #6
    Pour expliquer un peu ce que dit Ali:

    En décimal:
    <br />2,33 = 2&nbsp; &nbsp; &nbsp; + 0,3&nbsp; &nbsp;  + 0,03<br />&nbsp; &nbsp;  = 2*10^0 + 3*10^-1 + 3*10^-2<br />
    


    Mais sur un ordinateur, les nombres sont stockés dans la mémoire en binaire (base 2). Ceci implique que tout est une somme de puissance de 2.
    Si tu convertis 2,33 en une somme de puissances de 2:
    <br />2,33 = 2&nbsp; &nbsp;  + 0&nbsp; &nbsp;  + 0&nbsp; &nbsp; &nbsp; + 0,25&nbsp;  + 0&nbsp; &nbsp; &nbsp; + 0,0625 + etc<br />&nbsp; &nbsp;  = 1*2^1 + 0*2^0 + 0*2^-1 + 1*2^-2 + 0*2^-3 + 1*2^-4 + etc<br />
    


    Pour certains nombres, il faudrait un nombre infini de chiffres pour les décrire en binaire. D'où l'erreur que tu observes.

    Pour améliorer la précision, tu peux utiliser un type plus précis, long double, mais le problème sera toujours présent. Il faudrait utiliser d'autres algorithmes qui travaillent en base 10.
    Note que les fonctions de <math.h> travaillent sur des doubles.
  • tabliertablier Membre
    02:18 modifié #7
    Il existe des bibliothèques toutes faites pour les calculs, avec ou sans les sources. ça évite de réinventer la roue. Il y a longtemps, je me suis servi des "Numerical recipes" par exemple.
  • KyroKyro Membre
    02:18 modifié #8
    Je me doutais bien qu'il y avait une erreur au moment du stockage en mémoire.

    Merci pour la librairie, je vais aller y jeter un coup d'oeil.
  • mpergandmpergand Membre
    janvier 2011 modifié #10
    Sinon, pour convertir une chaine en double, il y a un fonction C qui fait ça très bien:
    strtod

    et tu as même le source strtod.c pour voir comment ils font  :)
  • tabliertablier Membre
    02:18 modifié #11
    Je me doutais bien qu'il y avait une erreur au moment du stockage en mémoire
    Ce n'est pas vraiment une erreur. C'est simplement que suivant la base de numération, les rationnels et les irrationnels ne sont pas les mêmes.
Connectez-vous ou Inscrivez-vous pour répondre.