Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Usage de ~ qui, ce me semble, veut dire not.

5 views
Skip to first unread message

Dominique

unread,
Apr 11, 2021, 4:57:11 AM4/11/21
to
Bonjour,

Python 3.8.5.

Je comprends mal le comportement de ~ (le tilde) :

soit a,b=5,7

a>b False normal

a>~b True, résultat attendu

b<a False, normal, mais

b<~a False aussi, et là, je ne comprends pas. Voyez-vous pourquoi j'ai
ce résultat inattendu ? Je suppose que, à la question « b pas inférieur
à a », je devrais obtenir True...

En vous souhaitant un beau dimanche,

--
Dominique
Courriel : dominique point sextant ate orange en France
Esto quod es

Dominique

unread,
Apr 11, 2021, 5:36:51 AM4/11/21
to
Le 11/04/2021 à 10:57, Dominique a écrit :
> Bonjour,
>
> Python 3.8.5.
>
> Je comprends mal le comportement de ~ (le tilde) :
>
> soit a,b=5,7
>
> a>b False normal
>
> a>~b True, résultat attendu
>
> b<a False, normal, mais
>
> b<~a False aussi, et là, je ne comprends pas. Voyez-vous pourquoi j'ai
> ce résultat inattendu ? Je suppose que, à la question « b pas inférieur
> à a », je devrais obtenir True...
>
> En vous souhaitant un beau dimanche,
>

Bon, mon fils m'a apporté une explication que je ne comprends pas bien
mais je vois que not a==0 rend True, quelle que soit la valeur de a. Je
déduis que « not une variable » retourne toujours 0, or 0 est False.

Mais si x='' (string vide), not x donne True. pourquoi ?

Pour revenir au tilde, soit a=5, ~a donne -6 et ~-5 donne 4... Pourquoi
? On voit comme un effet miroir avec une réduction de la valeur relative
d'une unité (~5 donne -5-1 et ~-6 donne 6-1)...

Tout ceci me rend perplexe :-)

Benoit Izac

unread,
Apr 11, 2021, 5:47:12 AM4/11/21
to
Bonjour,

Le 11/04/2021 à 10:57, Dominique a écrit dans le message
<s4udl2$191p$1...@gioia.aioe.org> :

> Je comprends mal le comportement de ~ (le tilde) :
>
> [ce me semble, veut dire not.]

Inexact :

<https://docs.python.org/3/reference/expressions.html#unary-arithmetic-and-bitwise-operations>

« not » c'est… « not ».

--
Benoit Izac

Benoit Izac

unread,
Apr 11, 2021, 5:51:29 AM4/11/21
to
Bonjour,

Le 11/04/2021 à 11:36, Dominique a écrit dans le message
<s4ufvh$8vt$1...@gioia.aioe.org> :

> Bon, mon fils m'a apporté une explication que je ne comprends pas bien
> mais je vois que not a==0 rend True, quelle que soit la valeur de a.

Pas tout à fait vrai :

>>> a = 0
>>> not a==0
False
>>> False==0
True

--
Benoit Izac

Alain Ketterlin

unread,
Apr 11, 2021, 6:47:50 AM4/11/21
to
Dominique <z...@aol.com.invalid> writes:

>> Je comprends mal le comportement de ~ (le tilde) :
>>
>> soit a,b=5,7
>>
>> a>b False normal
>>
>> a>~b True, résultat attendu
>>
>> b<a False, normal, mais
>>
>> b<~a False aussi, et là, je ne comprends pas. Voyez-vous pourquoi
>> j'ai ce résultat inattendu ? Je suppose que, à la question « b pas
>> inférieur à a », je devrais obtenir True...
[...]
> Bon, mon fils m'a apporté une explication que je ne comprends pas bien
> mais je vois que not a==0 rend True, quelle que soit la valeur de a.

Ben non, si a vaut 0, "not a == 0" vaut False.

> Je déduis que « not une variable » retourne toujours 0, or 0 est
> False.

Hmmm. Il n'y a rien de tel. "not" est la négation booléenne (qui change
True and False et vice-versa). Son opérande devrait en toute rigueur
être toujours une valeur booléenne.

> Mais si x='' (string vide), not x donne True. pourquoi ?

Normalement "not" s'applique à un booléen (comme "a == 0"), donc quand
on applique "not" à autre chose, le choix a été fait de transformer
cette autre chose en booléen. Cela n'a aucune signification universelle,
c'est juste une commodité, avec des conventions plus ou moins
arbitraire. En gros, "not x" vaut :

