A ceux qui ne peuvent pas reproduire le bug: ne décommentez pas les déclarations de debug commentées, elles affectent le résultat.
Cela implique que le problème est lié aux déclarations de debug. Et il semble qu'il y ait une erreur d'arrondi causée par le chargement des valeurs dans les registres lors des déclarations de sortie, c'est pourquoi d'autres ont constaté que vous pouvez corriger cela avec -ffloat-store
Question supplémentaire:
Je me demandais, devrais-je toujours activer l'option -ffloat-store
?
Pour être frivole, il doit y avoir une raison pour laquelle certains programmeurs n'activent pas -ffloat-store
, sinon l'option n'existerait pas (de même, il doit y avoir une raison pour laquelle certains programmeurs activent -ffloat-store
). Je ne recommanderais pas de l'activer toujours ou de ne jamais l'activer. L'activer empêche certaines optimisations, mais le désactiver permet le genre de comportement que vous obtenez.
Mais, en général, il y a quelques divergences entre les nombres flottants binaires (comme les ordinateurs utilisent) et les nombres flottants décimaux (avec lesquels les gens sont familiers), et cette divergence peut causer un comportement similaire à ce que vous obtenez (pour être clair, le comportement que vous obtenez n'est pas causé par cette divergence, mais un comportement similaire peut l'être). La chose est que, puisque vous avez déjà une certaine imprécision lorsqu'il s'agit de flottants, je ne peux pas dire que -ffloat-store
améliore ou détériore la situation.
A la place, vous pouvez envisager de trouver d'autres solutions au problème que vous essayez de résoudre (malheureusement, Koenig ne renvoie pas au papier réel, et je ne trouve pas vraiment de lieu "canonique" évident pour cela, donc je vais devoir vous renvoyer à Google).
Si vous ne faites pas d'arrondi à des fins de sortie, je regarderais probablement std::modf()
(dans cmath
) et std::numeric_limits::epsilon()
(dans limits
). En repensant à la fonction originale round()
, je crois qu'il serait plus propre de remplacer l'appel à std::floor(d + .5)
par un appel à cette fonction :
// cela a toujours les mêmes problèmes que la fonction d'arrondi originale
int arrondi_sup(double d)
{
// la valeur de retour sera coercée en int, et tronquée comme attendu
// vous pouvez ensuite assigner l'int à un double, si désiré
return d + 0.5;
}
Je pense que cela suggère l'amélioration suivante :
// cela ne fonctionnera pas pour d négatif ...
// cela peut toujours arrondir certains nombres vers le haut alors qu'ils devraient être arrondis vers le bas
int arrondi_sup(double d)
{
double plancher;
d = std::modf(d, &plancher);
return plancher + (d + .5 + std::numeric_limits::epsilon());
}
Une petite note : std::numeric_limits::epsilon()
est défini comme "le plus petit nombre ajouté à 1 qui crée un nombre différent de 1". Vous devez généralement utiliser un epsilon relatif (c'est-à-dire, mettre à l'échelle epsilon d'une manière ou d'une autre pour tenir compte du fait que vous travaillez avec des nombres autres que "1"). La somme de d
, .5
et std::numeric_limits::epsilon()
devrait être proche de 1, donc le regroupement de cette addition signifie que std::numeric_limits::epsilon()
sera à peu près de la bonne taille pour ce que nous faisons. Si tout se passe, std::numeric_limits::epsilon()
sera trop grand (quand la somme des trois est inférieure à un) et peut nous amener à arrondir certains chiffres vers le haut alors que nous ne devrions pas le faire.
Aujourd'hui, vous devriez envisager std::nearbyint()
.
52 votes
Aux nouveaux utilisateurs de SO : VOICI comment poser une question. +1
1 votes
FWIW, je reçois la bonne sortie avec g++ 4.5.0 en utilisant MinGW.
0 votes
Je reçois 4.5 4.6 pour tous les cas. Quelle est votre version de g++? J'ai g++ (Debian 4.3.2-1.1) 4.3.2
0 votes
@Ours : Je ne peux pas reproduire cela avec GCC 4.5.3 ou 4.6.1, sur x86 ou x86_64. (Mais je n'ai aucune idée si c'est un bogue ou juste l'une des nombreuses vilénies concernant les nombres à virgule flottante.)
0 votes
Cela fonctionne comme prévu avec GCC 4.4.3 et 4.6.1 sur x86 avec ou sans
-std=c++0x
et avec n'importe lequel de-O0
,-O1
,-O2
et-O3
.0 votes
Je suis incapable de reproduire cela avec
g++ 4.4.3
sur Ubuntu 10.04 64 bits. Cela affiche4.5 4.6
avec et sans-O1
..-O3
.0 votes
FYI : gcc 4.6.1 (20110409) produit des résultats corrects sous Linux.
0 votes
G++ 4.6.1, les résultats sont corrects avec et sans optimisations.
0 votes
Sur g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2, j'obtiens la sortie correcte (
g++ -O3 x.cpp
, même chose pour-O[012]
)1 votes
Je me demande si cela a quelque chose à voir avec cela: gcc.gnu.org/gcc-4.5/changes.html "GCC a été intégré à la bibliothèque MPC. Cela permet à GCC d'évaluer plus précisément l'arithmétique complexe au moment de la compilation."
2 votes
Ideone utilise la version 4.3.4 ideone.com/b8VXg
5 votes
Tu devrais garder à l'esprit que ta routine n'est probablement pas fiable avec tous types de sortie. Contrairement à l'arrondi d'un double à un entier, cela est vulnérable au fait que tous les nombres réels ne peuvent pas être représentés, tu devrais donc t'attendre à obtenir plus de bugs comme celui-ci.
2 votes
Aux personnes qui ne peuvent pas reproduire le bug : ne décommentez pas les instructions de débogage commentées, elles affectent le résultat.
0 votes
N'a pas pu être reproduit sur gcc-4.5.1.
1 votes
De manière amusante, j'ai rencontré un problème similaire en 2006. À l'époque, j'ai été redirigé vers le rapport de bogue suivant : http://gcc.gnu.org/bugzilla/show_bug.cgi?id=323.
0 votes
Je pourrais le reproduire sous x86_64 Linux avec les bons drapeaux, voir réponse ci-dessous.