J'ai rencontré un problème gênant dans la sortie d'un numéro de point flottant. Lorsque je format 11.545 avec une précision de 2 points décimaux sur Windows IT SUITS "11.55", comme je m'attendrais. Cependant, lorsque je fais la même chose sur Linux, la sortie est "11.54"!
J'ai rencontré à l'origine le problème dans Python, mais une enquête plus approfondie a montré que la différence est dans la bibliothèque d'exécution C sous-jacente. (L'architecture est x86-x64 dans les deux cas.) L'exécution de la ligne de C suivante produit les différents résultats sur Windows et Linux, comme dans Python. P>
Windows: 0.13 Linux: 0.12
6 Réponses :
envisagez de comparer des nombres de points flottants avec une certaine tolérance / epsilon à la place. C'est beaucoup plus robuste que d'essayer de correspondre exactement.
Ce que je veux dire, c'est que deux flotteurs sont égaux lorsque: P>
fabs(f1 - f2) < eps
Oui, je ferais normalement cela, mais dans ce cas, je comparais des cordes, ne flotte pas directement. Les chaînes font partie d'une sortie de programme beaucoup plus importante. En outre, s'ils sont arrondis à 2 endroits, je ne peux pas utiliser de manière réaliste un EPA de 0,02 - qui dissimulerait des différences réelles.
Vous pouvez essayer de soustraire (ou d'ajouter un nombre négatif) un petit delta qui n'aura aucun effet sur l'arrondi pour les chiffres suffisamment éloignés de la précision.
Par exemple, si vous arrondissez avec % .2f code>, essayez cette version sous Windows: p>
11.54499999999999992895
11.54
11.55
Cela fonctionne pour ce cas particulier, mais pas comme une solution générale. Par exemple, si le numéro que je veux formater est de 0,545 au lieu de 11.545, alors '%. 2f'% (0,545 - 0,001) code> retourne "0,54", tandis que
'%. 2f'% 0.545 < / code> sur Linux retourne correctement "0,55".
Le module décimal vous donne accès à plusieurs modes d'arrondi: Vous pouvez construire une décimale d'une chaîne int ou une chaîne. Dans votre cas, nourrir une chaîne avec plus de chiffres que vous ne le souhaitez et tronquent en définissant le contexte.Prec. p> Voici un lien vers un post Pymotw avec un aperçu détaillé du module décimal: p> http://broadcast.oreilly.com/2009/08/pymotw-decimal---fixed-and-flo.html < / a> p> p>
Oui, il produit 11,55 sur Linux, mais je ne peux pas modifier le programme Linux, seuls les fenêtres. J'ai donc besoin d'obtenir les fenêtres pour produire 11.54 à la place.
Désolé pour une erreur mal interprétée - j'ai mis à jour la solution avec des informations sur le module décimal. Espérons que cela vous donnera le contrôle de l'arrondi pour dupliquer le comportement Linux sous Windows.
Bonne idée, mais identique à la réponse de Paxdiablo, il ne passe pas le test "0.545" - qui s'élève à "0,54" lorsque le programme Linux produirait "0,55".
L'exemple montre comment aller de deux manières. Si vous essayez d'ajouter '0.545' à la liste - il imprimera à la fois '.55' et '.54' pour cette entrée. Pour '11 .545 'Vous devriez obtenir '11 .55' (rond_half_up) & '11 .54 '(rond_half_down) pour' 0.545 'Vous devriez obtenir' 0.55 '(rond_half_up) &' 0.54 '(rond_half_down) est-ce que cela ne fonctionne pas sur Windows? (Désolé, je n'ai pas de machine Windows facilement disponible.) Ou cherchez-vous à créer '11 .54 '&' 0.55 '. Le schéma Linux utilise devrait être cohérent, peut-être que l'un des autres modes «décimal» fonctionnera pour le dupliquer sous Windows?
Oui, il imprime ce que vous dites, mais malheureusement, ce que je suis après est beaucoup plus complexe que cela. Linux ne tourne pas toujours toujours. J'ai essayé d'expliquer dans le poste original ce que je
Je vois - je vais essayer rond_half_even & round_05up et voyez s'ils correspondent au comportement. Vous avez mentionné que vous avez frappé une impasse lorsque vous essayez de trouver la source Windows pour PrintF, mais vous devriez pouvoir trouver le code source Linux pour PrintF et l'utiliser sous Windows. Bonne chance, je suis intéressé par la réponse finale.
Tout d'abord, il semble que Windows ait Si vous n'avez pas déjà lu "Comment imprimer des nombres de points flottants avec précision" em> par Steele and White, trouvez une copie et lisez-la. C'est définitivement une lecture éclairante. Assurez-vous de trouver l'original de la fin des années 70. Je pense que j'ai acheté le mien d'ACM ou d'IEEE à un moment donné. P> %. 2f code> est arrondi sur le nombre approprié de chiffres em>. L'algorithme le plus connu pour cela est DTOA implémenté par David M. Gay . Vous pouvez probablement le porter sur Windows ou trouver une implémentation native. P>
Non, les deux implémentations sont parfaitement valables. ISO 754 permet plusieurs modes d'arrondi; Linux utilise rond-à-jour et Linux utilise la ronde à partir de 0.
Vous avez peut-être raison, glenn - rond () code> ne fait pas cela, mais
printf () code> fait!
rond () code> semble être cohérent entre Windows et Linux.
La fonction C ROUND () CODE> s'éloigne toujours de zéro, donc je m'attendrais à ce qu'elle soit cohérente.
Le premier lien est cassé.
Vous pourriez être capable de soustraire une quantité minuscule de la valeur pour forcer l'arrondi
print "%.2f"%(11.545-1e-12)
Je ne pense pas que Windows fait quelque chose de notamment intelligent (comme essayer de réinterpréter le flotteur dans la base 10) ici: J'imagine que c'est simplement informer avec précision les 17 premiers chiffres importants (ce qui donnerait «11 .545000000000000 ') et Puis attachez des zéros supplémentaires à la fin pour constituer le nombre demandé de places après le point. P>
Comme d'autres l'ont dit, les différents résultats pour 0,125 proviennent de Windows à l'aide de demi-up rond et de Linux en utilisant une demi-à-midi. P>
Notez que pour Python 3.1 (et Python 2.7, lorsqu'il apparaît), le résultat de la mise en forme d'un flotteur sera indépendant de la plate-forme (sauf éventuellement sur des plates-formes inhabituelles). P>
Je ne pense pas que ce ne soit que sur des zéros supplémentaires, car le nombre n'est pas réellement de 11.5450000 ... même à 17 chiffres. Mais +1 pour les informations sur Python 3.1 et 2.7 - En attendant de cela!
Les chiffres significatifs «rond à 17 points significatifs (pas 17 places après le point!) Et le virage sur la formule supplémentaire des Zeros semble fonctionner pour moi, pour ce nombre particulier. Les 17 premiers chiffres ressemblent à 11.54499 ..; Le 18ème est aussi un 9, donc nous nous sommes arrondis. La conjecture a été motivée par la version d'origine 1985 de IEEE 754: à la section 5.6 (Binary <---> Conversions décimales), vous trouverez le texte "La mise en œuvre peut, à son option, modifier tous les chiffres significatifs après le neuvième Simple et le dix-septième pour double à d'autres chiffres décimaux, généralement 0. " Je suppose que Microsoft a choisi d'exercer cette option. :)
Comparer des flotteurs en convertissant des cordes et en comparant les chaînes est une idée fondamentalement non-sport. En outre, si vous faites des mathématiques pour venir à ces valeurs, vous pouvez normalement vous retrouver avec des résultats différents de toute façon (par exemple, la précision interne 32, 64 ou 80 bits interne; précision de précision différente des fonctions de libm), avant même de ne pas atteindre mise en page.
Un double a environ 15 chiffres décimaux de précision - au moins pour MSVC. J'aurais supposé que cela serait similaire pour une version x86 Linux, mais peut-être avoir des techniques pour fournir plus (est un
double code> sur la construction Linux 8 octets? Est
dbl_dig Code> dans
float.h code> quelque chose de plus grand que 15?) Que se passe-t-il sur votre version Windows est correct, car aux 15 chiffres de la précision, la valeur représente 11.545. Bienvenue dans le monde bizarre et pas toujours aussi merveilleux de points flottants ...