- si x est None, il est considéré avoir la valeur booléenne False (donc
"not None" vaut True)
- si x est un entier, la valeur 0 est False et toute autre valeur est
True ; donc "not x" équivaut à "x == 0"
- si x est une chaîne de caractères, la valeur vide '' vaut False et
toute autre valeur vaut True ; donc "not x" équivaut à "len(x) == 0"
etc.

Les détails sont à
https://docs.python.org/3/reference/expressions.html#comparisons

Tout ça pout économiser quelques caractères...

> Pour revenir au tilde, soit a=5, ~a donne -6 et ~-5 donne 4...
> Pourquoi ? On voit comme un effet miroir avec une réduction de la
> valeur relative d'une unité (~5 donne -5-1 et ~-6 donne 6-1)...

Le tilde est l'opération de négation bit-à-bit (*pas* la négation
booléenne, une sorte de micro-négation appliquée ndividuellement sur les
bits qui composent une valeur). Elle change chaque bit en son
complément. Ce que tu oberves est le résultat de l'opération appliquée à
des données qui représentent des entiers. C'est lié au codage des
entiers en "complément à deux". Cf. par exemple (plutôt la page en
anglais) :

https://fr.wikipedia.org/wiki/Compl%C3%A9ment_%C3%A0_deux
https://en.wikipedia.org/wiki/Two%27s_complement

Et effectivement, ~x est égal à -(x+1). C'est une propriété de cette
représentation (~0 -> -1, ~1 -> -2, etc.), mais c'est une propriété
arithmétique, disons, anecdotique : l'opération ~ inverse
individuellement les bits de l'entier, c'est tout. Il existe des
microprocesseurs utilisant une autre représentation et cette propriété
n'est pas vraie sur ces processeurs.

Pour comprendre ce qui se passe, il faut se souvenir que les entiers
sont représentés sur un nombre fini de bits (en général 32 ou 64), et
que tous les bits sont inversés. Par exemple, sur 32 bits :

5 est représenté par 0...0101 (32 bits en tout, donc 29 fois 0 en tête).
~5 est donc 1...1010 (avec donc 29 fois 1 en tête)

Et 1...1010 c'est la représentation de -6.

