Bug arithmétique avec g++ - C++ - Programmation
Marsh Posté le 12-03-2007 à 10:03:12
Joel F a écrit :
|
stun outil du démon
edit : cela dit, ca ressemble simplement à l'implémentation mac qui arrondit plutôt que de tronquer, non ?
Marsh Posté le 12-03-2007 à 10:08:06
ReplyMarsh Posté le 12-03-2007 à 10:16:39
parce que c'est pas 5.0
Edit : je te fais même l'exemple au passage
tu reconnaitras ton code à peine modifié :
Code :
|
$ g++ ctest.cpp -o ctest.exe |
$ g++ --version |
re-edit:
en fait, mon test ne prouve rien, c'est le matin, tout ca le size_t(5.0) sera probablement converti en 5 dans un size_t ... désolé ...
Marsh Posté le 12-03-2007 à 15:28:37
sur ma debian en g++ 4.1.2 ça marche, ça fait un joli li ?, 5
Marsh Posté le 12-03-2007 à 16:32:12
bah apparement selon qu'il y est -O4 ou pas ou en fait si, ca change
Marsh Posté le 12-03-2007 à 16:37:23
nana, l'extension pourrave de gcc 4.2 sur machine SSE3
Le fait est que le comportement est correct si y a des optims ou pas.
Drame encore + gros :
Code :
|
renvoie 5 dans toutes les configs machines/compilos
Marsh Posté le 13-03-2007 à 00:29:29
Joel F a écrit : size_t(5.00000) je vois pas COMMENT ca peut renvoyer 4 ! |
Dixit §4.9.1: "An rvalue of a floating point type can be converted to an rvalue of an integer type.
The conversion truncates; that is, the fractional part is discarded. [...]"
Joel F a écrit : Le bug est là |
Je ne crois pas. la valeur "a peu près 5.000" peut être bien différente suivant les optimisations appliquées. Il n'y a rien dans le standard C++ fasse pour empêcher cela.
Marsh Posté le 13-03-2007 à 08:00:21
Pardon mais 0.2 n'a pas de représentation exacte (0x3FC999999999999A). Rien à voir avec les optimisations, flags de compil et autres petits hommes verts.
La révision des fondamentaux c'est par ici: http://docs.sun.com/source/806-3568/ncg_goldberg.html
Marsh Posté le 13-03-2007 à 08:29:17
++fab a écrit : |
diantre, j'aimerais bien comprendre l'effet de l'ajout d'une etape intermediaire qui ne modifie pas la valeur et qui pourtant en change el résultat final :|
Citation : |
Merci bien je ne le savais pas
Ma question portait surtout sur l'expliation de la variabilité du comportement d'une même famille de compilateur masi merci pour ce bashage
inapproprié
Marsh Posté le 13-03-2007 à 08:53:02
Joel F a écrit : Merci bien je ne le savais pas |
En quoi est-ce inapproprié? Il n'y a rien de mieux à attendre de la part du compilateur. De n'importe quel compilateur. Croire qu'il en serait autrement est une grossière méprise.
Marsh Posté le 13-03-2007 à 08:56:32
tbp a écrit : En quoi est-ce inapproprié? Il n'y a rien de mieux à attendre de la part du compilateur. De n'importe quel compilateur. Croire qu'il en serait autrement est une grossière méprise. |
Bon, on va dire qu'il est 8:50 un mardi matin et que je m'exprime mal ... je cherche la cause de la variabilité du phénoméne.
Je me doutes bien qu'on n'y peut rien hein -- genre les cours sur le codage IEEE 754 j'en donne moi même -- néanmoins, force
est de constater que :
- la version du gcc influe sur le résultat
- les options d'optimisations ou leurs absences aussi
- le code adjacent aussi ...
Donc ton histoire de "les optims n'ont rien à y voir", permets moi d'en douter ...
Alors, je vais poser une question claire et précise : Pourquoi cette variation ?
Marsh Posté le 13-03-2007 à 09:43:58
La question n'a pas à être posée dans ces termes, vu les garanties fournie par le langage et IEEE 754.
Alors si le fond du problème est de savoir "dans quelles conditions puis-je espérer un résultat 'déterministe' dans une séquence d'opérations sur des flottants en c++?", un nombre sans représentation exacte a peu de chance de faire partie de la réponse (sauf à inclure un pèlerinage à Lourdes).
Marsh Posté le 13-03-2007 à 11:47:50
IEEE 754 n'est pas censée répondre à ce problème de déterminisme ? Ne serait-il pas plus approprié de dire: telle optim ou tel jeu d'instruction, n'est pas IEEE 754 compliant ?
Marsh Posté le 13-03-2007 à 12:58:48
Je croyais qu'il était question de C++, un modèle un poil plus laxiste qu'IEEE 754.
Marsh Posté le 13-03-2007 à 16:54:06
tu veux toujours pas balancer l'assembleur voir un coup ?
Marsh Posté le 13-03-2007 à 17:26:58
On repart de 0:
1/ je fais un calcul sur des flottants sans representation exacte
2/ ce calcul n'a pas les mêmes résultats selon le compilo/plateforme/options de compil
Question : Pourquoi cette variabilité ...
Marsh Posté le 13-03-2007 à 18:53:15
Parce que ce bout de code est un bug ambulant.
Au même titre que
Code :
|
Au mieux le compilo en arrive à
Code :
|
au pire, il y a qque transitions [x87/SSE] division [SSE/x87] troncation [SSE/x87] etc...
Le problème n'a rien a voir avec le compilateur ou la plateforme, mais avec le fait que l'auteur pense que le résultat va être 5.
Marsh Posté le 13-03-2007 à 19:09:29
bon, tu sais lire ? ... j'ai BIEN COMPRIS que le résultat doit être 4 ...
Malheureusement, ce n'est pas le résultat obtenu SUR TOUTES LE SPLATEFORMES A MA DISPOSITION
Marsh Posté le 13-03-2007 à 19:52:06
Joel F a écrit : bon, tu sais lire ? ... j'ai BIEN COMPRIS que le résultat doit être 4 ... |
Le monsieur te dit que c'est l'operation que tu fais faire au compilo qui est problematique, et que ton code est donc faux ... Si je fais des depassements de tableaux, je ne me plains pas comme quoi ca ne donne pas les memes resultats sur toutes les plateformes! Ici, c'est pareil.
Marsh Posté le 13-03-2007 à 19:59:12
Joel F a écrit : On repart de 0: 1/ je fais un calcul sur des flottants sans representation exacte Question : Pourquoi cette variabilité ... |
Parce que la norme laisse volontairement dans le flou le cast float ou double --> int (et a fortiori avec size_t), histoire de bénéficier d'optims d'implémentation dans le cast statique.
Donc ce que te dit tbp, c'est qu'on ne doit jamais faire ça avec des nombres, mais tjrs utiliser les fonctions trunc/ceil/floor de <math> qui, s'ils sont correctement codés, devraient être IEEE754 compliant, et donc a priori donner le même résultat sur toutes les plateformes.
C'est donc bien un bug dans ton code.
Par contre, bien sûr, le cast int --> float ou double est autorisé.
Marsh Posté le 13-03-2007 à 20:03:23
Joel F a écrit : On repart de 0: |
wof, même en java, sans strictfp tu manges des bonnes différences.
Marsh Posté le 13-03-2007 à 22:50:52
Qques bémols.
Je n'ai pas dit que les troncations et autres casts étaient verbotten, ni invoqué une violation de la sacro-sainte IEEE 754, mais juste que les présomptions de l'auteur étaient bancales.
En fait il est relativement pénible d'être carré avec les flottants sur un x86, et facile de se tirer dans le pied, ne serait-ce qu'à cause de l'exotisme du x87 (et des ABI). Le laxisme du C/C++ n'arrange rien.
Marsh Posté le 13-03-2007 à 23:31:55
Ace17 a écrit : Le monsieur te dit que c'est l'operation que tu fais faire au compilo qui est problematique, et que ton code est donc faux ... Si je fais des depassements de tableaux, je ne me plains pas comme quoi ca ne donne pas les memes resultats sur toutes les plateformes! Ici, c'est pareil. |
Pas certain que l'analogie soit bonne. Un dépassement de tableaux, c'est un comportement indéfini. Je n'ai pas connaissance que les opérations évoquées précedemment, soit classées "comportement indéfini".
Marsh Posté le 13-03-2007 à 23:33:18
el muchacho a écrit : Parce que la norme laisse volontairement dans le flou le cast float ou double --> int (et a fortiori avec size_t), |
Qu'est-ce qui est flou dans le passage que j'ai quoté un peu plus haut ?
Citation : histoire de bénéficier d'optims d'implémentation dans le cast statique. |
Tu pourrais développer ?
Marsh Posté le 13-03-2007 à 23:43:22
Joel F a écrit : On repart de 0: |
Penses aux transformations - déclenchées par une optimisation - du genre x / 2 --> x * 0.5, qui vont influer sur le résultat du calcul.
Il y a indirectement des réponses aux questions que tu te poses dans n1124.pdf, section <fenv.h>.
Marsh Posté le 14-03-2007 à 05:35:03
++fab a écrit : Qu'est-ce qui est flou dans le passage que j'ai quoté un peu plus haut ?
|
<<la valeur "a peu près 5.000" peut être bien différente suivant les optimisations appliquées. Il n'y a rien dans le standard C++ fasse pour empêcher cela.>>
Ok, je n'étais pas correct.
C'est pas pour le cast qu'il y a un flou mais dans la représentation des flottants. C'est d'ailleurs un des arguments de l'arrière-garde du Fortran contre le C++ en calcul numérique. Une conséquence de ça, c'est que pour rendre les algos numériques le plus portable possible, les constantes flottantes sont souvent écrites en hexadécimal, mais l'exactitude de la répétition du résultat aux bits de poids faibles près sur des architectures différentes n'est pas garantie.
Marsh Posté le 14-03-2007 à 08:55:46
Quitte à penser pour un débile, y a quelque chose qui me turlupine ...
Citation :
|
Si ca c'est défini, je ne vois pas pourquoi la troncature d'un réel flottant ou double précision ne donne pas le même résultat partout.
Ca veut donc dire que :
Code :
|
n'a pas de sens, contrairement à tout ce que l'on m'a enseigné ?
Je suis bien conscient des problèmes de représentation exacte etc ...
ca me fait quand mait gamberger que les optimsiations et/ou réécriture de code autour des calculs puissent faire diverger la sauce tant que ça.
++fab : merci pour le lien. Y a le même genre de doc pour le C++ dispo quelque part ?
Marsh Posté le 14-03-2007 à 09:31:19
Encore une fois le problème n'a pas à voir avec une opération précise, mais le fait que dans le programme en question il n'y a aucune garantie sur les opérations qui vont intervenir, et ensuite aucune garantie sur la précision employée.
Par exemple pour le dernier,
Code :
|
j'ai pu obtenir de g++ un truc équivalent à
Code :
|
alors que dans le pire des cas au moins un appel (avec transfert de flottants), une division et une troncation auraient lieu le tout avec qques transferts possible entre x87/SSE et vice versa (par exemple si l'ABI exige le passage de flottants sur la pile x87, mais que le code est généré pour SSE).
Donc des chemins multiples, chacun avec des marges d'erreur différentes et vous escomptez une égalité... ça ne peut pas marcher.
Marsh Posté le 14-03-2007 à 09:39:25
tbp a écrit : |
donc c'est bien ce que je pensais, y a des trucs qui se passent dans mon dos entre ce que j'écris et ce que le compilateur effectue en réalité.
D'où les différences entre les exécutions sur des palteofrme/compilo différents ?
Marsh Posté le 14-03-2007 à 09:43:12
Oui mais c'est la mauvaise façon de regarder le problème, c'est le programme & les attentes que vous en avez qui sont mal définies.
Et de manière générale on a intérêt à y regarder à 2 fois dès qu'une comparaison entre flottants intervient.
Marsh Posté le 14-03-2007 à 11:19:01
tbp a écrit : Oui mais c'est la mauvaise façon de regarder le problème, c'est le programme & les attentes que vous en avez qui sont mal définies. |
Ok donc
Marsh Posté le 14-03-2007 à 14:41:40
Joel F a écrit : Quitte à penser pour un débile, y a quelque chose qui me turlupine ...
Si ca c'est défini, je ne vois pas pourquoi la troncature d'un réel flottant ou double précision ne donne pas le même résultat partout.
n'a pas de sens, contrairement à tout ce que l'on m'a enseigné ? |
Le C++ l'autorise, c'est pas pour ça qu'il faut l'utiliser. Parfois c'est pratqiue, mais en général, le typage non strict, c'est mal.
Marsh Posté le 12-03-2007 à 09:48:20
Voila un code tout con
Et voila le drame :
Sous MAC OS X
g++ 3.3 Apple variant :
Reading specs from /usr/libexec/gcc/darwin/ppc/3.3/specs
Thread model: posix
gcc version 3.3 20030304 (Apple Computer, Inc. build 1666)
5.000000000000000000000000000000000000
5
Sous Win XP avec Mingw
Reading specs from c:/mingw/bin/../lib/gcc/mingw32/3.4.2/specs
Configured with: ../gcc/configure --with-gcc --with-gnu-ld --with-gnu-as --host=
mingw32 --target=mingw32 --prefix=/mingw --enable-threads --disable-nls --enable
-languages=c,c++,f77,ada,objc,java --disable-win32-registry --disable-shared --e
nable-sjlj-exceptions --enable-libgcj --disable-java-awt --without-x --enable-ja
va-gc=boehm --disable-libgcj-debug --enable-interpreter --enable-hash-synchroniz
ation --enable-libstdcxx-debug
Thread model: win32
gcc version 3.4.2 (mingw-special)
5.000000000000000000000000000000000000
4
Sous Ubuntu 4.xxxx
Using built-in specs.
Target: i486-linux-gnu
Configured
with: ../src/configure -v --enable-languages=c,c++,fortran,objc,obj-c++,treelang --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --program-suffix=-4.1 --enable-__cxa_atexit --enable-clocale=gnu --enable-libstdcxx-debug --enable-mpfr --enable-checking=release
i486-linux-gnu
Thread model: posix
gcc version 4.1.2 20060928 (prerelease) (Ubuntu 4.1.1-13ubuntu5)
5.000000000000000000000000000000000000
4
quid ???
Message édité par Joel F le 12-03-2007 à 09:50:00