OVH Cloud OVH Cloud

[Calcul] Problème étrange

69 réponses
Avatar
Rincevent
Bonjour à tous,
g un gros problème dans mon programme C++.
Voilà g 3 entier a,b et c
Je souhaite calculer la partie entière de (a/b)*c
J'utilise pour cela la fonction floor() de <cmath>
Or deux problèmes se présentent :

1) Le compilateur renvoie 0 lorsque je lui demande de calculer (a/b)*c (et
ce, alors que les valeurs de a,b,c ne devraient pas donner un tel résultat)

2) Le compilateur m'insulte lorsque j'essaie d'appliquer la fonction floor()
à (a/b)*c (motif : l'argument n'est pas un double...)


- Je suppose qu'il doit exister une fonction pour convertir des rapports
d'entier en double, non ?
- Et inversement pour passer d'un double codant un entier --> en type int ?
- floor() attend un double comme argument... Soit mais quel est le type duy
résultat ? un double ? un int ?
- comment résoudre cet épineux problème de façon élégante ??? ;-)

Quelqu'un peut-t-il m'aider ?
Merci d'avance !

Rincevent

10 réponses

1 2 3 4 5
Avatar
Samuel Krempp
le Monday 24 May 2004 10:26, écrivit :

Bonjour à tous,
g un gros problème dans mon programme C++.
Voilà g 3 entier a,b et c
Je souhaite calculer la partie entière de (a/b)*c
J'utilise pour cela la fonction floor() de <cmath>
Or deux problèmes se présentent :

1) Le compilateur renvoie 0 lorsque je lui demande de calculer (a/b)*c (et
ce, alors que les valeurs de a,b,c ne devraient pas donner un tel
résultat)


la division de nombres entiers correspond à la division euclidienne (en ne
prenant que le quotient, pas le reste)
donc 3/5 == 0.
C'est comme ça dans bcp de langages, il faut le savoir.

2) Le compilateur m'insulte lorsque j'essaie d'appliquer la fonction
floor() à (a/b)*c (motif : l'argument n'est pas un double...)


je crois que c'est pas ça que te dit le compilo (ou alors il est bizarre)
Tu dois sûrement faire un truc comme :
int n = floor(a/b*c);
et c'est dans le '=' qu'il y a problème : un double à droite, un int à
gauche.

solution :
int n = static_cast<int>(floor((a*1.0/b) *c) );

- Je suppose qu'il doit exister une fonction pour convertir des rapports
d'entier en double, non ?


un "rapport d'entier" est un entier. et ça se convertit donc automatiquement
en double si besoin.

- Et inversement pour passer d'un double codant un entier --> en type int
? - floor() attend un double comme argument... Soit mais quel est le type
duy résultat ? un double ? un int ?


tu n'as aucune doc ?
il faudrait au moins que tu aies des références des fctions de la librairie
C et C++ si tu veux arriver à qque chose ...
http://www.dinkumware.com/manuals/reader.aspx?lib=cpl&h=math.html#floor

--
Sam

Avatar
Django Janny
Bonjour,

Il faut, je pense, que tu convertisse tes entiers en double au moment de ton
opération :
((double) a / (double) b) * (double) c
a partir de la ton résultat sera != de 0 et tu pour utiliser floor
évidemment dans le cas d'un calcul avec plusieurs utilisation des versions
double de a,b et c je te conseille vivement d'utiliser de nouvelles
variables (de type double...)

A+
Django

"Rincevent" a écrit dans le message de
news:c8sbjv$cug$
Bonjour à tous,
g un gros problème dans mon programme C++.
Voilà g 3 entier a,b et c
Je souhaite calculer la partie entière de (a/b)*c
J'utilise pour cela la fonction floor() de <cmath>
Or deux problèmes se présentent :

1) Le compilateur renvoie 0 lorsque je lui demande de calculer (a/b)*c (et
ce, alors que les valeurs de a,b,c ne devraient pas donner un tel
résultat)


2) Le compilateur m'insulte lorsque j'essaie d'appliquer la fonction
floor()

à (a/b)*c (motif : l'argument n'est pas un double...)


- Je suppose qu'il doit exister une fonction pour convertir des rapports
d'entier en double, non ?
- Et inversement pour passer d'un double codant un entier --> en type int
?

- floor() attend un double comme argument... Soit mais quel est le type
duy

résultat ? un double ? un int ?
- comment résoudre cet épineux problème de façon élégante ??? ;-)

Quelqu'un peut-t-il m'aider ?
Merci d'avance !