(En python, le nombre de bits pour représenter un entier n'est pas fixé,
mais c'est une autre histoire et ça ne change rien à notre propos. Tu
peux imaginer qu'il y a toujours quelques zéros en tête d'une valeur
positive -- et quelques uns en tête d'une valeur négative.)

Le tilde n'est utile que quand on travaille sur des bits individuels
(qu'on regroupe en général dans des entiers, parce qu'on n'a pas mieux).
Les autres opérations apparentées sont & | ^ (autres opérations binaires
bit-à-bit : "and" "or" "xor"), ainsi que << et >> (décalages). Exercice
pour le lecteur : pourquoi est-ce que "-1 >> d" vaut -1 quelle que soit
la valeur de d ?

-- Alain.

Olivier Miakinen

unread,
Apr 11, 2021, 7:53:22 AM4/11/21
to
Bonjour,

Je viens à peine de me mettre au python (il y a en gros une ou deux
semaines), alors ce genre de question m'intéresse beaucoup :

Le 11/04/2021 12:47, Alain Ketterlin a écrit :
>
> [...]
> Les autres opérations apparentées sont & | ^ (autres opérations binaires
> bit-à-bit : "and" "or" "xor"), ainsi que << et >> (décalages). Exercice
> pour le lecteur : pourquoi est-ce que "-1 >> d" vaut -1 quelle que soit
> la valeur de d ?

Je suppose que le décalage à droite propage le bit de signe, afin que
"-6 >> 1" vaille 3 tout comme "6 >> 1" vaut 3. Mais existe-t-il un type
d'entier non signé ? Un truc qui ferait que "unsigned(-1)" vaudrait un
de moins qu'une grande puissance de 2 ?


--
Olivier Miakinen

Benoit Izac

unread,
Apr 11, 2021, 8:03:21 AM4/11/21
to
Bonjour,

Le 11/04/2021 à 13:53, Olivier Miakinen a écrit dans le message
<s4unvh$27b$1...@cabale.usenet-fr.net> :

>> Les autres opérations apparentées sont & | ^ (autres opérations binaires
>> bit-à-bit : "and" "or" "xor"), ainsi que << et >> (décalages). Exercice
>> pour le lecteur : pourquoi est-ce que "-1 >> d" vaut -1 quelle que soit
>> la valeur de d ?
>
> Je suppose que le décalage à droite propage le bit de signe, afin que
> "-6 >> 1" vaille 3 tout comme "6 >> 1" vaut 3. Mais existe-t-il un type
^
-3

> d'entier non signé ? Un truc qui ferait que "unsigned(-1)" vaudrait un
> de moins qu'une grande puissance de 2 ?

Moi je pense que « a >> 1 == ~(~a >> 1) » donc vu que « -1 == ~0 » et
que « 0 >> d » vaut toujours 0, « ~(~0 >> d) == -1 ».

--
Benoit Izac

Olivier Miakinen

unread,
Apr 11, 2021, 8:39:41 AM4/11/21
to
Le 11/04/2021 14:03, Benoit Izac m'a répondu :
>
>>> Les autres opérations apparentées sont & | ^ (autres opérations binaires
>>> bit-à-bit : "and" "or" "xor"), ainsi que << et >> (décalages). Exercice
>>> pour le lecteur : pourquoi est-ce que "-1 >> d" vaut -1 quelle que soit
>>> la valeur de d ?
>>
>> Je suppose que le décalage à droite propage le bit de signe, afin que
>> "-6 >> 1" vaille 3 tout comme "6 >> 1" vaut 3. Mais existe-t-il un type
> ^
> -3

Oui, bien sûr. Faute de frappe stupide vu le peu de texte que j'écrivais :
j'aurais dû me relire.

>> d'entier non signé ? Un truc qui ferait que "unsigned(-1)" vaudrait un
>> de moins qu'une grande puissance de 2 ?
>
> Moi je pense que « a >> 1 == ~(~a >> 1) »

Certes, mais c'est une *conséquence* du fait que le décalage à droite propage
le bit de signe. J'ai du mal à voir ça comme une cause ou une explication de
ce comportement.

Par exemple, ça ne fonctionne à priori jamais avec le décalage à gauche :
« a << 1 != ~(~a << 1) »

Enfin, ça ne répond pas à ma question : y a-t-il un type unsigned en python ?

--
Olivier Miakinen

Benoit Izac

unread,
Apr 11, 2021, 8:57:59 AM4/11/21
to
Bonjour,

Le 11/04/2021 à 14:39, Olivier Miakinen a écrit dans le message
<s4uqmc$2k7$1...@cabale.usenet-fr.net> :

> Enfin, ça ne répond pas à ma question : y a-t-il un type unsigned en
> python ?

Ça s'est facile : non.

--
Benoit Izac

Olivier Miakinen

unread,
Apr 11, 2021, 9:20:19 AM4/11/21
to
Le 11/04/2021 14:57, Benoit Izac a écrit :
>
>> Enfin, ça ne répond pas à ma question : y a-t-il un type unsigned en
>> python ?
>
> Ça c'est facile : non.

:-)

Ok, je dois dire que je m'en doutais un peu. D'un autre côté, ça me semble
assez peu utile si les entiers sont au moins sur 64 bits.


--
Olivier Miakinen

Alain Ketterlin

unread,
Apr 11, 2021, 9:42:49 AM4/11/21
to
Olivier Miakinen <om+...@miakinen.net> writes:

>> Les autres opérations apparentées sont & | ^ (autres opérations binaires
>> bit-à-bit : "and" "or" "xor"), ainsi que << et >> (décalages). Exercice
>> pour le lecteur : pourquoi est-ce que "-1 >> d" vaut -1 quelle que soit
>> la valeur de d ?
>
> Je suppose que le décalage à droite propage le bit de signe, afin que
> "-6 >> 1" vaille 3 tout comme "6 >> 1" vaut 3. Mais existe-t-il un type
> d'entier non signé ? Un truc qui ferait que "unsigned(-1)" vaudrait un
> de moins qu'une grande puissance de 2 ?

Ton explication est correcte : en Python tous les entiers sont signés,
et tous les décalages "à droite" s'effectuent avec "extension de signe"
(le bit le plus à droite est répliqué). Dans -1 tous les bits sont à 1,
et donc le restent lors du décalage.

(Juste un truc, pour être sûr : le "bit de signe" est une expression
correcte -- le bit de poids fort, le plus à gauche, est effectivement 1
pour les entiers négatifs -- mais il vaut mieux éviter les confusions
avec la représentation "signed-magnitude", celle qui a deux
représentations de zéro.)

Et non, il n'y a pas d'entiers non signés en Python, ce qui n'a pas
vraiment de conséquence pratique, puisque tous les entiers sont de
précision arbitraire. Si on utilise uniquement des entiers positifs et
qu'on effectue des décalages, le résultat restera toujours positif, on
ne risque pas de surprise. Pour avoir 2^n-1 on fait "2 ** n - 1". Note
que la définition du langage précise :

"A right shift by n bits is defined as floor division by pow(2,n). A
left shift by n bits is defined as multiplication with pow(2,n)."

Au passage, puisqu'on parlait de ~ la doc dit :

"The unary ~ (invert) operator yields the bitwise inversion of its
integer argument. The bitwise inversion of x is defined as -(x+1). It
only applies to integral numbers."

Tout cela dans : https://docs.python.org/3/reference/expressions.html --
et si vous trouvez bizarre qu'on "réduise" les opérations binaires à des
opérations arithmétiques, vous avez toute ma sympathie.


Enfin, pour ceux que la discussion rend perplexe : il y a deux façons de
décaler à droite. Le décalage "arithmétique" recopie le bit de poids
fort, le décalage "logique" le met à zéro (ce sont respectivement les
instructions SAR et SHR sur x86). En C (entre autres), on utilise l'une
ou l'autre selon le type de l'entier. Ainsi :

x = -1;
y = x >> 1;

donnera à y une valeur différente selon que x est signé ou pas.

Rien de tout cela en Python : tout est signé, le décalage est toujours
arithmétique, il n'y a pas d'overflow, division et modulo sont corrects,
etc. C'est reposant, tant qu'on ne s'occupe pas de performance ou
d'occupation mémoire.

-- Alain.

Olivier Miakinen

unread,
Apr 11, 2021, 10:11:55 AM4/11/21
to
Le 11/04/2021 15:42, Alain Ketterlin a écrit :
>
> Ton explication est correcte : en Python tous les entiers sont signés,
> et tous les décalages "à droite" s'effectuent avec "extension de signe"
> (le bit le plus à droite est répliqué). Dans -1 tous les bits sont à 1,
> et donc le restent lors du décalage.

C'est assez classique pour à peu près tous les langages dans lesquels les
entiers signés sont représentés en « complément à 2 » et en taille fixe.
Mais je vois dans la suite de ta réponse que dans Python les entiers ne
sont pas contraints à une taille fixe.

> (Juste un truc, pour être sûr : le "bit de signe" est une expression
> correcte -- le bit de poids fort, le plus à gauche, est effectivement 1
> pour les entiers négatifs -- mais il vaut mieux éviter les confusions
> avec la représentation "signed-magnitude", celle qui a deux
> représentations de zéro.)

Oui, en effet. Cette repérsentation étant par exemple IEEE 754. Est-ce
que les réels en Python sont représentés en IEEE 754 ?

> Et non, il n'y a pas d'entiers non signés en Python, ce qui n'a pas
> vraiment de conséquence pratique, puisque tous les entiers sont de
> précision arbitraire.

Ah oui, en effet :

>>> 2**1000
10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376
>>> 2.**1000
1.0715086071862673e+301
>>> 2.**10000
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OverflowError: (34, 'Numerical result out of range')

> [...]
>
> Rien de tout cela en Python : tout est signé, le décalage est toujours
> arithmétique, il n'y a pas d'overflow, division et modulo sont corrects,
> etc. C'est reposant, tant qu'on ne s'occupe pas de performance ou
> d'occupation mémoire.

Oui. J'avais un à priori négatif au sujet de Python avant de m'y mettre,
mais maintenant au contraire je suis ravi d'avoir franchi le pas, et
« reposant » est vraiment le qualificatif qui convient.

Merci de tes réponses.


--
Olivier Miakinen

Olivier Miakinen

unread,
Apr 11, 2021, 10:31:14 AM4/11/21
to
Le 11/04/2021 16:11, je répondais à Alain Ketterlin :
>>
>> Rien de tout cela en Python : tout est signé, le décalage est toujours
>> arithmétique, il n'y a pas d'overflow, division et modulo sont corrects,
>> etc. C'est reposant, tant qu'on ne s'occupe pas de performance ou
>> d'occupation mémoire.
>
> Oui. J'avais un à priori négatif au sujet de Python avant de m'y mettre,
> mais maintenant au contraire je suis ravi d'avoir franchi le pas, et
> « reposant » est vraiment le qualificatif qui convient.
>
> Merci de tes réponses.

Et pardon pour avoir constamment répondu sur autre chose que l'opérateur
« ~ », malgré le titre du fil et tes efforts méritoires pour toujours y
revenir. ;-)


