Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

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
Wykaaa
Yann Renard a écrit :
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("%llin", 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



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.
Pour ma part, quand j'utilise un langage (n'importe lequel), je ne
mélange jamais des types différents dans une même expression, je n'ai
jamais eu le besoin de le faire car c'est un problème qui relève de la
conception.
Si on est obligé de caster et de convertir à tout va dans le code c'est
que la conception est foireuse, tout simplement.

Conclusion :
Par plaisir purement intellectuel, on peut discuter du code présenté
mais j'affirme que celui-ci est inutile car il n'y a pas de cas, dans la
réalité, où on serait forcé d'écrire ce code et rien d'autre...

Cependant, vous dites qu'il s'agit d'un test. C'est un test qui a quel
objectif ? Si c'est un test pour "voir" ce que ça fait sur votre
plateforme, il est inutile puisque dans une vraie application, on ne
rencontrera jamais le cas sauf à mal coder ou mal concevoir. C'est donc
de l'énergie dépensée pour rien.

Ce test n'est nécessaire que pour tester un compilateur (c'était mon
activité principale de faire des compilateurs, dont un compilateur C)
qui aurait été développé pour cette plateforme, mais je constate que ce
n'est pas le cas puisqu'il s'agit du gcc.

PS : désolé de "débouler" dans la discussion comme un chien dans un jeu
de quilles mais je rentre tout juste de l'hôpital où j'ai subi une
opération assez importante.
Avatar
Marc Boyer
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).

Toute la question est: est-ce qu'on code les cardinaux, les tailles,
sur des int ou des non signés ? Et comment on fait avec str* et
malloc, calloc, qui prennent des non signés ?

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
Wykaaa
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).

Toute la question est: est-ce qu'on code les cardinaux, les tailles,
sur des int ou des non signés ? Et comment on fait avec str* et
malloc, calloc, qui prennent des non signés ?

Marc Boyer



Ton exemple est assez pertinent mais il me semble que celui-ci devrait
n'utiliser que des non signés.
Avatar
Marc Boyer
Le 11-10-2010, Wykaaa a écrit :
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.



Ben non, si on a des données potentiellement négatives (des températures
par exemple), il faut stocker des signés.

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
Wykaaa
Marc Boyer a écrit :
Le 11-10-2010, Wykaaa a écrit :
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.



Ben non, si on a des données potentiellement négatives (des températures
par exemple), il faut stocker des signés.

Marc Boyer



Il suffit d'effectuer une translation par rapport à la plus petite
valeur. Et ceci est valable pour autre chose que des températures. Quand
on "normalise" des valeurs, la plupart du temps on effectue des
homothéties/translations (par exemple en assurance qualité logicielle).
Avatar
Yann Renard
On 10/11/2010 05:02 PM, Wykaaa wrote:
Yann Renard a écrit :
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("%llin", 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



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.
Pour ma part, quand j'utilise un langage (n'importe lequel), je ne
mélange jamais des types différents dans une même expression, je n'ai
jamais eu le besoin de le faire car c'est un problème qui relève de la
conception.
Si on est obligé de caster et de convertir à tout va dans le code c'est
que la conception est foireuse, tout simplement.

Conclusion :
Par plaisir purement intellectuel, on peut discuter du code présenté
mais j'affirme que celui-ci est inutile car il n'y a pas de cas, dans la
réalité, où on serait forcé d'écrire ce code et rien d'autre...

Cependant, vous dites qu'il s'agit d'un test. C'est un test qui a quel
objectif ? Si c'est un test pour "voir" ce que ça fait sur votre
plateforme, il est inutile puisque dans une vraie application, on ne
rencontrera jamais le cas sauf à mal coder ou mal concevoir. C'est donc
de l'énergie dépensée pour rien.

Ce test n'est nécessaire que pour tester un compilateur (c'était mon
activité principale de faire des compilateurs, dont un compilateur C)
qui aurait été développé pour cette plateforme, mais je constate que ce
n'est pas le cas puisqu'il s'agit du gcc.

PS : désolé de "débouler" dans la discussion comme un chien dans un jeu
de quilles mais je rentre tout juste de l'hôpital où j'ai subi une
opération assez importante.



Bonjour,

le cas dans lequel j'ai eu besoin de faire cela dans la vraie vie est
simple : je calcule la moyenne d'une série de valeurs entières signées,
stockées dans une std::vector (c'est du C++ mais je te présente mon cas
précis ;) ). Je fais donc simplement la somme de tous les éléments
contenus dans le vecteur et je divise par le .size() qui est
malheureusement non signé.

Voila.
Yann
Avatar
Yann Renard
On 10/12/2010 09:14 AM, Marc Boyer wrote:
Le 11-10-2010, Wykaaa a écrit :
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.



Ben non, si on a des données potentiellement négatives (des températures
par exemple), il faut stocker des signés.

Marc Boyer



Mince, c'est marrant, le cas que tu expose est quasiment le miens ;)
Je stocke des estimation de dérive de mesure. C'est donc censé être
proche de zéro en moyenne, et c'est donc un coup négatif, un coup positif.

Yann
Avatar
Samuel DEVULDER
Le 12/10/2010 09:56, Yann Renard a écrit :

le cas dans lequel j'ai eu besoin de faire cela dans la vraie vie est
simple : je calcule la moyenne d'une série de valeurs entières signées,
stockées dans une std::vector (c'est du C++ mais je te présente mon cas
précis ;) ). Je fais donc simplement la somme de tous les éléments
contenus dans le vecteur et je divise par le .size() qui est
malheureusement non signé.



Question bête: la moyenne n'étant de toute façon pas entière, pourquoi
ne pas convertir le total en double avant la division? Le résultat
serait un nombre flottant qui a beaucoup plus de sens pour la moyenne
qu'un nombre entier. (Quelle est la moyenne d'une mesure 0 ou 1 en entier?).

sam.
Avatar
Marc Boyer
Le 12-10-2010, Samuel DEVULDER a écrit :
Le 12/10/2010 09:56, Yann Renard a écrit :

le cas dans lequel j'ai eu besoin de faire cela dans la vraie vie est
simple : je calcule la moyenne d'une série de valeurs entières signées,
stockées dans une std::vector (c'est du C++ mais je te présente mon cas
précis ;) ). Je fais donc simplement la somme de tous les éléments
contenus dans le vecteur et je divise par le .size() qui est
malheureusement non signé.



Question bête: la moyenne n'étant de toute façon pas entière, pourquoi
ne pas convertir le total en double avant la division? Le résultat
serait un nombre flottant qui a beaucoup plus de sens pour la moyenne
qu'un nombre entier. (Quelle est la moyenne d'une mesure 0 ou 1 en entier?).



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

En plus, tout ceci me paraît bien compliqué, alors que la solution
simple, c'est de faire une conversion explicite non-signé -> signé
de la taille.

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 12-10-2010, Wykaaa a écrit :
Marc Boyer a écrit :
Le 11-10-2010, Wykaaa a écrit :
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.



Ben non, si on a des données potentiellement négatives (des températures
par exemple), il faut stocker des signés.




Il suffit d'effectuer une translation par rapport à la plus petite
valeur. Et ceci est valable pour autre chose que des températures. Quand
on "normalise" des valeurs, la plupart du temps on effectue des
homothéties/translations (par exemple en assurance qualité logicielle).



Dans le cas qui nous interesse, il suffit aussi de convertir le non signé
en signé dans la division.
Parce que la propotion de normalisation va impliquer de nombreuses
conversions signés/non signés sur les E/S...

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