[C] Problème très con sur une fonction apparemment super simple

Problème très con sur une fonction apparemment super simple [C] - C++ - Programmation

Marsh Posté le 24-10-2002 à 22:02:47    

Salut à tous,  
 
Voici la fonction en question :
 

Code :
  1. int hhmmToMin(float hhmm)
  2. {
  3. int hh = hhmm;
  4. int mm = (hhmm - hh) * 100;
  5. return (hh*60 + mm);
  6. }


 
Son objectif : en gros l'utilisateur tape une heure sous forme de valeur float (genre 12.30 pour 12h30) et la fonction doit transformer ça en nombre de minutes. Vraiment basique quoi a priori.
 
J'ai décomposé en deux variables pour que ce soit plus clair, même si j'aurais pu inclure la seconde dans le return (voire même les deux premières, avec des cast). Mais là n'est pas le problème.
 
Si je tape 1.55, la fonction me renvoie 114 (1*60 + 54) et non 115 (1*60 + 55). Avec d'autres valeurs des fois ça fonctionne, des fois non.
 
Pour hh pas de problèmes, elle prend la partie entière de 1.55, soit 1, par transtypage implicite.
 
C'est pour mm que ça pose problème : d'après le débuggeur la parenthèse donne bien le résultat escompté (0.550000), la multiplication par 100 aussi (55.0000). Mais lors de la conversion en int pour stocker le tout dans mm... cela donne 54, pas 55.
 
Ce qu'il y a de marrant, c'est que si je décompose la fonction comme cela :
 

Code :
  1. int hhmmToMin(float hhmm)
  2. {
  3. int hh = hhmm;
  4. float mmtemp = (hhmm - hh) * 100;
  5. int mm = mmtemp;
  6. return (hh*60 + mm);
  7. }


 
... et que je mets un breakpoint sur l'avant-dernière ligne, voici ce que me dit le débugger (si je lui demande) :
 
* mmtemp = 55.0000
* (int)mmtemp = 54
* (int)55.0000 = 55
 
 :heink:  
 
J'ai essayé de changer de types en mettant des double à la place des float, j'ai aussi essayé de transtyper tout explicitement, rien n'y fait, j'obtiens toujours 114.
 
C'est sûrement tout con, si qqun peut m'expliquer je suis preneur. Chui pas newbie en C/C++ mais ça fait un mmt que j'en avais pas refait, j'ai dû oublier qq trucs importants :o
 
D'ailleurs y'a p-e plus simple pour faire ce que la fonction fait...
 
Merci d'avance.


Message édité par sielfried le 24-10-2002 à 22:10:09

---------------
StarCraft Professional Gaming Database | [Ze Topic] Starcraft/BroodWar
Reply

Marsh Posté le 24-10-2002 à 22:02:47   

Reply

Marsh Posté le 24-10-2002 à 23:21:11    

soit j'ai de la merde dans les yeux, soit ton code y reviens à ça:
 

Code :
  1. int hhmmToMin(float hhmm)
  2. {
  3. return ( hhmm*60 );
  4. }

Reply

Marsh Posté le 24-10-2002 à 23:23:00    

(hhmm - hh)
=> 0 vu que hh == hhmm
 
int mm = (hhmm - hh) * 100;  
=> 0
 
return (hh*60 + mm);  
=> return (hhmm*60 + 0)

Reply

Marsh Posté le 24-10-2002 à 23:23:49    

a non oups !!!!!
 
autant pour moi j'ai dit une connerie !!! :D (fatigué vais faire un nolf2)
 
tu peux essayer d'ajouter un +0.5 pour compenser les erreurs d'arrondi par défaut...
 
mmmm.....  
 
et ça ?
 
float mmtemp = (hhmm - (float)hh) * 100;
 
histoire d'être sûr qu'il reste en virgule flottante tout le long ?


Message édité par bjone le 24-10-2002 à 23:28:37
Reply

Marsh Posté le 24-10-2002 à 23:40:23    

ca ca marche mais galere entre float et double et int pour la precision (d ou le pb de 30.0 qui passe a 29)
 