--
Olivier Miakinen

Dominique

unread,
Apr 11, 2021, 11:34:22 AM4/11/21
to
Le 11/04/2021 à 14:03, Benoit Izac a écrit :

> Moi je pense que « a >> 1 == ~(~a >> 1) » donc vu que « -1 == ~0 » et
> que « 0 >> d » vaut toujours 0, « ~(~0 >> d) == -1 ».
>

Là, j'avoue avoir décroché depuis un petit moment :-)
Je pense que je vais, temporairement, oublier le tilde...
Merci à vous tous,

Dominique

unread,
Apr 11, 2021, 11:35:53 AM4/11/21
to
C'est effectivement tout ce que je comprends de ce qui précède. Not et
tilde n'ont pas la même signification.

Merci et bonne fin de weekend,

Olivier Miakinen

unread,
Apr 11, 2021, 11:59:38 AM4/11/21
to
Le 11/04/2021 17:34, Dominique a écrit :
>
>> Moi je pense que « a >> 1 == ~(~a >> 1) » donc vu que « -1 == ~0 » et
>> que « 0 >> d » vaut toujours 0, « ~(~0 >> d) == -1 ».
>>
>
> Là, j'avoue avoir décroché depuis un petit moment :-)
> Je pense que je vais, temporairement, oublier le tilde...

