Aucune idée, je sais pas ce qu'il y a dedans. Donne les premières lignes pour voir
Sinon, peux tu aussi donner plus d'infos sur la ligne de commande gcc utilisé ? Tu es sur un machine "standard" (pas embarqué, pas supercalculateur) ?
Nan je suis sur un PC portable comme on en trouve dans le commmerce, c'est un HP, Core i5, ..., (je vais t'épargner tout le lshw).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 .file "main.cpp" .section .text._ZStanSt13_Ios_FmtflagsS_,"axG",@progbits,_ZStanSt13_Ios_FmtflagsS_,comdat .weak _ZStanSt13_Ios_FmtflagsS_ .type _ZStanSt13_Ios_FmtflagsS_, @function _ZStanSt13_Ios_FmtflagsS_: .LFB585: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 movl 8(%ebp), %edx movl 12(%ebp), %eax andl %edx, %eax popl %ebp .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc .LFE585: .size _ZStanSt13_Ios_FmtflagsS_, .-_ZStanSt13_Ios_FmtflagsS_ .section .text._ZStorSt13_Ios_FmtflagsS_,"axG",@progbits,_ZStorSt13_Ios_FmtflagsS_,comdat .weak _ZStorSt13_Ios_FmtflagsS_ .type _ZStorSt13_Ios_FmtflagsS_, @function _ZStorSt13_Ios_FmtflagsS_: .LFB586: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 movl 8(%ebp), %edx movl 12(%ebp), %eax orl %edx, %eax popl %ebp .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc .LFE586: .size _ZStorSt13_Ios_FmtflagsS_, .-_ZStorSt13_Ios_FmtflagsS_ .section .text._ZStcoSt13_Ios_Fmtflags,"axG",@progbits,_ZStcoSt13_Ios_Fmtflags,comdat .weak _ZStcoSt13_Ios_Fmtflags .type _ZStcoSt13_Ios_Fmtflags, @function _ZStcoSt13_Ios_Fmtflags: .LFB588: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 movl 8(%ebp), %eax notl %eax
mes "quelques optimisations anti erreurs".
Si je me souviens bien, sans l'option, le code ne tente pas de se ramener à un double au sens strict à chaque étape du calcul.
Mes principes de bases du codeur qui veut pouvoir dormir:Pour faire des graphes, essayez yEd.
- Une variable de moins est une source d'erreur en moins.
- Un pointeur de moins est une montagne d'erreurs en moins.
- Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
- jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
- La plus sotte des questions est celle qu'on ne pose pas.
le ter nel est le titre porté par un de mes personnages de jeu de rôle
Source : 11.7 Disappointments and Misunderstandings
En fait, ce qui m'étonne surtout, c'est que normalement, gcc utilise les registres sse pour ce genre de calcul, ce qui n'est pas le cas de ton code. Tu compiles avec quelles options ?On 68000 and x86 systems, for instance, you can get paradoxical results if you test the precise values of floating point numbers. For example, you can find that a floating point value which is not a NaN is not equal to itself. This results from the fact that the floating point registers hold a few more bits of precision than fit in a double in memory. Compiled code moves values between memory and floating point registers at its convenience, and moving them into memory truncates them.
You can partially avoid this problem by using the -ffloat-store option (see Optimize Options).
@leternel
En fait, je pense plutôt qu'il passe par les registres x87, qui sont à 80 bits au lieu de 64, d'où la différence. Chez les autres personnes qui ont testé, ça doit passer par les registres SSE qui sont bien à 64 bits
Comme je l'ai expliqué tout à l'heure à rOd, sur mon problème je compile avec l'optimisation -Os, mais pour l'exemple simple (Foo, Bar, ...) je compile sans option:
Et la différence apparait tout de même (sans l'option -ffloat-store).
Code : Sélectionner tout - Visualiser dans une fenêtre à part g++ -o main main.cpp
En fait, il y a plein d'option de compilation par défaut que tu vois pas. Compile avec
Code : Sélectionner tout - Visualiser dans une fenêtre à part g++ -o main main.cpp -v
Effectivement
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 Utilisation des specs internes. COLLECT_GCC=g++ COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-linux-gnu/4.7/lto-wrapper Target: i686-linux-gnu Configuré avec: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.7.2-2ubuntu1' --with-bugurl=file:///usr/share/doc/gcc-4.7/README.Bugs --enable-languages=c,c++,go,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.7 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.7 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --enable-targets=all --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=i686-linux-gnu --host=i686-linux-gnu --target=i686-linux-gnu Modèle de thread: posix gcc version 4.7.2 (Ubuntu/Linaro 4.7.2-2ubuntu1) COLLECT_GCC_OPTIONS='-o' 'main' '-v' '-shared-libgcc' '-mtune=generic' '-march=i686' /usr/lib/gcc/i686-linux-gnu/4.7/cc1plus -quiet -v -imultiarch i386-linux-gnu -D_GNU_SOURCE main.cpp -quiet -dumpbase main.cpp -mtune=generic -march=i686 -auxbase main -version -fstack-protector -o /tmp/cc1PKSE6.s GNU C++ (Ubuntu/Linaro 4.7.2-2ubuntu1) version 4.7.2 (i686-linux-gnu) compiled by GNU C version 4.7.2, GMP version 5.0.2, MPFR version 3.1.0-p3, MPC version 0.9 heuristiques GGC: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 le répertoire « /usr/local/include/i386-linux-gnu » est ignoré car inexistant le répertoire « /usr/lib/gcc/i686-linux-gnu/4.7/../../../../i686-linux-gnu/include » est ignoré car inexistant la recherche pour #include "..." débute ici : la recherche pour #include <...> débute ici: /usr/include/c++/4.7 /usr/include/c++/4.7/i686-linux-gnu /usr/include/c++/4.7/backward /usr/lib/gcc/i686-linux-gnu/4.7/include /usr/local/include /usr/lib/gcc/i686-linux-gnu/4.7/include-fixed /usr/include/i386-linux-gnu /usr/include Fin de la liste de recherche. GNU C++ (Ubuntu/Linaro 4.7.2-2ubuntu1) version 4.7.2 (i686-linux-gnu) compiled by GNU C version 4.7.2, GMP version 5.0.2, MPFR version 3.1.0-p3, MPC version 0.9 heuristiques GGC: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 Compiler executable checksum: 35c5a24ca91b342f120e3f1ace87b1cc COLLECT_GCC_OPTIONS='-o' 'main' '-v' '-shared-libgcc' '-mtune=generic' '-march=i686' as -v --32 -o /tmp/cclEQAt2.o /tmp/cc1PKSE6.s Version de l'assembleur GNU 2.22.90 (i686-linux-gnu) utilisant la version BFD (GNU Binutils for Ubuntu) 2.22.90.20120924 COMPILER_PATH=/usr/lib/gcc/i686-linux-gnu/4.7/:/usr/lib/gcc/i686-linux-gnu/4.7/:/usr/lib/gcc/i686-linux-gnu/:/usr/lib/gcc/i686-linux-gnu/4.7/:/usr/lib/gcc/i686-linux-gnu/ LIBRARY_PATH=/usr/lib/gcc/i686-linux-gnu/4.7/:/usr/lib/gcc/i686-linux-gnu/4.7/../../../i386-linux-gnu/:/usr/lib/gcc/i686-linux-gnu/4.7/../../../../lib/:/lib/i386-linux-gnu/:/lib/../lib/:/usr/lib/i386-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/i686-linux-gnu/4.7/../../../:/lib/:/usr/lib/ COLLECT_GCC_OPTIONS='-o' 'main' '-v' '-shared-libgcc' '-mtune=generic' '-march=i686' /usr/lib/gcc/i686-linux-gnu/4.7/collect2 --sysroot=/ --build-id --no-add-needed --as-needed --eh-frame-hdr -m elf_i386 --hash-style=gnu -dynamic-linker /lib/ld-linux.so.2 -z relro -o main /usr/lib/gcc/i686-linux-gnu/4.7/../../../i386-linux-gnu/crt1.o /usr/lib/gcc/i686-linux-gnu/4.7/../../../i386-linux-gnu/crti.o /usr/lib/gcc/i686-linux-gnu/4.7/crtbegin.o -L/usr/lib/gcc/i686-linux-gnu/4.7 -L/usr/lib/gcc/i686-linux-gnu/4.7/../../../i386-linux-gnu -L/usr/lib/gcc/i686-linux-gnu/4.7/../../../../lib -L/lib/i386-linux-gnu -L/lib/../lib -L/usr/lib/i386-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/i686-linux-gnu/4.7/../../.. /tmp/cclEQAt2.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/i686-linux-gnu/4.7/crtend.o /usr/lib/gcc/i686-linux-gnu/4.7/../../../i386-linux-gnu/crtn.o
Ca commence à sortir de mes compétences
Un point de différence avec mon gcc, c'est que je compile en -march=x86-64 alors que tu es en -march=i686. Ta version génère un code compatible avec les anciennes architectures (Pentium IV, III, etc), qui n'avaient pas de SSE. Ca vient peut être de là. Essaies en forçant l'architecture :
Tu peux également utiliser -march=native pour laisser la compilateur choisir l'architecture en fonction du processeur utilisé lors de la compilation (ce qui peut réduire la portabilité du binaire généré)
Code : Sélectionner tout - Visualiser dans une fenêtre à part g++ -march=x86-64 -o main main.cpp
Source : 3.17.16 Intel 386 and AMD x86-64 Options
Par contre, je ne sais pas d'où vient une telle configuration de gcc. Tu l'as installé comment ?
Là par contre l'option n'a rien changé.
En même temps c'est normal, j'ai installé un Xubuntu 32bits sur un PC 64bits.
J'ai installé avec synaptic le paquet build-essential.
Ah... je sais pas alors. Mais effectivement, si tu es en 32 bits, je sais pas très bien ce qui est généré et comment le comporte le programme. J'imagine que cela peut se comporter comme si tu utiliser des float et double dans ton programme ? Bref, cela sort de mes compétences à ce niveau Essaies différentes options de compilation, comme -sse2 ou -m32/-m64
Un peu de lecture, sur le fonctionnement bas niveau des processeurs : http://www.agner.org/optimize/#manuals (niveau avancé)
EDIT : sinon, sans aller aussi loin que leternel, si tu as des contraintes importantes concernant la précision des calculs (plusieurs dizaines de chiffres après la virgule), tu devras te plonger profondement dans le fonctionnement des compilateurs, des processeurs, du bas niveau, etc (à lire, la série d'article d'Alex Darby sur la programmation bas niveau)
"loin", c'est un grand mot.
J'ai juste subit deux ou trois revers assez vicieux à cause de ce problème, alors je me cantonne à ce que je maîtrise.
Bien sûr qu'on peut avoir une égalité entre double, mais rarement quand on en a besoin.
Du coup, il m'est arrivé de faire des choix d'implémentations pour éviter le double, quitte à perdre un peu de naturel dans les détails. Par exemple, sachant que j'avais le nombre de note, ne pas garder une moyenne mais un total dans la classe, et faire la division si besoin est.
Mes principes de bases du codeur qui veut pouvoir dormir:Pour faire des graphes, essayez yEd.
- Une variable de moins est une source d'erreur en moins.
- Un pointeur de moins est une montagne d'erreurs en moins.
- Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
- jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
- La plus sotte des questions est celle qu'on ne pose pas.
le ter nel est le titre porté par un de mes personnages de jeu de rôle
@leternel
Je disais "loin" par rapport à fait que ta phrase signifier "rejeter en masse toutes comparaisons d'égalité sur les réels". Par contre, au final, dans l'attitude, tu as probablement raison de considérer par défaut que rien ne se passe comme attendu. Dans les faits, sauf cas d'application spécifiques, je fais pareil
En fait, j'aurais du mal à m'extraire de l'utilisation des double, car je démarre une nouvelle implémentation d'un code qui doit produire les même résultats qu'un vieux code (mal foutu).
Et donc, d'après vous, à partir de combien de décimales on peut considérer que c'est un problème d'approximation flottante et non moi qui ai introduit un bias dans les calculs.
Parceque là, c'est à peut près à la 15ème décimale que ça diffère.
Et c'est justement en voulant savoir pourquoi ça différait que je suis tombé sur ce problème de variable intermédiaire.
Je précise qu'il s'agit d'un code de simulation physique (donc beaucoup de calculs flottants ).
j'avoue qu'il faut être extrêmement prudent lorsqu'on compare des flottants, et je dirais même plus: "c'est comme les pointeurs: à n'utiliser que si on ne peut pas faire autrement".
Et ces problèmes de flottants ne sont pas spécifiques à c++, c'est vrai aussi dans tous les autres langages que je connais (en c#, on arrive même à des résultats différents selon la version du framework utilisé et l'os).
« L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
Spinoza — Éthique III, Proposition VII
Oui en effet, mais je l'explique plus haut, je ne fais pas de comparaisons de flottants à proprement parlé :
Je reproduis la simulation avec les même entrées avec mon code pour le comparer à l'ancien et à la fin je compare "visuellement" les resultats.
Code : Sélectionner tout - Visualiser dans une fenêtre à part if(oldResult==newResult)
Si vous avez une autre méthode de comparaison, je suis preneur.
Ca dépend de ton contexte. Si tu fais des calculs de risque (booking) et que tes résultats sont destinés à être récupéré par une macro excel, alors 2 décimales sont suffisantes.
Si tes calculs sont destinés à calculer la trajectoire du satellite qui va être envoyé sur Mars, alors il en faudra plus.
En fait, si la précision est tellement importante, alors il faut opter pour une structure "fait maison" à base d'entiers, ou alors une bibliothèque faite pour.
De façon générale, dans la vraie vie, le delta du bias est le résultat de tests (souvent effectués par les clients si vous voyez ce que je veux dire...). Il n'est presque jamais décidé à priori.
« L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
Spinoza — Éthique III, Proposition VII
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager