C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Range des entiers signés

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (French)
View previous topic :: View next topic  
Author Message
Sylvain Togni
Guest





PostPosted: Thu Jul 27, 2006 9:11 am    Post subject: Range des entiers signés Reply with quote



Bonjour,

Les non-signés, la norme garanti [0, 2^n - 1]. Qu'en est-il des signés,
a-t-on [-2^(n - 1), 2^(n - 1) - 1] de garanti ?

--
Sylvain Togni
Back to top
kanze
Guest





PostPosted: Thu Jul 27, 2006 2:38 pm    Post subject: Re: Range des entiers signés Reply with quote



Sylvain Togni wrote:

Quote:
Les non-signés, la norme garanti [0, 2^n - 1].

Pas si tu insistes que n soit le nombre de bits. Il peut y avoir
des bits de padding, et autant que je sache, une implémentation
sur un hardware qui ne supporte pas de non-signer (les anciens
Unisys séries A ?) peut le simuler en masquant le bit de signe.

Quote:
Qu'en est-il des signés,
a-t-on [-2^(n - 1), 2^(n - 1) - 1] de garanti ?

Non. On a même des implémentations actuelles où ce n'est pas le
cas. Comment en ferais-tu si le hardware est complément à 1 (le
cas des Unisys 2200 actuels). Ou magnitude signée (le cas des
anciens Unisys séries A).

Aussi, la norme permet à ce que certaines valeurs
« trappent ». La norme C est beaucoup plus précise à cet
égard, et dit explicitement que si la représentation est
complément à 2 ou magnitude signée, une représentation avec le
bit de signe à 1 et tous les autres bits à zéro peut trapper.

Dans la pratique, évidemment, au moins de rencontrer un Unisys
2200, ou de se rétrouver sur des architectures fortes anciennes
(mais alors, il n'y a probablement pas de compilateur C++), les
entiers signés sont complément à 2, et tu auras l'intervale
auquel tu t'attends.

--
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
Back to top
Sylvain Togni
Guest





PostPosted: Thu Jul 27, 2006 3:52 pm    Post subject: Re: Range des entiers signés Reply with quote



kanze a écrit :

Quote:
Les non-signés, la norme garanti [0, 2^n - 1].

Pas si tu insistes que n soit le nombre de bits. Il peut y avoir
des bits de padding, et autant que je sache, une implémentation
sur un hardware qui ne supporte pas de non-signer (les anciens
Unisys séries A ?) peut le simuler en masquant le bit de signe.

Donc 2^(sizeof(unsigned)*CHAR_BIT) - 1 peut être supérieur à
UINT_MAX. Mais quand la norme spécifie que unsigned int
fait au moins 16 bits, parle-t-elle de sizeof ou de UINT_MAX ?

Quote:
Qu'en est-il des signés,
a-t-on [-2^(n - 1), 2^(n - 1) - 1] de garanti ?

Non. On a même des implémentations actuelles où ce n'est pas le
cas. Comment en ferais-tu si le hardware est complément à 1 (le
cas des Unisys 2200 actuels). Ou magnitude signée (le cas des
anciens Unisys séries A).

Aussi, la norme permet à ce que certaines valeurs
« trappent ». La norme C est beaucoup plus précise à cet
égard, et dit explicitement que si la représentation est
complément à 2 ou magnitude signée, une représentation avec le
bit de signe à 1 et tous les autres bits à zéro peut trapper.

Dans la pratique, évidemment, au moins de rencontrer un Unisys
2200, ou de se rétrouver sur des architectures fortes anciennes
(mais alors, il n'y a probablement pas de compilateur C++), les
entiers signés sont complément à 2, et tu auras l'intervale
auquel tu t'attends.

Hmm, je vais me limiter aux architectures courantes, alors.
C'est pour l'écriture d'un flux binaire :

void
BinaryStream::writeUInt8(unsigned x)
{
assert(x <= 0xFF);
myIsOk = myIsOk && myBuffer->sputc(x)
!= std::streambuf::traits_type::eof();
}

void
BinaryStream::writeUInt16(unsigned x)
{
assert(x <= 0xFFFFU);
writeUInt8((x ) & 0xFF);
writeUInt8((x >> Cool & 0xFF);
}

void
BinaryStream::writeInt8(int x)
{
assert(-0x80 <= x && x <= 0x7F);
writeUInt8(x < 0 ? 0xFF + (x + 1) : x);
}

void
BinaryStream::writeInt16(int x)
{
assert(-0x8000 <= x && x <= 0x7FFF);
writeUInt16(x < 0 ? 0xFFFFU + (x + 1) : x);
}

....

--
Sylvain Togni
Back to top
kanze
Guest





PostPosted: Fri Jul 28, 2006 9:11 am    Post subject: Re: Range des entiers signés Reply with quote

Sylvain Togni wrote:
Quote:
kanze a écrit :

Les non-signés, la norme garanti [0, 2^n - 1].

Pas si tu insistes que n soit le nombre de bits. Il peut y
avoir des bits de padding, et autant que je sache, une
implémentation sur un hardware qui ne supporte pas de
non-signer (les anciens Unisys séries A ?) peut le simuler
en masquant le bit de signe.

Donc 2^(sizeof(unsigned)*CHAR_BIT) - 1 peut être supérieur à
UINT_MAX.

Et l'a été, au moins sur une architecture.

Quote:
Mais quand la norme spécifie que unsigned int fait
au moins 16 bits, parle-t-elle de sizeof ou de UINT_MAX ?

La norme ne dit pas que unsigned int fait au mois 16 bits. Ce
que la norme (C -- la norme C++ ici en fait référence) dit,
c'est que UINT_MAX doit être au moins 65535. (Évidemment, il dit
aussi qu'il faut que la représentation soit en base 2. Ce qui
fait avec moins de 16 bits, on n'y arrive pas.)

Quote:
Qu'en est-il des signés,
a-t-on [-2^(n - 1), 2^(n - 1) - 1] de garanti ?

Non. On a même des implémentations actuelles où ce n'est pas
le cas. Comment en ferais-tu si le hardware est complément à
1 (le cas des Unisys 2200 actuels). Ou magnitude signée (le
cas des anciens Unisys séries A).

Aussi, la norme permet à ce que certaines valeurs « trappent
». La norme C est beaucoup plus précise à cet égard, et dit
explicitement que si la représentation est complément à 2 ou
magnitude signée, une représentation avec le bit de signe à
1 et tous les autres bits à zéro peut trapper.

Dans la pratique, évidemment, au moins de rencontrer un
Unisys 2200, ou de se rétrouver sur des architectures fortes
anciennes (mais alors, il n'y a probablement pas de
compilateur C++), les entiers signés sont complément à 2, et
tu auras l'intervale auquel tu t'attends.

Hmm, je vais me limiter aux architectures courantes, alors.

Ça rend la vie nettement plus facile, et la probabilité qu'on
a à supporter les autres est en général très faible, sinon nul.
Je fais comme toi ; pourquoi faire du travail pour rien ?

C'est un peu plus délicat en ce qui concerne les flottants,
parce qu'il y a encore une architecture assez répandue qui n'est
pas IEEE (et aussi dans le cas d'une architecture IEEE, il peut
y avoir des subtilités dans la conversion).

Quote:
C'est pour l'écriture d'un flux binaire :

void
BinaryStream::writeUInt8(unsigned x)
{
assert(x <= 0xFF);
myIsOk = myIsOk && myBuffer->sputc(x)
!= std::streambuf::traits_type::eof();
}

void
BinaryStream::writeUInt16(unsigned x)
{
assert(x <= 0xFFFFU);
writeUInt8((x ) & 0xFF);
writeUInt8((x >> Cool & 0xFF);
}

void
BinaryStream::writeInt8(int x)
{
assert(-0x80 <= x && x <= 0x7F);
writeUInt8(x < 0 ? 0xFF + (x + 1) : x);
}

void
BinaryStream::writeInt16(int x)
{
assert(-0x8000 <= x && x <= 0x7FFF);
writeUInt16(x < 0 ? 0xFFFFU + (x + 1) : x);
}

C'est à peu près ce que je fais aussi.

Note bien que ce que tu as écrit là est prèsque 100% portable ;
la seule chose qui n'est pas garantie par la norme, c'est la
comparaison d'un int avec -0x8000. (Sur une machine 16 bit,
0x8000 a le type unsigned. Ce qui fait que ton x sera converti
en unsigned avant la comparaison.)

Sinon, les règles veulent bien que les décalages, etc., ignore
les bits de rembourage (s'il y en a), et que la conversion de
signed en unsigned donne les mêmes bits qu'aurait eu le signed
en représentation complément à deux. (C-à-d que sur une
architecture complément à deux, la conversion signed -> unsigned
serait en fait un no-op, au niveau des bits, mais que sur une
autre architecture, les bits ne serait pas les mêmes après la
conversion.)

C'est à la lecture où le problème se pose (et où on fait des
économies en supposant complément à deux, sans vérification).
Parce que la conversion unsigned -> signed est définie par
l'implémentation (et il n'y a aucun exigeance que si tu fais
signed -> unsigned -> signed, tu te rétrouves avec la valeur du
départ). Donc, une implémentation du genre :

int
BinaryStream::readInt16()
{
return readUInt16() ;
}

ne marche que sur une machine complément à 2 avec des int
d'exactement 16 bits. Sur des architectures courantes, si tu
utilises les int16_t et uint16_t de C99, c'est garantie.
D'ailleurs, en C99, si tu utilises ces types, et l'architecture
n'est pas complément à 2, ou n'a pas de type entier avec
exactement 16 bits, tu auras une erreur de compilation. C'est
donc la solution optimale ; tu ne fais pas de travail
supplémentaire, et si tu tombes sur une architecture où il
l'aurait fallu, tu as une erreur de compilation.

Le seul hic, c'est que les implémentations de C99 sont
rarissime.

--
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
Back to top
Olivier Miakinen
Guest





PostPosted: Fri Jul 28, 2006 2:53 pm    Post subject: Re: Range des entiers signés Reply with quote

Le 28/07/2006 09:24, kanze a écrit :
Quote:

[...]
assert(-0x8000 <= x && x <= 0x7FFF);

Note bien que ce que tu as écrit là est prèsque 100% portable ;
la seule chose qui n'est pas garantie par la norme, c'est la
comparaison d'un int avec -0x8000. (Sur une machine 16 bit,
0x8000 a le type unsigned. Ce qui fait que ton x sera converti
en unsigned avant la comparaison.)

J'ai eu un problème similaire avec -2147483648 sur une machine 32 bits.
Si je me rappelle bien, j'ai dû le remplacer par (-2147483647 - 1) pour
éviter un warning à la compilation.
Back to top
Sylvain Togni
Guest





PostPosted: Fri Jul 28, 2006 3:20 pm    Post subject: Re: Range des entiers signés Reply with quote

Olivier Miakinen a écrit :

Quote:
assert(-0x8000 <= x && x <= 0x7FFF);
Note bien que ce que tu as écrit là est prèsque 100% portable ;
la seule chose qui n'est pas garantie par la norme, c'est la
comparaison d'un int avec -0x8000. (Sur une machine 16 bit,
0x8000 a le type unsigned. Ce qui fait que ton x sera converti
en unsigned avant la comparaison.)