Juste pour essayer de te « raccrocher », un exemple en supposant des
entiers sur 16 bits.

Si a s'écrit en binaire :
0000000011000001
alors ~a s'écrira en binaire :
1111111100111110

Tous les 0 de l'écriture en binaire deviennent des 1, et tous les 1
deviennent des 0.



En Python, avec des entiers de taille illimitée, c'est la même chose
sauf que, conceptuellement, il y a une infinité de 0 ou de 1 à gauche :
...0000000011000001
et :
...1111111100111110



--
Olivier Miakinen

Alain Ketterlin

unread,
Apr 11, 2021, 1:43:03 PM4/11/21
to
Olivier Miakinen <om+...@miakinen.net> writes:

[...]
> Oui, en effet. Cette repérsentation étant par exemple IEEE 754. Est-ce
> que les réels en Python sont représentés en IEEE 754 ?

Oui et non. En théorie, la règle est :

"These represent machine-level double precision floating point numbers.
You are at the mercy of the underlying machine architecture (and C or
Java implementation) for the accepted range and handling of overflow."

(https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy)

Et dans la bibliothèque standard, il est dit que :

"Floating point numbers are usually implemented using double in C"

(https://docs.python.org/3/library/stdtypes.html#typesnumeric)


Donc, en pratique, oui c'est IEEE 754 (double précision). Idem pour les
nombres complexes.

-- Alain.

Benoit Izac

unread,
Apr 11, 2021, 1:43:52 PM4/11/21
to
Bonjour,

Le 11/04/2021 à 15:42, Alain Ketterlin a écrit dans le message
<87r1jh7...@universite-de-strasbourg.fr.invalid> :

>>> Les autres opérations apparentées sont & | ^ (autres opérations binaires
>>> bit-à-bit : "and" "or" "xor"), ainsi que << et >> (décalages). Exercice
>>> pour le lecteur : pourquoi est-ce que "-1 >> d" vaut -1 quelle que soit
>>> la valeur de d ?
>>
>> Je suppose que le décalage à droite propage le bit de signe, afin que
>> "-6 >> 1" vaille 3 tout comme "6 >> 1" vaut 3. Mais existe-t-il un type
>> d'entier non signé ? Un truc qui ferait que "unsigned(-1)" vaudrait un
>> de moins qu'une grande puissance de 2 ?
>
> Ton explication est correcte : en Python tous les entiers sont signés,
> et tous les décalages "à droite" s'effectuent avec "extension de signe"
> (le bit le plus à droite est répliqué). Dans -1 tous les bits sont à 1,
> et donc le restent lors du décalage.

Ce n'est pas plutôt le bit le plus à gauche qui est répliqué ?

--
Benoit Izac

Alain Ketterlin

unread,
Apr 11, 2021, 5:04:16 PM4/11/21
to
Benoit Izac <use.re...@INVALID.ADDRESS> writes:

[...]
>>>> pourquoi est-ce que "-1 >> d" vaut -1 quelle que soit la valeur de
>>>> d ?
>>>
>>> Je suppose que le décalage à droite propage le bit de signe, afin que
>>> "-6 >> 1" vaille 3 tout comme "6 >> 1" vaut 3. Mais existe-t-il un type
>>> d'entier non signé ? Un truc qui ferait que "unsigned(-1)" vaudrait un
>>> de moins qu'une grande puissance de 2 ?
>>
>> Ton explication est correcte : en Python tous les entiers sont signés,
>> et tous les décalages "à droite" s'effectuent avec "extension de signe"
>> (le bit le plus à droite est répliqué). Dans -1 tous les bits sont à 1,
>> et donc le restent lors du décalage.
>
> Ce n'est pas plutôt le bit le plus à gauche qui est répliqué ?

Si si, bien sûr, merci d'avoir corrigé.

-- Alain.
0 new messages