Code :
  1. int g_fniHhmmToMin(double dHhmm)
  2. {
  3. char buffer[50];
  4. double dHh = floor(dHhmm);
  5. double dTmp = (dHhmm - dHh) * 100.0;
  6. _gcvt(dTmp, 10, buffer);
  7. int iMm = atoi(buffer);
  8. return ((int)(dHh*60.0) + iMm);
  9. }

 
 
Doit y avoir plus simple :(


---------------
VT ... Vaucluse / Vrille(euse :sarcastic: ) c'est pareil tant qu'il y a l'humour :D
Reply

Marsh Posté le 25-10-2002 à 00:09:35    

VisualC++ a écrit a écrit :

ca ca marche mais galere entre float et double et int pour la precision (d ou le pb de 30.0 qui passe a 29)
 

Code :
  1. int g_fniHhmmToMin(double dHhmm)
  2. {
  3. char buffer[50];
  4. double dHh = floor(dHhmm);
  5. double dTmp = (dHhmm - dHh) * 100.0;
  6. _gcvt(dTmp, 10, buffer);
  7. int iMm = atoi(buffer);
  8. return ((int)(dHh*60.0) + iMm);
  9. }

 
 
Doit y avoir plus simple :(
 




 
En effet ça marche... et en effet y'a plus simple. En fait il suffit de passer une valeur double au lieu de float pour que ça fonctionne. Avec ma fonction de départ ça marche aussi. J'avais essayé tout mais pas ça :/
 
Je sais pas, lors de la multiplication par 100 il doit y avoir un arrondi bancal de fait avec le type float, genre le nombre vaut en fait 54.99999999(...), que le débugger arrondit à 55.0000 mais que le transtypage en int tronque en 54 (d'où l'apparente incohérence de l'affichage du débugger).
 
Cela dit si qqun peut m'expliquer de façon un peu plus technique l'origine de la couille lorsque j'utilise un float, c'est encore mieux.
 
Merci à vous deux en attendant :jap:


---------------
StarCraft Professional Gaming Database | [Ze Topic] Starcraft/BroodWar
Reply

Marsh Posté le 25-10-2002 à 00:57:59    

Bah en fait non, ça merde. Ca marche avec 1.55, mais par ex. pas sur 12.20. Par contre avec ta fonction ça a l'air bon qqsoit le nombre :sweat:  
 
Le pb c'est que vu que chui en première année de DUT info (c'est pour un projet), je dois me limiter le + possible à ce qu'on a vu pour le moment (même si je comprends ta fonction), et ta solution paraîtrait un peu compliquée :/


---------------
StarCraft Professional Gaming Database | [Ze Topic] Starcraft/BroodWar
Reply

Marsh Posté le 25-10-2002 à 03:01:14    

Reply

Marsh Posté le 25-10-2002 à 05:07:48    

Les valeurs flottantes manquent de précision...
Là où on t'affiche 55.00000, c'est peut-être 54.99999.
La solution est effectivement d'ajouter un chouia au flottant avant tronquage.
 
Si tu veux éviter des warnings, rend tes casts float->int explicites !

Code :
  1. int hhmmToMin(float hhmm)
  2. {
  3. int hh= (int)hhmm;
  4. int mm= (int)( (hhmm-hh)*100.f + .5f );
  5. return hh*60 + mm;
  6. }


---------------
Bricocheap: Montage de ventilo sur paté de mastic silicone
Reply

Marsh Posté le 25-10-2002 à 11:26:29    

Musaran a écrit a écrit :

Les valeurs flottantes manquent de précision...
Là où on t'affiche 55.00000, c'est peut-être 54.99999.
La solution est effectivement d'ajouter un chouia au flottant avant tronquage.
 
Si tu veux éviter des warnings, rend tes casts float->int explicites !

Code :
  1. int hhmmToMin(float hhmm)
  2. {
  3. int hh= (int)hhmm;
  4. int mm= (int)( (hhmm-hh)*100.f + .5f );
  5. return hh*60 + mm;
  6. }






 
Vi, bah ça marche bien avec +.5f, je crois que je vais faire comme ça. Pour les casts implicites, oui, c'est vrai que c'est plus net comme ça. Plus lisible et plus de warning.
 
Thx :jap:


---------------
StarCraft Professional Gaming Database | [Ze Topic] Starcraft/BroodWar
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed