web-dev-qa-db-fra.com

Pourquoi la taille de 2⁶³ est-elle de 36 octets, alors que 2⁶³-1 n’est que de 24 octets?

Tout dans Python est un objet. Ainsi, la taille d'un int dans Python sera plus grande que d'habitude.

>>> sys.getsizeof(int())
24

OK, mais pourquoi faut-il 12 octets de plus pour 2⁶³ Par rapport à 2⁶³ - 1 Et pas un seul?

>>> sys.getsizeof(2**63)
36
>>> sys.getsizeof(2**62)
24

Je comprends que 2⁶³ Est long et 2⁶³-1 Un int, mais pourquoi 12 octets de différence?

Plus intuitif, j'ai essayé d'autres choses:

>>> a = 2**63
>>> a -= 2**62
>>> sys.getsizeof(a)
36

a est toujours stocké en tant que long même s'il pourrait être dans un int maintenant. Donc ce n'est pas surprenant. Mais:

>>> a -= (2**63 - 1)
>>> a = 2**63
>>> a -= (2**63 - 1)
>>> a
1L
>>> sys.getsizeof(a)
28

Une nouvelle taille.

>>> a = 2**63
>>> a -= 2**63
>>> a
0L
>>> sys.getsizeof(a)
24

Retour à 24 octets, mais toujours avec un long.

Dernière chose que j'ai eu:

>>> sys.getsizeof(long())
24

Question:

Comment fonctionne la mémoire de stockage dans ces scénarios?

Sous-questions:

Pourquoi y a-t-il un espace de 12 octets pour ajouter ce que notre intuition nous dit n'est qu'un bit?

Pourquoi int() et long() 24 octets, alors que long(1) a déjà 28 octets et int(2⁶²)?

NB: Python 3.X fonctionne un peu différemment, mais pas de manière plus intuitive. Ici, je me suis concentré sur Python 2.7 ; Je n'ai pas testé sur les versions précédentes.

51
T.Nel

Bien que je ne l'ai pas trouvé dans la documentation, voici mon explication.

Python 2 promeut implicitement int en long, lorsque la valeur dépasse la valeur pouvant être stockée dans int. La taille du nouveau type (long) est la taille par défaut de long, qui est 32. Désormais, la taille de votre variable sera déterminée par sa valeur, qui peut aller haut et bas.

from sys import getsizeof as size
a = 1
n = 32

# going up
for i in range(10):
    if not i:
        print 'a = %100s%13s%4s' % (str(a), type(a), size(a))
    else:
        print 'a = %100s%14s%3s' % (str(a), type(a), size(a))
    a <<= n

# going down
for i in range(11):
    print 'a = %100s%14s%3s' % (str(a), type(a), size(a))
    a >>= n


a =                                                                                                    1 <type 'int'>  24
a =                                                                                           4294967296 <type 'long'> 32
a =                                                                                 18446744073709551616 <type 'long'> 36
a =                                                                        79228162514264337593543950336 <type 'long'> 40
a =                                                              340282366920938463463374607431768211456 <type 'long'> 44
a =                                                    1461501637330902918203684832716283019655932542976 <type 'long'> 48
a =                                           6277101735386680763835789423207666416102355444464034512896 <type 'long'> 52
a =                                 26959946667150639794667015087019630673637144422540572481103610249216 <type 'long'> 56
a =                       115792089237316195423570985008687907853269984665640564039457584007913129639936 <type 'long'> 60
a =              497323236409786642155382248146820840100456150797347717440463976893159497012533375533056 <type 'long'> 64
a =    2135987035920910082395021706169552114602704522356652769947041607822219725780640550022962086936576 <type 'long'> 68
a =              497323236409786642155382248146820840100456150797347717440463976893159497012533375533056 <type 'long'> 64
a =                       115792089237316195423570985008687907853269984665640564039457584007913129639936 <type 'long'> 60
a =                                 26959946667150639794667015087019630673637144422540572481103610249216 <type 'long'> 56
a =                                           6277101735386680763835789423207666416102355444464034512896 <type 'long'> 52
a =                                                    1461501637330902918203684832716283019655932542976 <type 'long'> 48
a =                                                              340282366920938463463374607431768211456 <type 'long'> 44
a =                                                                        79228162514264337593543950336 <type 'long'> 40
a =                                                                                 18446744073709551616 <type 'long'> 36
a =                                                                                           4294967296 <type 'long'> 32
a =                                                                                                    1 <type 'long'> 28

Comme vous pouvez le constater, le type reste long après qu’il soit devenu trop gros pour un int, et la taille initiale était de 32, mais la taille change avec la valeur (peut être supérieure ou inférieure [ ou égal, évidemment] à 32)

Donc, pour répondre à votre question, la taille de base est 24 pour int, et 28 pour long, alors que long dispose également de l'espace nécessaire pour enregistrer des valeurs élevées (qui commence par 4). octets - donc 32 octets pour long, mais peut monter et descendre en fonction de la valeur)

Quant à votre sous-question, créer un type unique (avec une taille unique) pour un nouveau numéro est impossible, donc Python a des "sous-classes" de long type, qui traiter avec une plage de nombres, donc, une fois que vous avez dépassé la limite de votre ancien long, vous devez utiliser le plus récent, ce qui représente également des nombres beaucoup plus grands. Il a donc quelques octets de plus.

5
CIsForCookies