Conversion incorrecte avec atof ou strtod
Bonjour,
Voilà mon problème :
- Ma chaine szParam (char [500]) contient "5000000000000039" (avec \0 à la fin). (pour info il y a 13 "0")
- Je dispose d'une variable dCodePgmTri (double) ; (petite précision au cas où : cette variable fait partie d'une structure et j'utilise un tableau de cette structure)
- Je fais dCodePgmTri = atof (szParam)
Je compile mon programme sous W2000 (avec Visual C++ 6.0) et sous Unix HP (via gcc).
Sous W2000, la conversion de ma valeur fonctionne parfaitement, par contre sous Unix HP, la conversion me renvoie "5000000000000040" !!
Je ne dépasse pourtant pas la valeur max d'un double (qui est beaucoup, beaucoup plus grande...j'ai d'ailleurs fait un affichage ecran de DBL_MAX pour m'en assurer).
J'ai constaté que si je mets "38" à la place de "39" (je ne répète pas ici les chiffres qui précèdent), j'obtiens la bonne valeur ; avec 40 j'obtiens 40 et avec 41 j'obtiens aussi 40. Par contre avec 9941 j'obtiens 9920 !
J'ai essayé avec strtod et j'obtiens les mêmes résultats toujours corrects sous W2000 mais parfois incorrect sous Unix... :(
Ce programme tourne depuis un petit moment et cette erreur n'avait jamais été détectée avant qu'on ne tombe sur la valeur "50...39"
Alors si quelqu'un a une idée, je suis preneur...
Merci d'avance.
Sebastien "quelque peu déboussolé sur ce coup-là"
Re: Conversion incorrecte avec atof ou strtod
Citation:
Envoyé par sber74
Voilà mon problème :
- Ma chaine szParam (char [500]) contient "5000000000000039" (avec \0 à la fin). (pour info il y a 13 "0")
- Je dispose d'une variable dCodePgmTri (double) ; (petite précision au cas où : cette variable fait partie d'une structure et j'utilise un tableau de cette structure)
- Je fais dCodePgmTri = atof (szParam)
Cette fonction est obsolète depuis ... 1989! Préférer strtod()...
Citation:
Je compile mon programme sous W2000 (avec Visual C++ 6.0) et sous Unix HP (via gcc).
Sous W2000, la conversion de ma valeur fonctionne parfaitement, par contre sous Unix HP, la conversion me renvoie "5000000000000040" !!
C'est grave ? Ca fait une précision de 1.99E-14 %, je m'en contente...
Visiblement tu ne sait pas ce que sont les nombres à virgule flottantes... En gros, se sont des nombres codés "signe, mantisse, exposant". La gamme est très large, mais la précision est évidemment limitée... Il est donc tout à fait normal que les chiffres de poids faibles soient imprécis. Je te renvois à ton Wiki préféré pour les détails...
Conversion incorrecte avec atof ou strtod
Alors j'utilise peut-être pas le bon type et je n'ai pas du totu comprendre sur les types à virgules flottantes.
En fait ma valeur correspond à un code identifiant (donc un nombre entier) issue d'une base de données (numeric 18 ), il est donc important que la conversion soit exacte.
Mais alors si je ne dois pas prendre des doubles, quelle type (et quelle fonction de conversion associée) dois-je utiliser pour stocker un nombre entier pouvant avoir jusqu'à 18 chiffres ?
Re: Conversion incorrecte avec atof ou strtod
Le problème est qu'avec le format double le plus répandu (et je doute fort qu'HP ne l'utilise pas -- si j'ai bonne mémoire, HP a des particularité sur la représentation des NaN mais rien de plus), les entiers positifs inférieurs ou égal à 9007199254740992 sont représentables exactement. Et 5000000000000039 en fait partie. Cela vaut la peine d'investiger.
Comment fais-tu tes affichages?
Si tu optiens le même nombre d'une autre manière qu'avec strtod (par exemple (double)500000*(double)100000000+(double)39) est-ce qu'il y a le même problème?
Est-ce que ton printf reconnait %a et que donne l'affichage avec?
(ca devrait être 0x1.1c37937e08027p+52)
Si tu manipules beaucoup des flottants, tu as intérêt à te renseigner plus sur eux, car ce sont des bêtes particulières.
Re: Conversion incorrecte avec atof ou strtod
Citation:
Envoyé par sber74
En fait ma valeur correspond à un code identifiant (donc un nombre entier) issue d'une base de données (numeric 18 ), il est donc important que la conversion soit exacte.
Les flottants ne sont pas la solution alors.
Citation:
Mais alors si je ne dois pas prendre des doubles, quelle type (et quelle fonction de conversion associée) dois-je utiliser pour stocker un nombre entier pouvant avoir jusqu'à 18 chiffres ?
long long va jusque 9223372036854775807 (donc tu as tes 18 chiffres si je ne me suis pas trompé), unsigned long long jusque 18446744073709551615 (ce qui fait 19 chiffres).
Re: Conversion incorrecte avec atof ou strtod
Citation:
Envoyé par sber74
En fait ma valeur correspond à un code identifiant (donc un nombre entier) <...> quelle type (et quelle fonction de conversion associée) dois-je utiliser pour stocker un nombre entier pouvant avoir jusqu'à 18 chiffres ?
Des entiers. [C99] long long ou unsigned long long, par exemple.
Conversion incorrecte avec atof ou strtod
Ok, demain au boulot je testerai donc le "unsigned long long" pour voir si ça marche.
En espérant que mes compilateurs supporte la norme C99. Je rappelle que sous Windows j'utilise le compilateur de Visual C++ 6.0 et sous Unix j'utilise gcc (je crois que c'est la version 3.2 mais je dois vérifier...)
Et sinon c'est quoi la fonction de conversion en lieu et place de "strtod" ?
Merci de votre aide. J'apprends plein de chose sur ce coup-là...
Re: Conversion incorrecte avec atof ou strtod
Citation:
Envoyé par sber74
En espérant que mes compilateurs supporte la norme C99. Je rappelle que sous Windows j'utilise le compilateur de Visual C++ 6.0
N'est pas C99; mais a une extension int64 ou un truc comme ça... Détails sur le forum "Développement Windows".
Citation:
et sous Unix j'utilise gcc (je crois que c'est la version 3.2 mais je dois vérifier...)
gcc supporte (partiellement) C99 depuis la version 3.x. La dernière version de gcc est 4.x.
Citation:
Et sinon c'est quoi la fonction de conversion en lieu et place de "strtod" ?
[C99] strtoll() et strtoull()
Re: Conversion incorrecte avec atof ou strtod
Bonjour,
Merci pour toutes ces infos. Finalement pour rester plus ouvert (si par exemple mes identifiants devenaient un jour des numeric 20 ou plus) et sachant que je ne fais donc aucune opération sur ces valeurs mais uniquement des tests d'égalité, je vais reste en "char" et je ferai mes comparaisons octect par octet.
En fait au départ je croyais juste gagner du temps en faisant mes tests d'égalité avec des numériques plutôt ques des char mais bon il ne doit pas y avoir une grande différence...
Re: Conversion incorrecte avec atof ou strtod
Citation:
Envoyé par sber74
Finalement pour rester plus ouvert (si par exemple mes identifiants devenaient un jour des numeric 20 ou plus) et sachant que je ne fais donc aucune opération sur ces valeurs mais uniquement des tests d'égalité, je vais reste en "char" et je ferai mes comparaisons octect par octet.
Si ce sont des chaines de caractères, strcmp()...
Re: Conversion incorrecte avec atof ou strtod
Bonsoir,
Me revoilà car d'autres soucis m'ont détourné du sujet...
Bon j'ai essayé en passant par des chaines mais ça a considérablement augmenté mes temps de traitements sur de gros volumes de données. Donc je repars sur des numériques...
Alors, sauf erreur de ma part on a :
sous Windows
Code:
1 2 3
| _int64 ou unsigned __int64
printf ("%I64i ou %I64u"...
_atoi64 |
sous Unix
Code:
1 2
| long long ou unsigned long long
printf ("%lli ou %llu"... |
Mais quel est l'équivalent de _atoi64 sous Unix ? J'ai cherché partout mais je n'ai pas trouvé :( (je suppose que je suis un mauvais chercheur...)
Et quel est l'équivalent, sous Unix et sous Windows, pour des unsigned ?
Merci d'avance.
PS : quelqu'un avait mentionné les fonctions strtol et strtoul mais ça ne fonctionne pas avec des entiers 64bits.
Re: Conversion incorrecte avec atof ou strtod
Citation:
Envoyé par sber74
Mais quel est l'équivalent de _atoi64 sous Unix ?
strtoll() et strtoull()