Rincevent









Avatar
Pierre Maurette
"Rincevent" typa:

Bonjour à tous,
g un gros problème dans mon programme C++.
Voilà g 3 entier a,b et c
Je souhaite calculer la partie entière de (a/b)*c
J'utilise pour cela la fonction floor() de <cmath>
Or deux problèmes se présentent :

1) Le compilateur renvoie 0 lorsque je lui demande de calculer (a/b)*c (et
ce, alors que les valeurs de a,b,c ne devraient pas donner un tel résultat)
Comment faites-vous pour mener ce calcul de tête ou avec papier-crayon

? Commencez-vous par diviser ? Avez vous besoin de flottants pour
traiter le problème ?
Si vous faites :
int resultat = (a*c)/b;
vous traitez exactement le problème tel qu'il est posé, c'est à dire
comme un problème d'entiers. Je vous laisse, par rapport à ce que vous
souhaitez, juger de l'oportunité d'un ajustement par floor().
Personnellement, je ne l'utiliserais pas, puisque c'est une fonction
double. Mais bon, personnellement, je trouve regrettable l'utilisation
de / pour la division entière, j'aime bien le couple div mod du
Pascal.
Il est aussi rapide et plus naturel de tester le signe (et
malheureusement je pense qu'il faudra également tester le résultat
exact, le cas ou a*c est divisible par b) pour ajuster le résultat.
Mais le résultat direct correspond à l'idée que je me fais d'une
partie entière.

2) Le compilateur m'insulte lorsque j'essaie d'appliquer la fonction floor()
à (a/b)*c (motif : l'argument n'est pas un double...)
En C++, floor() est surchargée pour admettre plusieurs prototypes dont

float floor(float) et sans doute double floor(double). Je ne sais pas
ce qui est dans la norme et ce qui est dans les implémentations, mais
peu importe.
L'instruction:
a = floor((a*c)/b); //int a, b, c;
ne lui permet peut-être pas de résoudre la surcharge.
a = floor(((double)a*c)/b);
résoud le problème (inutile de caster toutes les variables). Utilisez
static_cast<double> si vous préférez.

- Je suppose qu'il doit exister une fonction pour convertir des rapports
d'entier en double, non ?
- Et inversement pour passer d'un double codant un entier --> en type int ?
- floor() attend un double comme argument... Soit mais quel est le type duy
résultat ? un double ? un int ?
- comment résoudre cet épineux problème de façon élégante ??? ;-)
En téléchargeant un peu de documentation ?


Pierre

Avatar
Jean-Noël Mégoz
----- Original Message -----
From: "Rincevent"
Newsgroups: fr.comp.lang.c++
Sent: Monday, May 24, 2004 10:26 AM
Subject: [Calcul] Problème étrange


Bonjour à tous,
g un gros problème dans mon programme C++.
Voilà g 3 entier a,b et c
Je souhaite calculer la partie entière de (a/b)*c
J'utilise pour cela la fonction floor() de <cmath>
Or deux problèmes se présentent :

1) Le compilateur renvoie 0 lorsque je lui demande de calculer (a/b)*c (et
ce, alors que les valeurs de a,b,c ne devraient pas donner un tel
résultat)




Comme déjà dit par qq'un, si a/b = 0, alors forcément (a/b)*c sera nul
aussi.
D'où ce petit conseil que je me suis toujours félicité de suivre : autant
que possible, faire les multiplications avant les divisions : calcule
(a*c)/b, plutôt.
Dans le cas de réels, cette façon de faire donne en plus résultat plus
précis.

2) Le compilateur m'insulte lorsque j'essaie d'appliquer la fonction
floor()

à (a/b)*c (motif : l'argument n'est pas un double...)



Il suffit de caster l'un des entier (déjà dit aussi) : floor((a*c)/(double)
b).
Note que caster un seul entier suffit pour que toute l'opération donne un
nombre flottant.

Avatar
Rincevent
"Rincevent" a écrit dans le message de news:
c8sbjv$cug$
Bonjour à tous,
g un gros problème dans mon programme C++.
Voilà g 3 entier a,b et c
Je souhaite calculer la partie entière de (a/b)*c


Pour info, mon programme doit effectuer (en simplifiant) ces n processus :

1) on fixe N le nb de niveaux de gris differents d'une image (N%6)

int N = 256;

2) On obtient, par un procédé qui n'est pas décrit ici, une image M
representée par une matrice dont les éléments sont des entiers compris entre
0 et 255 (donc 256 valeurs en tout)

