OVH Cloud OVH Cloud

[débutant] "Exception en point flottant"

11 réponses
Avatar
Dudule
Bonsoir,

Voici le code d'une application simple, pour appliquer l'apprentissage des
fonctions. Le programme a pour but de séparer les chiffres d'un entier.
La toute dernière instruction empêche l'exécution, et est à l'origine du
message figurant en sujet.

Merci pour votre aide.

#include <iostream>
using std::cin;
using std::cout;
using std::endl;

unsigned short int quotient(unsigned short int, unsigned short int);
unsigned short int reste(unsigned short int, unsigned short int);
void affichage(unsigned short int);

int main()
{
int nombre;
do
{
cout << "Entrez un entier entre 1 et 32767: ";
cin >> nombre;
} while (nombre<=0 || nombre>=32768);

affichage(nombre);

return 0;
}

unsigned short int quotient(unsigned short int nombre, unsigned short int
diviseur)
{
return nombre/diviseur;
}

unsigned short int reste(unsigned short int nombre, unsigned short int
diviseur)
{
return nombre%diviseur;
}

void affichage(unsigned short int nombre)
{
unsigned short int diviseur=10000;
unsigned short int quot;


for (int i=5; i>=0; i--)
{
quot = quotient(nombre,diviseur);
if (quot!=0)
cout << quot << " ";
nombre = reste(nombre,diviseur);

/******** ligne à problème !! ********/
diviseur /= 10;
}
}

10 réponses

1 2
Avatar
Fabien LE LEZ
On Tue, 10 May 2005 00:48:48 +0200, Dudule
:

"Exception en point flottant"


Mon dieu mon dieu... les messages traduits en "français" sont toujours
aussi risibles. J'imagine que c'est la traduction babelfishienne de
"floating-point exception" ?

Par contre, j'avoue n'avoir pas la moindre idée de la cause de
l'erreur, puisque ton programme n'utilise que des entiers.
--
Le grand site de la philosophie animale : <http://perso.edulang.com/philo/>

Avatar
Oodini

"Exception en point flottant"


Mon dieu mon dieu... les messages traduits en "français" sont toujours
aussi risibles. J'imagine que c'est la traduction babelfishienne de
"floating-point exception" ?


Message donné en natif par ma SuSE 9.2 Pro.

Par contre, j'avoue n'avoir pas la moindre idée de la cause de
l'erreur, puisque ton programme n'utilise que des entiers.


Merci néanmoins de l'intervention.


Avatar
Pierre Maurette

"Exception en point flottant"


Mon dieu mon dieu... les messages traduits en "français" sont toujours
aussi risibles. J'imagine que c'est la traduction babelfishienne de
"floating-point exception" ?


Message donné en natif par ma SuSE 9.2 Pro.
Linux s'améliore ces derniers temps dans sa francisation, mais ça reste

hétérogène et approximatif. Mais comme même les messages en anglais
sont parfois folklos ...

Pour votre problème, il est clair que la boucle dans affichage() "veut"
tourner 6 fois, et que diviseur prendra les valeurs 10000, 1000, 100,
10, 1, 0 (boom, division par 0). Comportement normal quand on poste à
minuit 48 puis 3h40 ;-)
Pourquoi "Exception en point flottant" ? Je n'en sais trop rien. Très
mauvaise traduction de "arithmetic exception" ? Il faudrait quand même
voir la doc (Intel ?) pour être certain.

Vous pourriez déclarer quotient() et reste() inline. Vous pourriez
également vous en passer *ici*, mais le comportement ne serait pas le
même dans tous les cas.

--
Pierre



Avatar
Cyrille
Bonsoir,

Voici le code d'une application simple, pour appliquer l'apprentissage des
fonctions. Le programme a pour but de séparer les chiffres d'un entier.
La toute dernière instruction empêche l'exécution, et est à l'origine du
message figurant en sujet.


Qu'est-ce qui te fait dire que c'est cette ligne qui provoque l'erreur?

for (int i=5; i>=0; i--)
{
quot = quotient(nombre,diviseur);
if (quot!=0)
cout << quot << " ";
nombre = reste(nombre,diviseur);

/******** ligne à problème !! ********/
diviseur /= 10;
}


