OVH Cloud OVH Cloud

Division de nombre entiers signés par non signés

65 réponses
Avatar
Yann Renard
Bonjour à tous,

avec le code suivant, je m'attends à obtenir "-1" comme résultat.

#include <stdio.h>

int main(int argc, char** argv)
{
unsigned long long b = 5;
signed long long a = -5;
signed long long c = a / b;
printf("%lli\n", c);
return 0;
}

Or j'obtiens 3689348814741910322. La plateforme que j'utilise pour faire
ce test est Ubuntu Linux Lucid Lynx sur architecture x86_64.

# uname -a
Linux cervelet 2.6.32-25-generic #44-Ubuntu SMP Fri Sep 17 20:05:27 UTC
2010 x86_64 GNU/Linux

# gcc --version
gcc (Ubuntu 4.4.3-4ubuntu5) 4.4.3

Compilé sans optimisation. Est ce que je me trompe ? Ou est ce GCC qui
fait des bétises ?

Merci d'avance,
Yann

10 réponses

Avatar
Samuel DEVULDER
Le 12/10/2010 10:35, Marc Boyer a écrit :

Parce qu'on perd de la précision en flottant ? Surtout dans
des sommes ou des termes s'annullent entre eux.




Je parlais: "convertir le total en double avant la division" donc pas de
perte relative à la sommation.

Du reste si tu travailles sur des entiers raisonnables (50 et quelques
bits pour les double, 23 et quelques pour les float: ca laisse de la
marge), les flottants stockent et manipulent sans erreurs ces valeurs
entières.


En plus, tout ceci me paraît bien compliqué, alors que la solution



Ben non: conversion en double pour la division puis passage en int du
résultat:
(int)(((double)sum) / size)


simple, c'est de faire une conversion explicite non-signé -> signé
de la taille.