3) Après traitement, je suis en mesure de déterminer les particules de
l'image, càd les ensembles de points connexes par arcs.
Je souhaite "colorier" ces particules en fonctions de leurs tailles.

4) Pour cela, on demande à l'utilisateur combien de classe de particules il
souhaite (classe : au sens mathématique). Ce nombre est stocké dans P.
P est également un entier !

5) Pour la particules appartenant à la k-ème classe, sa couleur est donc
(canoniquement) donnée par (k/P)*N
(k/P)*N n'est pas forcément un entier, on prends donc la partie entière pour
être sur...

Voilà, ça c'est la description théorique de ce que je dois faire.
C'est donc le codage C++ de la partie 5) qui me pose problème...

Je vais tester de ce pas vos différentes solutions.
Merci pour vos contributions !

Rincevent

Avatar
Pierre Maurette
"Rincevent" typa:


"Rincevent" a écrit dans le message de news:
[...]

1) on fixe N le nb de niveaux de gris differents d'une image (N%6)

int N = 256;

2) On obtient, par un procédé qui n'est pas décrit ici, une image M
representée par une matrice dont les éléments sont des entiers compris entre
0 et 255 (donc 256 valeurs en tout)

3) Après traitement, je suis en mesure de déterminer les particules de
l'image, càd les ensembles de points connexes par arcs.
Je souhaite "colorier" ces particules en fonctions de leurs tailles.

4) Pour cela, on demande à l'utilisateur combien de classe de particules il
souhaite (classe : au sens mathématique). Ce nombre est stocké dans P.
P est également un entier !

5) Pour la particules appartenant à la k-ème classe, sa couleur est donc
(canoniquement) donnée par (k/P)*N
(k/P)*N n'est pas forcément un entier, on prends donc la partie entière pour
être sur...
Tous vos entierzs sont positifs, déclarez-les donc unsigned. N est une

constante, apparemment, ainsi que P pendant le calcul. Votre problème
esr ainsi simplifié :
int resultat = (k*N)/P; //c'est tout
ou même
int resultat = (k<<8)/P;
que devrait vous générer le compilateur si vous avez déclaré N const.

Pierre

Avatar
drkm
Pierre Maurette writes:

"Rincevent" typa:

Bonjour à tous,
g un gros problème dans mon programme C++.
Voilà g 3 entier a,b et c
Je souhaite calculer la partie entière de (a/b)*c
J'utilise pour cela la fonction floor() de <cmath>
Or deux problèmes se présentent :

1) Le compilateur renvoie 0 lorsque je lui demande de calculer (a/b)*c (et
ce, alors que les valeurs de a,b,c ne devraient pas donner un tel résultat)


Comment faites-vous pour mener ce calcul de tête ou avec papier-crayon
? Commencez-vous par diviser ? Avez vous besoin de flottants pour
traiter le problème ?
Si vous faites :
int resultat = (a*c)/b;
vous traitez exactement le problème tel qu'il est posé, c'est à dire
comme un problème d'entiers.


Et qu'advient-il lorsque

a == std::numeric_limits< int >::max() ;

? En fait, je suis en train de me demander s'il n'y a pas conversion
du résultat de « a * c » en un long int dans ce cas, mais je ne pense
pas ; et ce ne ferait que déplacer le problème. Tandis que

int result = static_cast< int >(
static_cast< double >( a ) / b * c
) ;

gère correctement le problème.

Pour ce qui est de la promotion en long int, je n'ai trouvé que
4.5/1. Je ne suis pas certain qu'il s'agit du bon paragraphe, mais si
c'est le cas, cette promotion en long int n'existe pas (ce que je
pense).

--drkm


Avatar
kanze
Samuel Krempp wrote in message
news:<40b1cbb2$0$12736$...
le Monday 24 May 2004 10:26, écrivit :


[...]
2) Le compilateur m'insulte lorsque j'essaie d'appliquer la fonction
floor() à (a/b)*c (motif : l'argument n'est pas un double...)


je crois que c'est pas ça que te dit le compilo (ou alors il est
bizarre) Tu dois sûrement faire un truc comme :

int n = floor(a/b*c);

et c'est dans le '=' qu'il y a problème : un double à droite, un int à
gauche.

solution :
int n = static_cast<int>(floor((a*1.0/b) *c) );


La conversion double en int est implicite en C++. Si le compilateur émet
plus d'un avertissement lors de l'affectation, ça m'étonnerait.