Bon, dans cette boucle, diviseur est égal à 10000 la première fois quand
i==5, 1000 quand i==4... et donc 0 quand i==0. Dans quotient(), tu as
alors une division par zéro. Il faut arrêter la boucle avant, donc la
remplacer par:
"for (int i=5; i>0; i--)"
ou mieux, puisque tu ne te sers pas de i dans ta boucle, autant exprimer
concrètement les conditions de début et de fin de la boucle selon ce
diviseur:
"for (unsigned short diviseur = 10000; diviseur != 0; diviseur /= 10)"

--
win the yes need the no to win against the no!

Avatar
kanze
Pierre Maurette wrote:

"Exception en point flottant"


Mon dieu mon dieu... les messages traduits en "français"
sont toujours aussi risibles. J'imagine que c'est la
traduction babelfishienne de "floating-point exception" ?


Message donné en natif par ma SuSE 9.2 Pro.
Linux s'améliore ces derniers temps dans sa francisation, mais

ça reste hétérogène et approximatif. Mais comme même les
messages en anglais sont parfois folklos ...

Pour votre problème, il est clair que la boucle dans
affichage() "veut" tourner 6 fois, et que diviseur prendra les
valeurs 10000, 1000, 100, 10, 1, 0 (boom, division par 0).
Comportement normal quand on poste à minuit 48 puis 3h40 ;-)

Pourquoi "Exception en point flottant" ? Je n'en sais trop
rien. Très mauvaise traduction de "arithmetic exception" ? Il
faudrait quand même voir la doc (Intel ?) pour être certain.


Des raisons historiques. Sous Unix, un trappe hardware se
manifeste normalement par un signal. Dans les premiers Unix, il
y avait bien des SIGDIV0 (division par zéro) et des SIGFPE
(«@floating point exception »). Et la plupart du temps, un
SIGFPE pour une division par zéro flottant, ce qui prêtait à
confusion. À je ne sais pas quelle époque, la décision a été
prise d'unifier toutes les erreurs dues à l'arithmétique en un
signal -- que pour des raisons de compatibilité en arrière, on
nommait SIGFPE. Malheureusement, la plupart de la documentation
continue encore à décrire SIGFPE comme « floating point
exception ».

La page de man Solaris dit « arithmetic exception » (mais le
commentaire dans le fichier d'en-tête dit encore « floating
point exception ».) Le message que j'ai du shell, lorsqu'un
processus se termine par un SIGFPE, c'est aussi « arithmetic
exception ». Et le shell, dans mon cas, c'est bash -- le même
que sous Linux. Alors, ou bien, il y a une erreur dans
l'implémentation pour Linux, ou bien il y a une erreur (vraiment
grossière) dans la traduction.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34




Avatar
Fabien LE LEZ
On 10 May 2005 00:54:22 -0700, :

ou bien il y a une erreur (vraiment
grossière) dans la traduction.


Comme la traduction a manifestement été faite par un logiciel, pas par
un humain, il y a peu de chances pour que cette erreur ait pu se
glisser.
--
Le grand site de la philosophie animale : <http://perso.edulang.com/philo/>

Avatar
Dudule
Pierre Maurette wrote:

"Exception en point flottant"



Message donné en natif par ma SuSE 9.2 Pro.
Linux s'améliore ces derniers temps dans sa francisation, mais ça reste

hétérogène et approximatif. Mais comme même les messages en anglais
sont parfois folklos ...


Ca m'a tout l'air d'être le cas ici, vu l'explication du problème que vous
fournissez. :-)

Pour votre problème, il est clair que la boucle dans affichage() "veut"
tourner 6 fois, et que diviseur prendra les valeurs 10000, 1000, 100,
10, 1, 0 (boom, division par 0).


Effectivement...
Mais le problème n'apparaît alors qu'à la dernière itération.
Pourquoi les autres itérations n'effectuent-elles par leur cout ?
Cela m'aurait sans doute mis sur la voie (je pensais que j'avais un problème
de typage, avec ce message abscons).

Comportement normal quand on poste à minuit 48 puis 3h40 ;-)


Je vois que vous ne négligez aucune information pour mesurer la dimension
d'un problème. :-)

