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

1 2 3 4 5
Avatar
Gabriel Dos Reis
Marc Boyer writes:

[...]

| J'avais pris le nombre de trimestre, car il a cette amusante proprià ©té
| que pour 40 années de cotisation, il tient sur un char, et pour 42
| (qui est arrivé en France), il faut un unsigned char.

Dois-je comprendre que tu cotises pour une caisse de retraite dont le
char est signé ?

-- Gaby
Avatar
Antoine Leca
Marc Boyer écrivit :
C'est ça: on privilégie un comportement robuste aux bornes,
au détriment de la généralité.



Si tu veux dire que C n'est ni Basic ni Pascal, on va être d'accord. :-)


Là encore: on privilégie les règles claires, la portabilité, quitte
à perdre les débutants.



Re-belote


Le 06-10-2010, Antoine Leca a écrit :
Marc Boyer écrivit :
Il a l'avantage de produire le débordement sur de petites valeurs
négatives, que l'on voit vite sur des tests unitaires, alors que
le choix contraire ne l'aurait fait apparaître sur de grandes valeurs,
que pas grand monde ne teste (jusqu'au jour où la fusée explose ;-) ).



Remarque que le problème des grandes valeurs est peut-être estompé à ce
niveau, mais il reste pour l'opérateur * (et à un moindre niveau <<).



Je ne vois pas en quoi le problème diffère avec la multiplication.
int i= -3; int u= 6; int idiv= u / i; int imul= u * i;



Désolé si ce n'était pas clair: je voulais parler des soucis engendrés
par les « grandes » valeurs, la « convention inverse » si tu préfères :
si ceux [les soucis] qui viennent des non-signés sont relativement
épargnés (grâce à la norme), ce n'est pas le cas de ceux [les soucis]
qui dérivent des débordements de *, qui en C est une opération
castratrice (n bits × n bits, faudrait 2n bits mais C n'en offre que n).


J'avais pris le nombre de trimestre, car il a cette amusante propriété
que pour 40 années de cotisation, il tient sur un char, et pour 42
(qui est arrivé en France), il faut un unsigned char.



Désolé mais là je ne te suis pas.
C'est un sujet qui ne me rajeunit pas (je me souviens en particulier
d'une mission en 1987 sur ce sujet :^) ), mais même à l'époque, personne
n'essayait de faire tenir un nombre de trimestres de l'ordre de 150 dans
un entier signé sur 7+1 bits...


De ce fait, les programmeurs C apprennent vite à se
méfier des unsigned qui traînent, puis par ricochet des sizeof() et
autres size_t qui importent le même effet.



Sauf que, comme dit ailleurs, comme *alloc, str* et des soeurs prennent
des size_t en paramêtre ou valeur de retour, on est obligé d'y faire
attention.



Voui. D'où le « importe » de ma phrase. « Se méfier » et « faire
attention » ne sont pas en opposition pour moi.


Supposons que l'on stocke l'ensemble des revenus pour chaque trimestre
du salarié, dans une liste chainée ou un tableau dynamique. On va
surement vouloir stocker la taille de cet ensemble.
Dans quoi ? Dans un int ?



Parce que Brian et Dennis l'ont dit !

Oui, mais si on utilise un conteneur
fait dans une bibliothèque, pourquoi aurait-il choisi un int ?



En C, si le conteneur utilise des unsigned pour dimensionner, on va au
devant de problèmes... c'est d'ailleurs ce que je comprends de la
position de Marc E. sur le sujet (libre à lui de me corriger).

Le vrai souci à mon sens, c'est surtout pour les chaînes, et c'était
très sensible au temps du 16 bits. Pour le reste, le facteur de la
taille des objets supprime l'inconvénient de tangenter INT_MAX en
pratique. Mais pour les chaînes (et par mimétisme les objets abstraits,
blobs si vous préférez), je crois que c'est un gros souci, et que cela a
empêché le C de se doté d'un mécanisme universel de gestion des chaînes
de caractères (avec le problème de la gestion dynamique du tas)


Antoine
Avatar
Marc Boyer
Le 06-10-2010, Gabriel Dos Reis a écrit :
Marc Boyer writes:
| J'avais pris le nombre de trimestre, car il a cette amusante propriété
| que pour 40 années de cotisation, il tient sur un char, et pour 42
| (qui est arrivé en France), il faut un unsigned char.

Dois-je comprendre que tu cotises pour une caisse de retraite dont le
char est signé ?



Je ne sais pas comment est implanté le code qui calculera ma retraite,
le jour où il s'agira de la prendre.
Mais actuellement, oui, je suis dans le régime général à 42 ans.

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 06-10-2010, Gabriel Dos Reis a écrit :
| > Marc Boyer writes:
| >| J'avais pris le nombre de trimestre, car il a cette amusante propri été
| >| que pour 40 années de cotisation, il tient sur un char, et pour 42
| >| (qui est arrivé en France), il faut un unsigned char.
| >
| > Dois-je comprendre que tu cotises pour une caisse de retraite dont le
| > char est signé ?
|
| Je ne sais pas comment est implanté le code qui calculera ma retra ite,
| le jour où il s'agira de la prendre.
| Mais actuellement, oui, je suis dans le régime général à 42 ans.

le fait que `char' soit signé ou non dépend de l'implémentat ion --
c'était le point oblique :-).

-- Gaby
Avatar
Gabriel Dos Reis
Marc Boyer writes:

| Le 07-10-2010, Gabriel Dos Reis a écrit :
| > Marc Boyer writes:
| >
| >| Le 06-10-2010, Gabriel Dos Reis a écrit :
| >| > Marc Boyer writes:
| >| >| J'avais pris le nombre de trimestre, car il a cette amusante prop riété
| >| >| que pour 40 années de cotisation, il tient sur un char, et pou r 42
| >| >| (qui est arrivé en France), il faut un unsigned char.
| >| >
| >| > Dois-je comprendre que tu cotises pour une caisse de retraite dont le
| >| > char est signé ?
| >|
| >| Je ne sais pas comment est implanté le code qui calculera ma re traite,
| >| le jour où il s'agira de la prendre.
| >
| > le fait que `char' soit signé ou non dépend de l'impléme ntation --
|
| Je sais. C'était le sens de mon 'il tient' dans le sens où 'i l est
| garantit par la norme qu'il tient'.

???

| Après, si le char est non signé, ou s'il est signé et su r plus
| de 8 bits utile, ça marche aussi...

?

-- Gaby
Avatar
Marc Boyer
Le 07-10-2010, Gabriel Dos Reis a écrit :
Marc Boyer writes:

| Le 06-10-2010, Gabriel Dos Reis a écrit :
| > Marc Boyer writes:
| >| J'avais pris le nombre de trimestre, car il a cette amusante propriété
| >| que pour 40 années de cotisation, il tient sur un char, et pour 42
| >| (qui est arrivé en France), il faut un unsigned char.
| >
| > Dois-je comprendre que tu cotises pour une caisse de retraite dont le
| > char est signé ?
|
| Je ne sais pas comment est implanté le code qui calculera ma retraite,
| le jour où il s'agira de la prendre.

le fait que `char' soit signé ou non dépend de l'implémentation --



Je sais. C'était le sens de mon 'il tient' dans le sens où 'il est
garantit par la norme qu'il tient'.
Après, si le char est non signé, ou s'il est signé et sur plus
de 8 bits utile, ça marche aussi...

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
Marc Boyer
Le 06-10-2010, Antoine Leca a écrit :
Marc Boyer écrivit :
C'est ça: on privilégie un comportement robuste aux bornes,
au détriment de la généralité.



Si tu veux dire que C n'est ni Basic ni Pascal, on va être d'accord. :-)

Là encore: on privilégie les règles claires, la portabilité, quitte
à perdre les débutants.



Re-belote



OK

Le 06-10-2010, Antoine Leca a écrit :
Marc Boyer écrivit :
Il a l'avantage de produire le débordement sur de petites valeurs
négatives, que l'on voit vite sur des tests unitaires, alors que
le choix contraire ne l'aurait fait apparaître sur de grandes valeurs,
que pas grand monde ne teste (jusqu'au jour où la fusée explose ;-) ).



Remarque que le problème des grandes valeurs est peut-être estompé à ce
niveau, mais il reste pour l'opérateur * (et à un moindre niveau <<).



Je ne vois pas en quoi le problème diffère avec la multiplication.
int i= -3; int u= 6; int idiv= u / i; int imul= u * i;



Désolé si ce n'était pas clair: je voulais parler des soucis engendrés
par les « grandes » valeurs, la « convention inverse » si tu préfères :
si ceux [les soucis] qui viennent des non-signés sont relativement
épargnés (grâce à la norme), ce n'est pas le cas de ceux [les soucis]
qui dérivent des débordements de *, qui en C est une opération
castratrice (n bits × n bits, faudrait 2n bits mais C n'en offre que n).



Ca dépend ce qu'on appelle "souci". Le "souci" du débutant, c'est
que l'arithmétique du C ne soit pas celle des naturel ou des réels.
Le souci du programmeur expériementé, c'est d'avoir des comportements
prédictibles.

Supposons que l'on stocke l'ensemble des revenus pour chaque trimestre
du salarié, dans une liste chainée ou un tableau dynamique. On va
surement vouloir stocker la taille de cet ensemble.
Dans quoi ? Dans un int ?



Parce que Brian et Dennis l'ont dit !



Pourquoi pas.

Oui, mais si on utilise un conteneur
fait dans une bibliothèque, pourquoi aurait-il choisi un int ?



En C, si le conteneur utilise des unsigned pour dimensionner, on va au
devant de problèmes... c'est d'ailleurs ce que je comprends de la
position de Marc E. sur le sujet (libre à lui de me corriger).



C'est à dire que C++ a fait le choix contraire. Stepanof
s'oppose à Brian et Dennis. Bon, on peut dire que ce ne sont pas
les même langages, mais sur le petit bout qui nous intéresse,
le sous-ensemble est commun.

Le vrai souci à mon sens, c'est surtout pour les chaînes, et c'était
très sensible au temps du 16 bits. Pour le reste, le facteur de la
taille des objets supprime l'inconvénient de tangenter INT_MAX en
pratique. Mais pour les chaînes (et par mimétisme les objets abstraits,
blobs si vous préférez), je crois que c'est un gros souci, et que cela a
empêché le C de se doté d'un mécanisme universel de gestion des chaînes
de caractères (avec le problème de la gestion dynamique du tas)



Lorsque j'étais enseignant de C, je recommandais size_t, par influence
du C++, par influence des types contraints à la Ada, parce que je
faisais coder des invariants de type, et aussi afin que les étudiants
rencontrent le problème.

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
Benoit Izac
Bonjour,

le 05/10/2010 à 15:44, Marc Boyer a écrit dans le message
<i8fa3e$2fs$ :

#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("%llin", c);
return 0;
}



Et non. Tu as une opération qui implique un signé et un non signé
de même taille. Il faut donc faire une conversion, soit du signé en
non signé, soit du non signé en signé.
La norme dit que c'est le signé qui sera convertit en non signé
(donc surement 2^64 - 6 dans ton cas). Puis on divise par 5.



Pourquoi « - 6 », ce n'est pas plutôt « - 5 » ?

--
Benoit Izac
Avatar
Benoit Izac
Bonjour,

le 06/10/2010 à 16:49, Marc Boyer a écrit dans le message
<i8i2ai$8m4$ :

Remarque que le problème des grandes valeurs est peut-être estompé à ce
niveau, mais il reste pour l'opérateur * (et à un moindre niveau <<).



Je ne vois pas en quoi le problème diffère avec la multiplication.
int i= -3;
int u= 6;
int idiv= u / i;
int imul= u * i;
Dans les deux cas, on a conversion du -3 en un grand signé, et l'opération
effectuée n'est surement pas celle que le débutant attendrait.



Je pense que tu voulais écrire « unsigned u= 6; » car sinon je ne
comprends le sens de ta remarque.

--
Benoit Izac
Avatar
Marc Boyer
Le 08-10-2010, Benoit Izac a écrit :
le 06/10/2010 à 16:49, Marc Boyer a écrit dans le message
Remarque que le problème des grandes valeurs est peut-être estompé à ce
niveau, mais il reste pour l'opérateur * (et à un moindre niveau <<).



Je ne vois pas en quoi le problème diffère avec la multiplication.
int i= -3;
int u= 6;
int idiv= u / i;
int imul= u * i;
Dans les deux cas, on a conversion du -3 en un grand signé, et l'opération
effectuée n'est surement pas celle que le débutant attendrait.



Je pense que tu voulais écrire « unsigned u= 6; » car sinon je ne
comprends le sens de ta remarque.



Tout à fait. Désolé pour l'erreur.

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
1 2 3 4 5