Je crois que le problème c'est plutôt qu'en C++, floor est surchargé,
pour float, double et long double. Et quand on lui passe un int, c'est
ambigu, parce que le compilateur ne sait pas laquelle des trois
fonctions choisir.

En passant, ces surcharges cassent du code existant pré-norme,
puisqu'avant la norme, quelque chose comme exp(3) était légal. L'intérêt
du surcharge est évident (à mon avis, en tout cas), mais ils auraient
peut-être dû ajouter des surcharges sur int, etc., pour ce genre de cas.

- Je suppose qu'il doit exister une fonction pour convertir des
rapports d'entier en double, non ?


un "rapport d'entier" est un entier. et ça se convertit donc
automatiquement en double si besoin.

- Et inversement pour passer d'un double codant un entier --> en
type int ? - floor() attend un double comme argument... Soit mais
quel est le type duy résultat ? un double ? un int ?


tu n'as aucune doc ?
il faudrait au moins que tu aies des références des fctions de la
librairie C et C++ si tu veux arriver à qque chose ...
http://www.dinkumware.com/manuals/reader.aspx?lib=cpl&h=math.html#floor


Au délà de la doc -- les fonctions mathématiques qui prenent des double
renvoie des double, celles qui prenent des float renvoient des float,
etc. C'est comme ça dans tous les langages que je connais.

--
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
kanze
"Rincevent" wrote in message
news:<c8t6si$aqg$...
"Rincevent" a écrit dans le message de news:
c8sbjv$cug$

g un gros problème dans mon programme C++.
Voilà g 3 entier a,b et c
Je souhaite calculer la partie entière de (a/b)*c


Pour info, mon programme doit effectuer (en simplifiant) ces n processus :

1) on fixe N le nb de niveaux de gris differents d'une image (N%6)

int N = 256;

2) On obtient, par un procédé qui n'est pas décrit ici, une image M
representée par une matrice dont les éléments sont des entiers compris entre
0 et 255 (donc 256 valeurs en tout)

3) Après traitement, je suis en mesure de déterminer les particules de
l'image, càd les ensembles de points connexes par arcs.
Je souhaite "colorier" ces particules en fonctions de leurs tailles.

4) Pour cela, on demande à l'utilisateur combien de classe de particules il
souhaite (classe : au sens mathématique). Ce nombre est stocké dans P.
P est également un entier !

5) Pour la particules appartenant à la k-ème classe, sa couleur est
donc (canoniquement) donnée par (k/P)*N (k/P)*N n'est pas forcément un
entier, on prends donc la partie entière pour être sur...


Si 0 <= k < 256 et 0 <= N <= 256 et P > 0, alors (k*N)/P donne
exactement le résultat que tu veux, sans risque de débordement ni
d'autres problèmes. Pour des valeurs aussi petites, laisse tomber les
flottants et leurs imprécisions.

--
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
Samuel Krempp
le Tuesday 25 May 2004 08:59, écrivit :

int n = floor(a/b*c);

et c'est dans le '=' qu'il y a problème : un double à droite, un int à
gauche.

solution :
int n = static_cast<int>(floor((a*1.0/b) *c) );


La conversion double en int est implicite en C++. Si le compilateur émet
plus d'un avertissement lors de l'affectation, ça m'étonnerait.


oui, le static_cast n'est là que pour éviter un avertissement.

Je crois que le problème c'est plutôt qu'en C++, floor est surchargé,
pour float, double et long double. Et quand on lui passe un int, c'est
ambigu, parce que le compilateur ne sait pas laquelle des trois
fonctions choisir.


ah oui j'avais pas pensé à cette ambiguité. je pensais que l'OP disait juste
qu'il avait un avertissement ("insulte").
j'imaginais mal le cas de l'appel de floor pour un int, qui n'est pas très
naturel 8-/

d'ailleurs comme dit dans un autre msg, la meileure solution ici est de
rester en int tout du long, mais en faisant la division euclidienne comme
il faut :
int n = (a*b) / c;

En passant, ces surcharges cassent du code existant pré-norme,
puisqu'avant la norme, quelque chose comme exp(3) était légal. L'intérêt
du surcharge est évident (à mon avis, en tout cas), mais ils auraient
peut-être dû ajouter des surcharges sur int, etc., pour ce genre de cas.


enfin, pour floor cette surcharge n'est pas un problème, vu que c'est assez
inutile de passer un nbre entier à la fonction.
Sinon la norme n'a pas du juger utile d'ajouter une surcharge sur int qui
n'apporterait rien d'autre que la compatibilité avec le code pré-norme.

--
Sam


1 2 3 4 5