Vous pourriez déclarer quotient() et reste() inline. Vous pourriez
également vous en passer *ici*, mais le comportement ne serait pas le
même dans tous les cas.


Comme je n'ai appris que très récemment les fonctions inline, peut-être
pourriez-vous m'éclairer. J'ai compris que les fonctions inline était un
peu comme un #include, excepté que l'intérêt de copier la fonction sur
place est laissé à la discrétion du compilateur.
Cela serait donc un compromis entre le "coût" de l'appel à la fonction, et
le coût de la consommation mémoire du fait de "copier" la fonction à chaque
fois qu'elle est appelée.
Est-ce bien cela ?

Si j'ai bien compris, ce qui motive votre suggestion est je suppose l'unique
utilisation des fonctions ?




Avatar
Dudule
Cyrille wrote:

Bon, dans cette boucle, diviseur est égal à 10000 la première fois quand
i==5, 1000 quand i==4... et donc 0 quand i==0. Dans quotient(), tu as
alors une division par zéro. Il faut arrêter la boucle avant, donc la
remplacer par:
"for (int i=5; i>0; i--)"


Diagnostic effectivement exact...

ou mieux, puisque tu ne te sers pas de i dans ta boucle, autant exprimer
concrètement les conditions de début et de fin de la boucle selon ce
diviseur:
"for (unsigned short diviseur = 10000; diviseur != 0; diviseur /= 10)"


Suggestion pleine de bon sens que j'applique derechef dans mon code. :-)
Merci !

Avatar
Pierre Maurette
Dudule, le 10/05/2005, a écrit :[...]
Effectivement...
Mais le problème n'apparaît alors qu'à la dernière itération.
Pourquoi les autres itérations n'effectuent-elles par leur cout ?
Cela m'aurait sans doute mis sur la voie (je pensais que j'avais un problème
de typage, avec ce message abscons).
(je suis très mauvais sur le "cout")

cout envoie ses trucs vers un flux de sortie associé au périphérique
standard stdout, l'écran de la console dans votre cas. Ce flux est
tamponné (bufférisé, buffered), c'est à dire qu'il ne se videra vers le
périphérique que ... quand il le voudra (honnêtement, je suis un peu
flou là dessus). On va dire en fin de ligne, donc vous auriez pu faire:
cout << quot << endl;
à la place de
cout << quot << " ";
(bien sûr, le réultat n'est pas le même).
Vous auriez également pu écrire:
cout << quot << " ";
fflush(stdout);
Mais il ne s'agit là que de modification du code pour tracer, comme
vous auriez pu ajouter des cin, des system("PAUSE") (DOS/Windows), etc.
La vraie solution, c'est le débogueur. C'est vrai que sous Linux, c'est
assez rustique :-( . Je crois que c'est limité à GDB. J'ai essayé DDD,
qui enjolive GDB, bon ... Mais un simpe débogueur source (et plus si
affinités) est un outil pédagogoque irremplaçable. J'admets qu'il
présente un petit danger, celui de faire en sorte que ça marche, sans
se préoccuper de la norme.


[...]
Comme je n'ai appris que très récemment les fonctions inline, peut-être
pourriez-vous m'éclairer. J'ai compris que les fonctions inline était un
peu comme un #include, excepté que l'intérêt de copier la fonction sur
place est laissé à la discrétion du compilateur.
Plutôt un #define qu'un #include, non ?


Cela serait donc un compromis entre le "coût" de l'appel à la fonction, et
le coût de la consommation mémoire du fait de "copier" la fonction à chaque
fois qu'elle est appelée.
Est-ce bien cela ?

Si j'ai bien compris, ce qui motive votre suggestion est je suppose l'unique
utilisation des fonctions ?
En fait, je ne vois pas très bien pourquoi une fonction. A part le fait

d'écrire quotient et reste, qui peut en être une très bonne. Il peut y
en avoir une autre, en partie due à cette cochonnerie d'opérateur /,
qui mélange division euclidienne et division réelle. Et là,
effectivement, la fonction n'est pas équivalent à l'opérateur seul:

inline int quotient(int a, int b) {return a / b;}
/* ............. */
long double x = 1.154;
long double y = 5.487;
long double z, t;

z = quotient(x, y);
t = x / y;

cout << z << endl;
cout << t << endl;

--
Pierre

Avatar
kanze
Dudule wrote:
Pierre Maurette wrote:

"Exception en point flottant"



Message donné en natif par ma SuSE 9.2 Pro.


Pour votre problème, il est clair que la boucle dans
affichage() "veut" tourner 6 fois, et que diviseur prendra
les valeurs 10000, 1000, 100, 10, 1, 0 (boom, division par
0).


Effectivement...
Mais le problème n'apparaît alors qu'à la dernière itération.
Pourquoi les autres itérations n'effectuent-elles par leur
cout ? Cela m'aurait sans doute mis sur la voie (je pensais
que j'avais un problème de typage, avec ce message abscons).


Elles l'ont sans doute effectuées. Si tu avais régardé le buffer
de cout juste avant le core, tu aurais vu les caractères que tu
y as mis.

Note bien que quand tu écris à cout, les caractères sont mis en
buffer. C'est tout. Le buffer n'est transféré au système que
lors d'une commande de flush, la fin *normal* du programme ou
quand le buffer soit plein. C'est pourquoi on conseille aux
débuttants d'utiliser toujours un std::endl pour terminer la
ligne, et non un 'n' -- std::endl est un manipulateur qui
ajoute le 'n', puis appelle flush() pour s'assurer que les
données soient passées au système.

Comportement normal quand on poste à minuit 48 puis 3h40 ;-)


Je vois que vous ne négligez aucune information pour mesurer
la dimension d'un problème. :-)


Il ne faut jamais mésestîmer l'importance des aspects
humains:-).

