Número inteiro
Definição
- Um número inteiro corresponde a um valor positivo ou negativo, incluindo zero, sem a parte decimal.
- Vejamos um exemplo de como uma variável pode ser associada a um número inteiro.
a = 6;
b = int(14)
c = int(5.4)
d = int(5.9)
print('a =',a,', b =', b, ', c =', c, ', d =', d)
Note que, para a variável a, não há especificação do tipo de dado. O Python analisa o valor, identifica que é um número inteiro e associa a variável a um objeto inteiro. Nos comandos seguintes, o programa utiliza o método int() para fazer a associação das variáveis a um objeto inteiro. Abaixo é mostrada a saída do programa.
a = 6 , b = 14 , c = 5 , d = 5
Observe que, tanto para a variável c quanto para a variável d, apenas a parte inteira do número foi aproveitada. Não foi feito qualquer arredondamento. O Python apresentará erro se não conseguir converter o argumento passado em int() para um número inteiro.
Método int()
O método int() retorna um objeto do tipo inteiro e pode ser chamado usando uma das formas abaixo.
class int() class int(valor) class int(valor, base)
onde valor é um número inteiro e base define a base numérica. Por padrão, valor é zero e base é decimal. Vejamos um exemplo.
a = 6; b = int() c = int('FF',16) print('a =',a,', b =', b, ', c =', c)
No exemplo acima, três variáveis são associadas a objetos inteiros. A primeira variável tem o valor 6; a segunda variável tem o valor zero; e a terceira variável tem o valor na base decimal que corresponde ao valor ‘FF’ na base hexadecimal. O resultado é mostrado abaixo.
a = 6 , b = 0 , c = 255
Identificador
No Python, duas variáveis do tipo inteiro e com o mesmo valor são associadas a um mesmo objeto. São dois nomes para um mesmo objeto. Podemos verificar isso usando o método id(). Este método informa a identificação única de um objeto durante a execução do programa.
a = 6 b = 15 c = a print('** 1 ') print('id(a) =',id(a),', id(b) =', id(b), ', id(c) =', id(c)) print('id(6) =', id(6), ', id(15) =', id(15)) b = a c = 15 print(' 2 **') print('id(a) =',id(a),', id(b) =', id(b), ', id(c) =', id(c)) print('id(6) =', id(6), ', id(15) =', id(15))
Uma possível saída é mostrada abaixo.
** 1 ** id(a) = 10914656 , id(b) = 10914944 , id(c) = 10914656 id(6) = 10914656 , id(15) = 10914944 ** 2 ** id(a) = 10914656 , id(b) = 10914656 , id(c) = 10914944 id(6) = 10914656 , id(15) = 10914944
Note que na primeira parte do programa, as variáveis a e c e o número 6 possuem a mesma identificação (10914656): a e c são dois nomes para o objeto inteiro 6. Além disso, a variável b e o número 15 possuem uma única identificação (10914944): temos apenas o nome b para o objeto inteiro 15 no programa.
Na segunda parte do programa, os valores das variáveis b e c são alterados. Agora a, b e 6 possuem a mesma identificação, enquanto c e 15 possuem uma outra identificação.
Short numbers
O Python mantém uma matriz de objetos inteiros para todos os números inteiros entre -5 e 256. Quando uma variável é definida com um valor nesse intervalo, a variável apenas recebe de volta uma referência ao objeto existente. Vejamos um exemplo.
for i in range(255,259): print('i =', i, ', id(i) =', id(i)) print() a = 255 print('a = ', a, 'id(a) = ', id(a)) b = 256 print('b = ', b, 'id(b) = ', id(b)) c = 257 print('c = ', c, 'id(c) = ', id(c)) d = 258 print('d = ', d, 'id(d) = ', id(d)) e = 257 print('e = ', e, 'id(e) = ', id(e))
Na primeira parte do programa, a variável i recebe valores de 255 a 258. Em seguida são definidas 4 diferentes variáveis que recebem valores de 255 a 258 e uma quinta variável que recebe o valor 257. O resultado do programa é mostrado abaixo.
i = 255 , id(i) = 10922624 i = 256 , id(i) = 10922656 i = 257 , id(i) = 140593168144208 i = 258 , id(i) = 140593168143184 a = 255 id(a) = 10922624 b = 256 id(b) = 10922656 c = 257 id(c) = 140593191797552 d = 258 id(d) = 140593191688784 e = 257 id(e) = 140593191797552
Note que: i = 255 e a = 255 possuem a mesma identificação e que i = 256 e b = 256 possuem a mesma identificação. Os valores 255 e 256 são short numbers, ou seja, esses valores são armazenados em objetos inteiros antes do início da execução do programa. Novas variáveis representam apenas novos nomes para esses objetos.
As variáveis c = 257 e e = 257 possuem a mesma identificação. São dois nomes para um mesmo objeto. Entretanto, i = 257 tem uma identificação diferente. A explicação é simples: quando a variável i assumiu o valor 257, um objeto inteiro foi alocado; mas em seguida o valor de i mudou para 258 e a variável passou a referenciar um novo objeto. Quando a variável c foi definida com o valor 257, nenhuma outra variável possuía esse valor e um novo objeto foi alocado. Quando a variável e foi definida, já existia um objeto com 257, então e passou a ser apenas um segundo nome para este objeto.
Por último, observe que i = 258 e d = 258 possuem a mesma identificação. A explicação é simples. O loop do início do programa se encerra com i = 258. Quando a variável d é definida com valor 258, nenhum objeto é alocado, e é apenas um segundo nome para o objeto com valor 258.
Implementação
- O tamanho de um objeto inteiro depende do valor armazenado. Podemos usar a função sys.getsizeof() para verificar a quantidade de bytes de um objeto.
import sys print('getsizeof(int()) =',sys.getsizeof(int())) print('getsizeof(0) =',sys.getsizeof(0)) print('getsizeof(1) =',sys.getsizeof(1)) print('getsizeof(2**30 - 1) =',sys.getsizeof(2**30 - 1)) print('getsizeof(2**30) =',sys.getsizeof(2**30)) print('getsizeof(2**60 - 1) =',sys.getsizeof(2**60 - 1)) print('getsizeof(2**60) =',sys.getsizeof(2**60)) print('getsizeof(2**90 - 1) =',sys.getsizeof(2**90 - 1)) print('getsizeof(2**90) =',sys.getsizeof(2**90)) print('getsizeof(2**120 - 1) =',sys.getsizeof(2**120 - 1))
Abaixo o resultado obtido com Python 3.6.9 em uma máquina Linux de 64 bits. Note que o objeto inteiro, sem parâmetro, possui 24 bytes (é inicializado com zero). Objetos com valores de 1 a 2^{30}-1 usam 28 bytes. E assim em diante.
getsizeof(int()) = 24 getsizeof(0) = 24 getsizeof(1) = 28 getsizeof(2**30 - 1) = 28 getsizeof(2**30) = 32 getsizeof(2**60 - 1) = 32 getsizeof(2**60) = 36 getsizeof(2**90 - 1) = 36 getsizeof(2**90) = 40 getsizeof(2**120 - 1) = 40
Podemos então resumir os resultados obtidos nos testes acima como:
Quantidade de Bytes | Valor Inicial | Valor Final |
24 Bytes | zero | zero |
28 Bytes | 1 | 2^{30} - 1 |
32 Bytes | 2^{30} | 2^{60} - 1 |
36 Bytes | 2^{60} | 2^{90} - 1 |
40 Bytes | 2^{90} | 2^{120} - 1 |
Os valores inteiros negativos seguem a mesma lógica para alocação de memória. Por exemplo, valores de -1 a -2^{30}+1 usam 28 bytes; valores de -2^{30} a -2^{60} + 1 usam 32 bytes; etc.
Podemos então concluir que, no ambiente utilizado, um número inteiro é representado por uma matriz de dígitos na base 2^{30}, onde cada dígito tem 4 bytes. Esta informação é confirmada por
import sys print(sys.int_info)
que fornece
sys.int_info(bits_per_digit=30, sizeof_digit=4)
- Com o que foi discutido acima, podemos observar que não existe limite definido para o tamanho de um número inteiro na implementação do Python3 usada neste estudo. Naturalmente que, quanto maior o número, maior será a alocação de memória e menor o desempenho do programa.
Armazenamento
- Um objeto inteiro em Python é internamente representado pela estrutura PyIntObject . Em especial, existem dois campos nessa estrutura que interessa nessa discussão: ob_size que armazena o sinal e a quantidade de dígitos do número inteiro; e ob_digit[] que é um vetor com os dígitos.
- Vejamos a representação de um número inteiro com um exemplo.
x = -123456789123456789123456789
Usando a base 2^{30} para representar x, temos
x = - (1006919445 \times (2^{30})^0 + 193906301 \times (2^{30})^1 + 107081695 \times (2^{30})^2)
O valor de x é então armazenado como mostrado abaixo.
ob_size = -3 ob_digit[0] = 1006919445 ob_digit[1] = 193906301 ob_digit[2] = 107081695
O programa abaixo mostra uma forma simples de calcular os dígitos de um número inteiro.
base = 2**30 num = abs(int(input('Entre com um número inteiro: '))) while num > base: a = num / base b = num % base i = 1 while a > base: a = a / base b = a % base i += 1 a = int(a) print(a) num = num - a * base**i print(num)
A resposta do programa para o inteiro 123456789123456789123456789 é
107081695 193906301 1006919445