Bon, c'est en relation avec Microsoft Windows(c) mais ça prouve bien que même le B-A-BA du fonctionnement d'un logiciel et biaisé par l'OS, et provoque donc des plantages là où ça ne devrai pas.
Alors voici mon problème, je suis en cours de portage d'une de mes applications vers Windows(c)... :-(
Remarquant un bug d'une valeur, je part à la chasse au bug pour finalement isoler le bug suivant :
double a = 800.0 ;
double b = 0.75 ;
double c = 0.6 ;
double d = a*b*c ;
printf("Prend %f * %f * %f = %f ( %i ) = %f ( %i ) %\n", a, b, c, a*b*c, (int)(a*b*c), d, (int)d) ;
Même un développeur de base comprendra ce code.
Et voici le résultat de l'exécution sous Windows (aucun soucis sous linux) :
Prend 800.000000 * 0.750000 * 0.600000 = 360.000000 ( 359 ) = 360.000000 ( 360 )
Peut-t-on m'expliquer ce que fou là ce 359 !? Windows compte mal à ce point ?
Ca m'inquiète sincèrement sur la qualité d'application même bien développé...
Pour information, ça a été compilé avec g++ 3.4.4 sous Windows.
PS: A la base, je voulais poster ça dans le forum de developpez.net (qui est mieux pour les questions dev), mais il est HS. Donc j'ai voulu mettre sur ce forum, qui n'est pas accessible non plus, donc en désespoir de cause, je poste ici :-)
# Erreur de base...
Posté par Calim' Héros (site web personnel) . Évalué à 10.
[^] # Re: Erreur de base...
Posté par jms . Évalué à 3.
http://www.sim07.net/2007/06/25/savez-vous-planter-windows-a(...)
oui oui c'est vieux !
[^] # Re: Erreur de base...
Posté par Calim' Héros (site web personnel) . Évalué à 3.
ça me rappel un concours sur "les meilleurs moyens de planter windows" parus dans un des premiers si ce n'est le premier virus mag.
Un des vainqueurs avait simplement pris une pelle, creusé un trou et mis le windows dedans.
[^] # Re: Erreur de base...
Posté par Zorro (site web personnel) . Évalué à 1.
[^] # Re: Erreur de base...
Posté par Sufflope (site web personnel) . Évalué à 4.
[^] # Re: Erreur de base...
Posté par Nicolas Dumoulin (site web personnel) . Évalué à 2.
Le problème de certains bugs sous windows (de mémoire) est justement d'être imprévisibles.
[^] # Re: Erreur de base...
Posté par Seazor . Évalué à 2.
Et pourtant c'était tout con : un mot de passe du screen saver de plus de 20 caractères. (+ lancer le poste de travail pour l'achever...)
Les 2 personnes ont été déclarées vainqueurs.
[^] # Re: Erreur de base...
Posté par nats . Évalué à 4.
Pour win98 et 95 me semble ^^
[^] # Re: Erreur de base...
Posté par Batchyx . Évalué à 1.
forcement je les ai mis à jour ...
[^] # Re: Erreur de base...
Posté par nats . Évalué à 2.
(Faut pas mettre les " hein)
[^] # Re: Erreur de base...
Posté par Batchyx . Évalué à 1.
et sinon il suffisait juste de télécharger le patch correctif de chez microsoft, puisque ça permettait de faire des DOS sur des serveurs web ...
[^] # Re: Erreur de base...
Posté par nats . Évalué à 3.
Avec la plupart des serveur FTP, si tu demandait un get comX suivi d'une coupure de la connexion (ctrl+c), bah tu avais soit un crash du serveur ftp soit un freeze du thread avec 100% de cpu à l'infinie.
Testé avec guildftp et autres comme serv-u (ca marchait y a deux ans environ, je sais pas si ça a été corrigé) par contre si tu faisait pas le ctrl+c ca tombait pas, je ne sais pas si y a le même genre de problème sous nulix mais c'était marrant et simple comme "DOS" ^^
[^] # Re: Erreur de base...
Posté par inico (site web personnel) . Évalué à 3.
c:\con\con\com1\null\con
Ca crash sur une machine mis à jour.
[^] # Re: Erreur de base...
Posté par Batchyx . Évalué à 1.
J'ai aussi essayé c:\con\con\com1\nul\con
Mon 98 à comme version 4.10.2222
[^] # Re: Erreur de base...
Posté par inico (site web personnel) . Évalué à 2.
En ligne de command, command.com crash mais n'importe pas l'os.
[^] # Re: Erreur de base...
Posté par Batchyx . Évalué à 2.
( http://img468.imageshack.us/my.php?image=win98pasconconnq9.p(...) )
à noter que j'avais fais du windows update ...
[^] # Re: Erreur de base...
Posté par Zorro (site web personnel) . Évalué à 2.
# OS ?
Posté par Thomas Douillard . Évalué à 4.
T'as essayé avec des versions plus récentes de g++ si possible ? Avec des options de compilations différentes ?
Sinon des indications peut être avec g++ -s et le code assembleur généré, tu peux comparer ce que t'as sous windows et sous linux.
Autre info qui manque, le processeur c'est quoi ? ( moi j'en ferai rien, mais ca peut peut être jouer ... )
[^] # Re: OS ?
Posté par Thomas Douillard . Évalué à 4.
Mais c'est peu probable, genre tu fais que des calculs avec des entiers, tout devrait être représentable sans trop de soucis sur des double.
http://www.codecogs.com/reference/math.h/round.php?alias=rou(...)
[^] # Re: OS ?
Posté par Jak . Évalué à 5.
Cachez ce -O que je ne saurais voir.
# ...
Posté par Jak . Évalué à 3.
# Chez moi...
Posté par pasSteve pasJobs . Évalué à 10.
#include <stdio.h>
int main() {
double a = 800.0 ;
double b = 0.75 ;
double c = 0.6 ;
double d = a*b*c ;
printf("Prend %f * %f * %f = %f ( %i ) = %f ( %i ) %\n",
a, b, c, a*b*c, (int)(a*b*c), d, (int)d) ;
return 0;
}
steve@myhost ~ $ gcc test.c -o test
steve@myhost ~ $ ./test
Prend 800.000000 * 0.750000 * 0.600000 = 360.000000 ( 359 ) = 360.000000 ( 360 ) %
steve@myhost ~ $ llvm-gcc test.c -o test
steve@myhost ~ $ ./test
Prend 800.000000 * 0.750000 * 0.600000 = 360.000000 ( 360 ) = 360.000000 ( 360 ) %
steve@myhost ~ $ icc test.c -o test
steve@myhost ~ $ ./test
Prend 800.000000 * 0.750000 * 0.600000 = 360.000000 ( 360 ) = 360.000000 ( 360 ) %
steve@myhost ~ $ gcc --version
gcc (GCC) 4.2.1
Copyright © 2007 Free Software Foundation, Inc.
Ce logiciel est libre; voir les sources pour les conditions de copie. Il n'y a PAS
GARANTIE; ni implicite pour le MARCHANDAGE ou pour un BUT PARTICULIER.
steve@myhost ~ $ llvm-gcc --version # LLVM 2.0
llvm-gcc (GCC) 4.0.1 (Apple Computer, Inc. build 5449)
Copyright © 2005 Free Software Foundation, Inc.
Ce logiciel est libre; voir les sources pour les conditions de copie. Il n'y a PAS
GARANTIE; ni implicite pour le MARCHANDAGE ou pour un BUT PARTICULIER.
steve@myhost ~ $ icc --version
icc (ICC) 10.0 20070426
Copyright (C) 1985-2007 Intel Corporation. All rights reserved.
[^] # Re: Chez moi...
Posté par micha_mosk . Évalué à 4.
[^] # Re: Chez moi...
Posté par inico (site web personnel) . Évalué à 3.
Même chose avec gcc sous Solaris et Windows.
Je cherche d'autre compilateur pour tester.
[^] # Re: Chez moi...
Posté par Batchyx . Évalué à 2.
[^] # Re: Chez moi...
Posté par Moonz . Évalué à 3.
/tmp 19:04 gcc -ffloat-store test.c -o test && ./test
Prend 800.000000 * 0.750000 * 0.600000 = 360.000000 ( 360 ) = 360.000000 ( 360 ) %
Ça marche donc avec -ffloat-store qui est activé pour -O1 (ou supérieur) ou -Os. En fait, il n'y a que -O0 qui fout la merde :)
[^] # Re: Chez moi...
Posté par Vivi (site web personnel) . Évalué à 1.
Le but de cette option est d'empêcher de se trimballer des résultats intermédaires flottants ayant plus de 64 bits de précision. Donc ça rajoute (en gros) des store/load après chaque calcul flottant pour forcer une troncation à 64 bits et assurer un calcul plus conforme à la norme IEEE.
Le meilleur moyen d'éviter ces problèmes, c'est d'utiliser une plateforme faisant ses calculs flottans en 64bits, donc abandonner le FPU x87. C'est en fait trés facile avec un ordi récent, il suffit d'utiliser le SSE2: option -msse2 -mfpmath=sse pour un x86, rien à faire pour un x86_64.
# c'est normal
Posté par aedrin . Évalué à 10.
le cast d'un flottant vers un int consiste à tronquer la partie fractionnaire (donc arrondi vers 0).
dans un cas tu tronques un double (d) dont la représentation (64 bits IEEE754) est visiblement >= 360 et < 361 (et donc tu récupères 360)
dans l'autre tu tronques le résultat d'une opération de multiplication entre doubles dont la structure interne peut (et visiblement c'est le cas) être plus précise qu'un double (parfois c'est 80bits, parfois 128, etc.) et qui dépend du compilo, de ta plateforme et de l'age du capitaine. Dans cette représentation temporaire, (a*b*c) est visiblement >= 359 et < 360.
Essaie donc de faire : (int)((double)(a*b*c)) et je suppute un petit 360.
Autre solution plus simple, lorsqu'on veut arrondir (mais je ne m'avance pas trop ce n'est pas forcément ce que tu veux faire ici) on fait plutôt (int)(x + 0.5) pour x >= 0
Je t'invite à (re)lire "What Every Computer Scientist Should Know About Floating-Point Arithmetic" : http://www.physics.ohio-state.edu/~dws/grouplinks/floating_p(...)
[^] # Commentaire supprimé
Posté par Anonyme . Évalué à 9.
Ce commentaire a été supprimé par l’équipe de modération.
[^] # Re: c'est normal
Posté par Vivi (site web personnel) . Évalué à 1.
Bof, le (a*b*c) est déjà de type double, le cast supplémentaire vers double ne sert à rien et sera sans doute ignoré par le compilo.
Ca dépend vraiment du backend du compilo, c'est difficile d'influer là dessus en modifiant le source C. Plein de paramètres peuvent influencer l'assembleur généré: le niveau d'optim, le code environnant, etc.
# "Facile"...
Posté par Pierre Carrier . Évalué à 6.
Merci a Bernard Parisse, UJF.
[^] # Re: "Facile"...
Posté par Jak . Évalué à 3.
# grumph
Posté par Éric (site web personnel) . Évalué à 9.
Quand je vois ça en PHP ou dans les scripts j'accepte que le développeur ne sache pas, mais quand on travaille à bas niveau comme dans le C, ça fait partie des pré-requis je pense.
Le pire c'est quand le développeur ne peut penser que à un bug des outils, jamais à se remettre en cause.
[^] # Re: grumph
Posté par aedrin . Évalué à 10.
en fait il s'est trompé de jour, il aurait dû poster hier... ;-)
[^] # Re: grumph
Posté par LeMagicien Garcimore . Évalué à 2.
[^] # Re: grumph
Posté par Nicolas Schoonbroodt . Évalué à 8.
* je fais une généralité, même si c'est une minorité, cette minorité suffit à faire la réputation de tous, un peu comme "les supporters de foots sont idiots"
[^] # Re: grumph
Posté par Calim' Héros (site web personnel) . Évalué à 10.
Alors la je ne suis pas d'accord, si c'était le même cas, on dirait que les supporter de foot sont intelligents puisque c'est la que ce trouve la minorité.
# géo trouvetout
Posté par matthieu bollot (site web personnel, Mastodon) . Évalué à 6.
[^] # Re: géo trouvetout
Posté par Calvin0c7 . Évalué à 8.
L'explication c'est qu'en binaire 1.30 ça fait à peu près 1.0100110011001100110011001100110011001100110011001101 (c'est une approximation) et 2.70 ça fait 10.10110011001100110011001100110011001100110011001101 (également un approximation).
Et quand tu additionne les deux (1.0100110011001100110011001100110011001100110011001101+
10.10110011001100110011001100110011001100110011001101 un ordinateur ça calcule en binaire) ça donne 11.1111111111111111111111111 soit 3.999999999999999.
Tu vois que le calcul est donc rigoureusement exact :)
Pour vérifier tu trouveras un convertisseur ici : http://www.michelcarrare.com/demos/converter.php
@+
Calvin
[^] # Re: géo trouvetout
Posté par Infernal Quack (site web personnel) . Évalué à 5.
Heureusement que je t'avais expliqué ça vendredi sinon ça aurait pu être toi l'auteur de ce message. Surtout que toi aussi tu n'aimes pas trop Microsoft : "Word c'est de la merde" :-)
L'association LinuxFr ne saurait être tenue responsable des propos légalement repréhensibles ou faisant allusion à l'évêque de Rome, au chef de l'Église catholique romaine ou au chef temporel de l'État du Vatican et se trouvant dans ce commentaire
[^] # Re: géo trouvetout
Posté par Calvin0c7 . Évalué à 3.
Si tu ne me l'avais pas expliqué j'aurai dit "moi aussi moi aussi j'ai des bugs comme ça en java ! Windows et Java c'est buggé".
Alors qu'en fait non, enfin en tout cas pas Java.
Merci de m'avoir permis de briller en société, j'en ai besoin...
# 2+2=5
Posté par olivn . Évalué à 3.
http://www.thinkgeek.com/tshirts/coder/60f5/
[^] # Re: 2+2=5
Posté par hocwp (site web personnel) . Évalué à 3.
variable two 3 two !
: 2 ( -- n) 5 two @ - dup two ! ;
Qui permet de calculer 2+2=5
2 2 + . -> 5 :-)
2 . -> 2
2 . -> 3
2 . -> 2 ....
Au passage, je sais que ce genre de bidouille est faisable en Lisp, mais vous connaissez d'autres langages qui permettent de faire ce genre de truc inutile (juste pour le fun) ?
[^] # Re: 2+2=5
Posté par hocwp (site web personnel) . Évalué à 2.
(let ((two 3))
(defun my-two (stream char)
(declare (ignore stream char))
(setq two (- 5 two))
two))
(set-macro-character #\2 #'my-two)
CL-USER> (+ 2 2)
5
CL-USER> 2
3
CL-USER> 2
2
CL-USER> 2
3
Et en C sous Windows ça donne quoi ? :-)
[^] # Re: 2+2=5
Posté par Calim' Héros (site web personnel) . Évalué à 5.
Dire qu'avant il suffisait d'un pentium pour faire ça naturellement...
# Heisenbug...
Posté par Joris Dedieu (site web personnel) . Évalué à 4.
http://fr.wikipedia.org/wiki/Heisenbug
http://linuxfr.org/~Krunch/22577.html
# de plus...
Posté par Sylvain Rampacek (site web personnel) . Évalué à 2.
Le %f n'affiche le double qu'avec une précision de float... donc il y a encore des risques d'imprécisions.
[^] # Re: de plus...
Posté par LeMagicien Garcimore . Évalué à 5.
Extrait de la doc gnu libc :
The `%f' conversion prints its argument in fixed-point notation, producing output of the form [-]ddd.ddd, where the number of digits following the decimal point is controlled by the precision you specify.
et plus loin :
Without a type modifier, the floating-point conversions use an argument of type double. (By the default argument promotions, any float arguments are automatically converted to double.)
et man printf est d'accord :
f,F The double argument is rounded and converted to decimal notation in the style [-]ddd.ddd, where the number of digits after the decimal-point character is equal to the precision specification.
sinon, %g choisi automatiquement la representation la plus lisible suivant la valeur de l'argument (%f ou %e). et %lf est invalide.
[^] # Re: de plus...
Posté par Sylvain Rampacek (site web personnel) . Évalué à 1.
mais bon, j'ai souvenir que dans certains de mes programmes, je préférais voir le résultat en %g qu'en %f... enfin, ça dépend de tellement de paramètres...
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.