Vous pourriez déclarer quotient() et reste() inline. Vous
pourriez également vous en passer *ici*, mais le
comportement ne serait pas le même dans tous les cas.


Comme je n'ai appris que très récemment les fonctions inline,
peut-être pourriez-vous m'éclairer.


C'est une technique qu'on utilise pour optimiser le code, une
fois que le profiler nous dit que c'est là qu'il faut optimiser.

J'ai compris que les fonctions inline était un peu comme un
#include, excepté que l'intérêt de copier la fonction sur
place est laissé à la discrétion du compilateur.


C'est plus compliqué que ça, au moins si on veut comprendre
toutes les implications du côté du compilateur, ce qui est
garantie, ce qui ne l'est pas, etc. Pour un débuttant, voire
même un programmeur moyen, les deux choses essentielles à
retenir, c'est 1) qu'ils sont un moyen infaillible à augmenter
le couplage entre des modules, et 2) qu'ils offrent des moyens
assez subtiles pour introduire le comportement indéfini dans un
programme. La contrapartie, c'est qu'en tant que moyen
d'optimisation, elles peuvent être plutôt efficace dans certains
cas, à un coût extrèmement faible en termes d'effort du
programmeur ou d'effet sur la lisibilité du programme.

En passant, j'ajouterai qu'avec la plupart des implémentations
aujourd'hui, les templates ont aussi les deux mêmes
désavantages. Ce qui fait qu'on se sert des fonctions inline
beaucoup plus volentairement dans un template. Et qu'évidemment,
ces deux désavantages n'apparaissent que quand la fonction sert
dans plusieurs modules. Ce qui fait qu'on se sert aussi
volentairement des fonctions inline quand la fonction est locale
à une unité de compilation.

Cela serait donc un compromis entre le "coût" de l'appel à la
fonction, et le coût de la consommation mémoire du fait de
"copier" la fonction à chaque fois qu'elle est appelée.


C'est surtout intéressant quand le compilateur peut trouver
d'autres possibilités d'optimisation à la suite de la mise en
ligne.

Est-ce bien cela ?

Si j'ai bien compris, ce qui motive votre suggestion est je
suppose l'unique utilisation des fonctions ?


Si qui la motive, sans doute, c'est qu'il croit que ta machine
est tellement lente que l'utilisateur ne peut pas supporter le
temps qu'il faut pour une dizaines d'appels de fonction, et
qu'il a profilé le même programme, et a constaté que c'est bien
l'appel de la fonction qui était le goulot d'étranglement.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34





1 2