Perso j'évite les unsigned sauf pour les trucs de bas niveau. Dans ma
pratique les int sont largement suffisants pour beaucoup de chose et
l'unsigned n'apporte pas grand chose: 1 bit en plus et beaucoup de
conversions implicites qui sont sources de soucis pour quasi tout le
monde. (personne n'a en tête la logique de la norme dans ce domaine). De
plus beaucoup de langage n'ont pas d'entiers non signés et ca n'empêche
pas de faire beaucoup de choses utiles avec.

sam.
Avatar
Marc Boyer
Le 12-10-2010, Samuel DEVULDER a écrit :
Le 12/10/2010 10:35, Marc Boyer a écrit :

Parce qu'on perd de la précision en flottant ? Surtout dans
des sommes ou des termes s'annullent entre eux.



Je parlais: "convertir le total en double avant la division" donc pas de
perte relative à la sommation.



Ah. ca doit marcher aussi, mais je ne vois pas bien l'intérêt.

En plus, tout ceci me paraît bien compliqué, alors que la solution



Ben non: conversion en double pour la division puis passage en int du
résultat:
(int)(((double)sum) / size)



A comparer avec la solution
sum / (int) size

On peut inventer pleins de solutions, mais une solution plus compliquée
ne se justifie que si elle apporte quelque chose. Et la double conversion
int -> float -> int, je ne vois pas ce qu'elle apporte ici.

simple, c'est de faire une conversion explicite non-signé -> signé
de la taille.



Perso j'évite les unsigned sauf pour les trucs de bas niveau. Dans ma
pratique les int sont largement suffisants pour beaucoup de chose et
l'unsigned n'apporte pas grand chose: 1 bit en plus et beaucoup de
conversions implicites qui sont sources de soucis pour quasi tout le
monde.



Nous sommes d'accord: les non signés sont sources de problème. Mais,
à partir du moment ou les fonctions str* et *alloc les manipulent,
on ne peut pas complètement occulter. D'où le besoin d'une stratégie
d'usage.
Et puis, C++/STL a choisi des non signés pour manipuler les tailles
de ses conteneurs, ce qui les a peut-être remis sur le devant de la
scène (mais Qt semble avoir choisi int).

(personne n'a en tête la logique de la norme dans ce domaine).



C'est pas compliqué: dès qu'on voit un mélange signé / non signé,
faire attention.

De
plus beaucoup de langage n'ont pas d'entiers non signés et ca n'empêche
pas de faire beaucoup de choses utiles avec.



Oui, mais C a une vocation à l'universalité (de la machine à laver
à la station spaciale) que n'ont pas beaucoup de langage.

Marc Boyer
--
En prenant aux 10% des francais les plus riches 12% de leurs revenus,
on pourrait doubler les revenus des 10% les plus pauvres.
http://www.inegalites.fr/spip.php?article1&id_mot0
Avatar
Antoine Leca
Wykaaa écrivit :
Marc Boyer a écrit :
Le 11-10-2010, Wykaaa a écrit :
Indépendamment du plaisir purement intellectuel de discourir sur les
pièges du C, j'aimerais bien savoir dans quel cas , dans la "vraie
vie", on a réellement besoin du code présenté et pourquoi on ne
pourrait faire autrement.



typedef struct {
int *val;
size_t size;
} vector;

Ensuite, tu fais une moyenne (somme en int, divisée par la taille,
size_t).



Ton exemple est assez pertinent mais il me semble que celui-ci devrait
n'utiliser que des non signés.



Intéressant. Personnellement je pense qu'il faut plutôt utiliser int
pour size ; ce qui impose de se poser _au moment de la conception_ la
question de savoir si int est suffisamment « large » (et là je rejoins
ta position sur le fait que cela montre surtout un problème de conception).

Par ailleurs, le fait que les valeurs de Marc soient des int est ÀMHA
immatériel : ce pourrait être des float ou des double ou des complex ou
des char, et cela ne changera rien ou presque. Seul « petit » souci pour
faire la moyenne (et encore plus pour calculer une variance, ce qui sera
probablement le cas de Yann), avec des int tu peux facilement avoir des
débordements de la somme, c'est moins courant avec des flottants. Et je
retiens ici la proposition de Samuel de convertir les int en double (ou
float) au moment de calculer la somme.


Antoine
Avatar
Wykaaa
Antoine Leca a écrit :
Wykaaa écrivit :
Marc Boyer a écrit :
Le 11-10-2010, Wykaaa a écrit :
Indépendamment du plaisir purement intellectuel de discourir sur les
pièges du C, j'aimerais bien savoir dans quel cas , dans la "vraie
vie", on a réellement besoin du code présenté et pourquoi on ne
pourrait faire autrement.


typedef struct {
int *val;
size_t size;
} vector;

Ensuite, tu fais une moyenne (somme en int, divisée par la taille,
size_t).


Ton exemple est assez pertinent mais il me semble que celui-ci devrait
n'utiliser que des non signés.



Intéressant. Personnellement je pense qu'il faut plutôt utiliser int
pour size ; ce qui impose de se poser _au moment de la conception_ la
question de savoir si int est suffisamment « large » (et là je rejoins
ta position sur le fait que cela montre surtout un problème de conception).

Par ailleurs, le fait que les valeurs de Marc soient des int est ÀMHA
immatériel : ce pourrait être des float ou des double ou des complex ou
des char, et cela ne changera rien ou presque. Seul « petit » souci pour
faire la moyenne (et encore plus pour calculer une variance, ce qui sera
probablement le cas de Yann), avec des int tu peux facilement avoir des
débordements de la somme, c'est moins courant avec des flottants. Et je
retiens ici la proposition de Samuel de convertir les int en double (ou
float) au moment de calculer la somme.


Antoine



Je pense effectivement que c'est le plus raisonnable finalement.
Avatar
Gabriel Dos Reis
Marc Boyer writes:

[...]

| >> simple, c'est de faire une conversion explicite non-signé -> sig né
| >> de la taille.
| >
| > Perso j'évite les unsigned sauf pour les trucs de bas niveau. Dans ma
| > pratique les int sont largement suffisants pour beaucoup de chose et
| > l'unsigned n'apporte pas grand chose: 1 bit en plus et beaucoup de
| > conversions implicites qui sont sources de soucis pour quasi tout le
| > monde.
|
| Nous sommes d'accord: les non signés sont sources de problème . Mais,
| à partir du moment ou les fonctions str* et *alloc les manipulent,
| on ne peut pas complètement occulter. D'où le besoin d'une stra tégie
| d'usage.
| Et puis, C++/STL a choisi des non signés pour manipuler les tailles
| de ses conteneurs, ce qui les a peut-être remis sur le devant de la
| scène (mais Qt semble avoir choisi int).

devant la scène des erreurs ?
(je choix des unsigned dans la STL est beacuoup plus compliqué que
le simple constat le suggèrerait.)
Avatar
Benoit Izac
Bonjour,

le 13/10/2010 à 10:03, Marc Boyer a écrit dans le message
<i93p3q$qvp$ :

Ben non: conversion en double pour la division puis passage en int du
résultat:
(int)(((double)sum) / size)



A comparer avec la solution
sum / (int) size



Il me semble (je ne suis pas un crack là dessus) que ce n'est pas
exactement la même chose car le résultat est faut si (size > INT_MAX),
alors qu'au dessus c'est si (sum/size > INT_MAX).

--
Benoit Izac
Avatar
Marc Boyer
Le 13-10-2010, Gabriel Dos Reis a écrit :
Marc Boyer writes:
| Nous sommes d'accord: les non signés sont sources de problème. Mais,
| à partir du moment ou les fonctions str* et *alloc les manipulent,
| on ne peut pas complètement occulter. D'où le besoin d'une stratégie
| d'usage.
| Et puis, C++/STL a choisi des non signés pour manipuler les tailles
| de ses conteneurs, ce qui les a peut-être remis sur le devant de la
| scène (mais Qt semble avoir choisi int).

devant la scène des erreurs ?



Oui. Je n'ai jamais vu quelqu'un clamer sur un forum ou dans
une discussion "le choix des non signés, ça m'a sauvé mon projet".
En général, quand ça se passe bien, on ne dit rien.
"La forêt qui pousse fait moins de bruit que l'arbre qui tombe"
(citation de mémoire).

(je choix des unsigned dans la STL est beacuoup plus compliqué que
le simple constat le suggèrerait.)



Je suis preneur de tout pointeur, toute information, sur ce choix.

Marc Boyer
--
En prenant aux 10% des francais les plus riches 12% de leurs revenus,
on pourrait doubler les revenus des 10% les plus pauvres.
http://www.inegalites.fr/spip.php?article1&id_mot0
Avatar
Gabriel Dos Reis
Marc Boyer writes:

| Le 13-10-2010, Gabriel Dos Reis a écrit :
| > Marc Boyer writes:
| >| Nous sommes d'accord: les non signés sont sources de problà ¨me. Mais,
| >| à partir du moment ou les fonctions str* et *alloc les manipulent,
| >| on ne peut pas complètement occulter. D'où le besoin d'une s tratégie
| >| d'usage.
| >| Et puis, C++/STL a choisi des non signés pour manipuler les tai lles
| >| de ses conteneurs, ce qui les a peut-être remis sur le devant de la
| >| scène (mais Qt semble avoir choisi int).
| >
| > devant la scène des erreurs ?
|
| Oui.

Dans ce cas, tu enfonces une porte ouverte -- voir les écrits de BS
à ce sujet.

[...]

| > (je choix des unsigned dans la STL est beacuoup plus compliqué que
| > le simple constat le suggèrerait.)
|
| Je suis preneur de tout pointeur, toute information, sur ce choix.

Pointeurs vers des discussions orales ou internes du comité C++ ?

Par contre, tu peux lire TC++PL3 pour voir ce qu'en pense l'auteur.

-- Gaby
Avatar
Marc Boyer
Le 17-10-2010, Gabriel Dos Reis a écrit :
Marc Boyer writes:
| Le 13-10-2010, Gabriel Dos Reis a écrit :
| > Marc Boyer writes:
| >| Nous sommes d'accord: les non signés sont sources de problème. Mais,
| >| à partir du moment ou les fonctions str* et *alloc les manipulent,
| >| on ne peut pas complètement occulter. D'où le besoin d'une stratégie
| >| d'usage.
| >| Et puis, C++/STL a choisi des non signés pour manipuler les tailles
| >| de ses conteneurs, ce qui les a peut-être remis sur le devant de la
| >| scène (mais Qt semble avoir choisi int).
| >
| > devant la scène des erreurs ?
|
| Oui.

Dans ce cas, tu enfonces une porte ouverte -- voir les écrits de BS
à ce sujet.



Lesquels ?

| > (je choix des unsigned dans la STL est beacuoup plus compliqué que
| > le simple constat le suggèrerait.)
|
| Je suis preneur de tout pointeur, toute information, sur ce choix.

Pointeurs vers des discussions orales ou internes du comité C++ ?



S'il y en a, bien sûr.

Par contre, tu peux lire TC++PL3 pour voir ce qu'en pense l'auteur.



Je ne trouve pas grand chose (mais je cherche peut-être mal).
16.3.4 dit juste des choses genre "ça permet une plus grande plage de
valeur, mais ça peut provoquer des surprises".

Marc Boyer
--
En prenant aux 10% des francais les plus riches 12% de leurs revenus,
on pourrait doubler les revenus des 10% les plus pauvres.
http://www.inegalites.fr/spip.php?article1&id_mot0
Avatar
Gabriel Dos Reis
Marc Boyer writes:

| Le 17-10-2010, Gabriel Dos Reis a écrit :
| > Marc Boyer writes:
| >| Le 13-10-2010, Gabriel Dos Reis a écrit :
| >| > Marc Boyer writes:
| >| >| Nous sommes d'accord: les non signés sont sources de probl ème. Mais,
| >| >| à partir du moment ou les fonctions str* et *alloc les manipul ent,
| >| >| on ne peut pas complètement occulter. D'où le besoin d'un e stratégie
| >| >| d'usage.
| >| >| Et puis, C++/STL a choisi des non signés pour manipuler les tailles
| >| >| de ses conteneurs, ce qui les a peut-être remis sur le devant de la
| >| >| scène (mais Qt semble avoir choisi int).
| >| >
| >| > devant la scène des erreurs ?
| >|
| >| Oui.
| >
| > Dans ce cas, tu enfonces une porte ouverte -- voir les écrits de BS
| > à ce sujet.
|
| Lesquels ?

celles que tu viens d'enfoncer :-)

| >| > (je choix des unsigned dans la STL est beacuoup plus compliqué que
| >| > le simple constat le suggèrerait.)
| >|
| >| Je suis preneur de tout pointeur, toute information, sur ce choix.
| >
| > Pointeurs vers des discussions orales ou internes du comité C++ ?
|
| S'il y en a, bien sûr.
|
| > Par contre, tu peux lire TC++PL3 pour voir ce qu'en pense l'auteur.
|
| Je ne trouve pas grand chose (mais je cherche peut-être mal).
| 16.3.4 dit juste des choses genre "ça permet une plus grande plage d e
| valeur, mais ça peut provoquer des surprises".

quelle édition, quelle printing ?

-- Gaby