J'ai eu un problème similaire avec -2147483648 sur une machine 32 bits.
Si je me rappelle bien, j'ai dû le remplacer par (-2147483647 - 1) pour
éviter un warning à la compilation.

C'est bizarre, je pensais que -0x8000 et -2147483648 étaient des
constantes entières signées (négatives), alors que si je comprend
bien c'est des constantes entières non signées positives (0x8000
et 2147483648) auxquelles on applique l'opérateur - ?

--
Sylvain Togni
Back to top
Olivier Miakinen
Guest





PostPosted: Fri Jul 28, 2006 3:37 pm    Post subject: Re: Range des entiers signés Reply with quote

Le 28/07/2006 12:20, Sylvain Togni a écrit :
Quote:

C'est bizarre, je pensais que -0x8000 et -2147483648 étaient des
constantes entières signées (négatives),

C'est ce que je croyais avant d'obtenir ce warning de compilation.

Quote:
alors que si je comprend
bien c'est des constantes entières non signées positives (0x8000
et 2147483648) auxquelles on applique l'opérateur - ?

En effet.
Back to top
James Kanze
Guest





PostPosted: Sun Jul 30, 2006 12:02 am    Post subject: Re: Range des entiers signés Reply with quote

Sylvain Togni wrote:
Quote:
Olivier Miakinen a écrit :

assert(-0x8000 <= x && x <= 0x7FFF);

Note bien que ce que tu as écrit là est prèsque 100% portable ; la
seule chose qui n'est pas garantie par la norme, c'est la
comparaison d'un int avec -0x8000. (Sur une machine 16 bit, 0x8000 a
le type unsigned. Ce qui fait que ton x sera converti en unsigned
avant la comparaison.)

J'ai eu un problème similaire avec -2147483648 sur une machine 32
bits. Si je me rappelle bien, j'ai dû le remplacer par (-2147483647
- 1) pour éviter un warning à la compilation.

C'est bizarre, je pensais que -0x8000 et -2147483648 étaient des
constantes entières signées (négatives), alors que si je comprend bien
c'est des constantes entières non signées positives (0x8000 et
2147483648) auxquelles on applique l'opérateur - ?

Il n'y a pas de littéraux négatifs en C++. D'une côté, c'est
effectivement un peu étonnant dans ce cas ci. De l'autre...
est-ce que ça te plairait que « -123 » et « - 123 » ait une
signification différente ?

--
James Kanze kanze.james (AT) neuf (DOT) fr
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
Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (French) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.