Comprimento de um número inteiro em Python

233

No Python, como você encontra o número de dígitos em um número inteiro?

Strigoides
fonte
1
Eu não entendo sua pergunta. Você quis dizer o tamanho de um número inteiro? Deseja encontrar o número de dígitos? Por favor, esclareça.
batbrat

Respostas:

317

Se você deseja o comprimento de um número inteiro como no número de dígitos do número inteiro, sempre pode convertê-lo em string como str(133)e encontrar seu comprimento como len(str(123)).

GeekTantra
fonte
18
Obviamente, se você estiver procurando o número de dígitos, isso produzirá um resultado muito grande para números negativos, pois contará o sinal negativo.
Chris Upchurch
37
Ei, esta é uma solução lenta. Fiz um fatorial de um número aleatório de 6 dígitos e descobri seu comprimento. Este método levou 95,891 segundos. E o Math.log10método levou apenas 7,486343383789062e-05 segundos, aproximadamente 1501388 vezes mais rápido!
FadedCoder
1
Isso não é apenas lento, mas consome muito mais memória e pode causar problemas em grandes números. use em Math.log10vez disso.
Peyman
246

Sem conversão para string

import math
digits = int(math.log10(n))+1

Para também lidar com números zero e negativos

import math
if n > 0:
    digits = int(math.log10(n))+1
elif n == 0:
    digits = 1
else:
    digits = int(math.log10(-n))+2 # +1 if you don't count the '-' 

Você provavelmente gostaria de colocar isso em uma função :)

Aqui estão alguns benchmarks. A len(str())já está por trás até mesmo para muito pequenos números

timeit math.log10(2**8)
1000000 loops, best of 3: 746 ns per loop
timeit len(str(2**8))
1000000 loops, best of 3: 1.1 µs per loop

timeit math.log10(2**100)
1000000 loops, best of 3: 775 ns per loop
 timeit len(str(2**100))
100000 loops, best of 3: 3.2 µs per loop

timeit math.log10(2**10000)
1000000 loops, best of 3: 844 ns per loop
timeit len(str(2**10000))
100 loops, best of 3: 10.3 ms per loop
John La Rooy
fonte
5
Usar o log10 para isso é a solução de um matemático; O uso de len (str ()) é uma solução para programadores e é mais claro e mais simples.
Glenn Maynard
68
@ Glenn: Eu certamente espero que você não esteja sugerindo que esta é uma má solução. A ingênua solução O (log10 n) do programador funciona bem em códigos ad-hoc de prototipagem - mas prefiro ver matemáticos a solução O (1) elegante em código de produção ou em uma API pública. +1 para gnibbler.
Juliet
5
@gnibbler: +1. Nunca percebi que o log10 pode ser usado para encontrar a magnitude de um número. Gostaria de poder votar novamente mais de uma vez :).
Abbas
14
Oi! Eu vou algo estranho, Alguém de você pode me explicar por int(math.log10(x)) +1que 99999999999999999999999999999999999999999999999999999999999999999999999( 71 ) retorna 72 ? Eu pensei que eu poderia contar com método log10, mas eu tenho que usar len (str (x)) em vez :(
Marecky
6
Eu acredito que sei o motivo do comportamento estranho, é devido a imprecisões de ponto flutuante, por exemplo. math.log10(999999999999999)é igual a 14.999999999999998assim int(math.log10(999999999999999))se torna 14. Mas então math.log10(9999999999999999)é igual a 16.0. Talvez o uso roundseja uma solução para esse problema.
amigos estão dizendo sobre jamylak
43

Todas as soluções math.log10 oferecem problemas.

math.log10 é rápido, mas apresenta problemas quando seu número é maior que 999999999999997. Isso ocorre porque o flutuador possui muitos 0,9s, fazendo com que o resultado seja arredondado.

A solução é usar um método contador de tempo para números acima desse limite.

Para tornar isso ainda mais rápido, crie 10 ^ 16, 10 ^ 17 e assim por diante e armazene como variáveis ​​em uma lista. Dessa forma, é como uma pesquisa de tabela.

def getIntegerPlaces(theNumber):
    if theNumber <= 999999999999997:
        return int(math.log10(theNumber)) + 1
    else:
        counter = 15
        while theNumber >= 10**counter:
            counter += 1
        return counter
Calvintwr
fonte
Obrigado. Esse é um bom contra-exemplo para math.log10. É interessante ver como a representação binária inverte os valores, resultando matematicamente incorreto.
WloHu
em seguida, len (str (num)) seria melhor
Vighnesh Raut
2
@Vighnesh Raut: E magnitudes mais lentas
Chaitanya Bangera 15/01
"É perigoso confiar nas operações de ponto flutuante que fornecem resultados exatos" - Mark Dickinson, membro da equipe principal de desenvolvimento do Python bugs.python.org/issue3724
Sreeragh AR
26

Os Python 2.* intusam 4 ou 8 bytes (32 ou 64 bits), dependendo da sua compilação do Python. sys.maxint( 2**31-1para entradas de 32 bits, 2**63-1para entradas de 64 bits) informará qual das duas possibilidades é obtida.

No Python 3, ints (como longs no Python 2) podem levar tamanhos arbitrários até a quantidade de memória disponível; sys.getsizeofdá-lhe uma boa indicação para qualquer valor dado, embora não também contam alguma sobrecarga fixa:

>>> import sys
>>> sys.getsizeof(0)
12
>>> sys.getsizeof(2**99)
28

Se, como outras respostas sugerem, você estiver pensando em alguma representação de string do valor inteiro, basta pegar a lenrepresentação, seja na base 10 ou não!

Alex Martelli
fonte
Desculpe, esta resposta foi diminuída. É informativo e ao ponto plausível da pergunta (se fosse apenas mais específico sobre qual 'len' é desejado). 1
mjv
Isso parece interessante, mas não sei como extrair o comprimento
Tjorriemorrie
17

Faz vários anos desde que essa pergunta foi feita, mas eu compilei uma referência de vários métodos para calcular o comprimento de um número inteiro.

def libc_size(i): 
    return libc.snprintf(buf, 100, c_char_p(b'%i'), i) # equivalent to `return snprintf(buf, 100, "%i", i);`

def str_size(i):
    return len(str(i)) # Length of `i` as a string

def math_size(i):
    return 1 + math.floor(math.log10(i)) # 1 + floor of log10 of i

def exp_size(i):
    return int("{:.5e}".format(i).split("e")[1]) + 1 # e.g. `1e10` -> `10` + 1 -> 11

def mod_size(i):
    return len("%i" % i) # Uses string modulo instead of str(i)

def fmt_size(i):
    return len("{0}".format(i)) # Same as above but str.format

(a função libc requer alguma configuração, que eu não incluí)

size_expé graças a Brian Preslopsky, size_stré graças a GeekTantra, e size_mathé graças a John La Rooy

Aqui estão os resultados:

Time for libc size:      1.2204 μs
Time for string size:    309.41 ns
Time for math size:      329.54 ns
Time for exp size:       1.4902 μs
Time for mod size:       249.36 ns
Time for fmt size:       336.63 ns
In order of speed (fastest first):
+ mod_size (1.000000x)
+ str_size (1.240835x)
+ math_size (1.321577x)
+ fmt_size (1.350007x)
+ libc_size (4.894290x)
+ exp_size (5.976219x)

(Isenção de responsabilidade: a função é executada nas entradas 1 a 1.000.000)

Aqui estão os resultados para sys.maxsize - 100000a sys.maxsize:

Time for libc size:      1.4686 μs
Time for string size:    395.76 ns
Time for math size:      485.94 ns
Time for exp size:       1.6826 μs
Time for mod size:       364.25 ns
Time for fmt size:       453.06 ns
In order of speed (fastest first):
+ mod_size (1.000000x)
+ str_size (1.086498x)
+ fmt_size (1.243817x)
+ math_size (1.334066x)
+ libc_size (4.031780x)
+ exp_size (4.619188x)

Como você pode ver, mod_size( len("%i" % i)) é o mais rápido, um pouco mais rápido que o uso str(i)e significativamente mais rápido que os outros.

Ninguém está aqui
fonte
Você realmente deve incluir a configuração da libc libc = ctyle.CDLL('libc.so.6', use_errno=True)(supondo que seja isso). E não funciona para números maiores do que sys.maxsizeporque os números de ponto flutuante não podem ser "muito grandes". Portanto, qualquer número acima disso, acho que você está preso a um dos métodos mais lentos.
Torxed 27/10/19
15

Seja o número nentão o número de dígitos né dado por:

math.floor(math.log10(n))+1

Observe que isso fornecerá respostas corretas para + ve números inteiros <10e15. Além disso, os limites de precisão do tipo de retorno math.log10entram em ação e a resposta pode ser reduzida em 1. Eu simplesmente usaria len(str(n))além disso; isso requer O(log(n))tempo igual à iteração sobre potências de 10.

Agradeço a @SetiVolkylany por trazer minha atenção a essa limitação. É incrível como as soluções aparentemente corretas têm advertências nos detalhes da implementação.

BiGYaN
fonte
1
Não funciona se n fora do intervalo [-999999999999997, 999999999999997]
PADYMKO
@ SetiVolkylany, eu testei até 50 dígitos para python2.7 e 3.5. Apenas faça um assert list(range(1,51)) == [math.floor(math.log10(n))+1 for n in (10**e for e in range(50))].
BiGYaN
2
tente com o Python2.7 ou o Python3.5 >>> math.floor(math.log10(999999999999997))+1 15.0 >>> math.floor(math.log10(999999999999998))+1 16.0. Veja minha resposta stackoverflow.com/a/42736085/6003870 .
PADYMKO 13/03/19
12

Bem, sem converter em string, eu faria algo como:

def lenDigits(x): 
    """
    Assumes int(x)
    """

    x = abs(x)

    if x < 10:
        return 1

    return 1 + lenDigits(x / 10)

Recursão minimalista FTW

odradek
fonte
1
Você atingirá o limite de recursão para números grandes.
nog642
9

Conte o número de dígitos sem o número inteiro convertido em uma sequência:

x=123
x=abs(x)
i = 0
while x >= 10**i:
    i +=1
# i is the number of digits
novo
fonte
Nice evita completamente a conversão de strings.
Patrick Mutuku 26/10/19
8

Como mencionado o querido usuário @Calvintwr, a função math.log10tem problema em um número fora de um intervalo [-999999999999997, 999999999999997], onde obtemos erros de ponto flutuante. Eu tive esse problema com o JavaScript (o Google V8 e o NodeJS) e o C (o compilador GNU GCC), portanto, uma 'purely mathematically'solução é impossível aqui.


Com base nesta essência e na resposta, o querido usuário @Calvintwr

import math


def get_count_digits(number: int):
    """Return number of digits in a number."""

    if number == 0:
        return 1

    number = abs(number)

    if number <= 999999999999997:
        return math.floor(math.log10(number)) + 1

    count = 0
    while number:
        count += 1
        number //= 10
    return count

Eu testei em números com comprimento de até 20 (inclusive) e tudo bem. Deve ser suficiente, porque o número inteiro máximo do comprimento em um sistema de 64 bits é 19 ( len(str(sys.maxsize)) == 19).

assert get_count_digits(-99999999999999999999) == 20
assert get_count_digits(-10000000000000000000) == 20
assert get_count_digits(-9999999999999999999) == 19
assert get_count_digits(-1000000000000000000) == 19
assert get_count_digits(-999999999999999999) == 18
assert get_count_digits(-100000000000000000) == 18
assert get_count_digits(-99999999999999999) == 17
assert get_count_digits(-10000000000000000) == 17
assert get_count_digits(-9999999999999999) == 16
assert get_count_digits(-1000000000000000) == 16
assert get_count_digits(-999999999999999) == 15
assert get_count_digits(-100000000000000) == 15
assert get_count_digits(-99999999999999) == 14
assert get_count_digits(-10000000000000) == 14
assert get_count_digits(-9999999999999) == 13
assert get_count_digits(-1000000000000) == 13
assert get_count_digits(-999999999999) == 12
assert get_count_digits(-100000000000) == 12
assert get_count_digits(-99999999999) == 11
assert get_count_digits(-10000000000) == 11
assert get_count_digits(-9999999999) == 10
assert get_count_digits(-1000000000) == 10
assert get_count_digits(-999999999) == 9
assert get_count_digits(-100000000) == 9
assert get_count_digits(-99999999) == 8
assert get_count_digits(-10000000) == 8
assert get_count_digits(-9999999) == 7
assert get_count_digits(-1000000) == 7
assert get_count_digits(-999999) == 6
assert get_count_digits(-100000) == 6
assert get_count_digits(-99999) == 5
assert get_count_digits(-10000) == 5
assert get_count_digits(-9999) == 4
assert get_count_digits(-1000) == 4
assert get_count_digits(-999) == 3
assert get_count_digits(-100) == 3
assert get_count_digits(-99) == 2
assert get_count_digits(-10) == 2
assert get_count_digits(-9) == 1
assert get_count_digits(-1) == 1
assert get_count_digits(0) == 1
assert get_count_digits(1) == 1
assert get_count_digits(9) == 1
assert get_count_digits(10) == 2
assert get_count_digits(99) == 2
assert get_count_digits(100) == 3
assert get_count_digits(999) == 3
assert get_count_digits(1000) == 4
assert get_count_digits(9999) == 4
assert get_count_digits(10000) == 5
assert get_count_digits(99999) == 5
assert get_count_digits(100000) == 6
assert get_count_digits(999999) == 6
assert get_count_digits(1000000) == 7
assert get_count_digits(9999999) == 7
assert get_count_digits(10000000) == 8
assert get_count_digits(99999999) == 8
assert get_count_digits(100000000) == 9
assert get_count_digits(999999999) == 9
assert get_count_digits(1000000000) == 10
assert get_count_digits(9999999999) == 10
assert get_count_digits(10000000000) == 11
assert get_count_digits(99999999999) == 11
assert get_count_digits(100000000000) == 12
assert get_count_digits(999999999999) == 12
assert get_count_digits(1000000000000) == 13
assert get_count_digits(9999999999999) == 13
assert get_count_digits(10000000000000) == 14
assert get_count_digits(99999999999999) == 14
assert get_count_digits(100000000000000) == 15
assert get_count_digits(999999999999999) == 15
assert get_count_digits(1000000000000000) == 16
assert get_count_digits(9999999999999999) == 16
assert get_count_digits(10000000000000000) == 17
assert get_count_digits(99999999999999999) == 17
assert get_count_digits(100000000000000000) == 18
assert get_count_digits(999999999999999999) == 18
assert get_count_digits(1000000000000000000) == 19
assert get_count_digits(9999999999999999999) == 19
assert get_count_digits(10000000000000000000) == 20
assert get_count_digits(99999999999999999999) == 20

Todos os exemplos de códigos testados com o Python 3.5

PADYMKO
fonte
3

Para a posteridade, sem dúvida, a solução mais lenta para esse problema:

def num_digits(num, number_of_calls=1):
    "Returns the number of digits of an integer num."
    if num == 0 or num == -1:
        return 1 if number_of_calls == 1 else 0
    else:
        return 1 + num_digits(num/10, number_of_calls+1)
Stefan van den Akker
fonte
2
from math import log10
digits = lambda n: ((n==0) and 1) or int(log10(abs(n)))+1
Robert William Hanks
fonte
1

Supondo que você esteja solicitando o maior número que você pode armazenar em um número inteiro, o valor depende da implementação. Sugiro que você não pense dessa maneira ao usar python. De qualquer forma, um valor bastante grande pode ser armazenado em um python 'número inteiro'. Lembre-se, Python usa digitação de pato!

Edit: Eu dei a minha resposta antes do esclarecimento de que o autor da pergunta queria o número de dígitos. Para isso, concordo com o método sugerido pela resposta aceita. Nada mais a acrescentar!

morcego
fonte
1
def length(i):
  return len(str(i))

fonte
1

Isso pode ser feito para números inteiros rapidamente usando:

len(str(abs(1234567890)))

Que obtém o comprimento da sequência do valor absoluto de "1234567890"

absretorna o número SEM quaisquer negativos (somente a magnitude do número), strconverte / converte em uma sequência e lenretorna o comprimento da sequência.

Se você deseja que ele funcione para carros alegóricos, pode usar um dos seguintes:

# Ignore all after decimal place
len(str(abs(0.1234567890)).split(".")[0])

# Ignore just the decimal place
len(str(abs(0.1234567890)))-1

Para referência futura.

Frogboxe
fonte
Eu acho que seria mais simples para truncar o próprio número de entrada (por exemplo, com um elenco de int) do que para truncar sua representação de seqüência decimal: len(str(abs(int(0.1234567890))))retornos 1.
David Foerster
Não, isso não funcionaria. Se você ativar 0,17 em um número inteiro que você começa 0 eo comprimento do que seria diferente com o comprimento de 0,17
Frogboxe
No primeiro caso, ao truncar tudo de e incluindo o ponto decimal da representação da string, você está efetivamente calculando o comprimento da parte integrante do número, que é o que minha sugestão também faz. Para 0,17 ambas as soluções retornar 1.
David Foerster
0

Formate em notação científica e retire o expoente:

int("{:.5e}".format(1000000).split("e")[1]) + 1

Eu não sei sobre velocidade, mas é simples.

Observe o número de dígitos significativos após o decimal (o "5" no ".5e" pode ser um problema se arredondar a parte decimal da notação científica para outro dígito. Defino-o arbitrariamente grande, mas pode refletir a comprimento do maior número que você conhece.

Brian Preslopsky
fonte
0
def count_digit(number):
  if number >= 10:
    count = 2
  else:
    count = 1
  while number//10 > 9:
    count += 1
    number = number//10
  return count
Del_sama
fonte
Embora esse código possa resolver a questão, incluir uma explicação de como e por que isso resolve o problema realmente ajudaria a melhorar a qualidade da sua postagem e provavelmente resultaria em mais votos positivos. Lembre-se de que você está respondendo à pergunta dos leitores no futuro, não apenas à pessoa que está perguntando agora. Por favor edite sua resposta para adicionar explicações e dar uma indicação do que limitações e premissas se aplicam.
Adrian Mole
0

Se você precisar pedir a um usuário para fornecer informações e, em seguida, contar quantos números existem, poderá seguir o seguinte:

count_number = input('Please enter a number\t')

print(len(count_number))

Nota: nunca use int como entrada do usuário.

Sagar Biswas
fonte
Um caso bastante específico que você descreve aqui, pois está realmente relacionado ao comprimento de uma string. Além disso, eu poderia inserir qualquer caractere não numérico e você ainda acreditaria que é um número.
Ben
0
def digits(n)
    count = 0
    if n == 0:
        return 1
    while (n >= 10**count):
        count += 1
        n += n%10
    return count
print(digits(25))   # Should print 2
print(digits(144))  # Should print 3
print(digits(1000)) # Should print 4
print(digits(0))    # Should print 1
Jahedul Anowar
fonte
0

Meu código para o mesmo é o seguinte; eu usei o método log10:

from math import *

def digit_count (number):

if number>1 and round(log10(number))>=log10(number) and number%10!=0 :
    return round(log10(number))
elif  number>1 and round(log10(number))<log10(number) and number%10!=0:
    return round(log10(number))+1
elif number%10==0 and number!=0:
    return int(log10(number)+1)
elif number==1 or number==0:
    return 1

Eu tive que especificar no caso de 1 e 0 porque log10 (1) = 0 e log10 (0) = ND e, portanto, a condição mencionada não é satisfeita. No entanto, esse código funciona apenas para números inteiros.

Devvrat Chaubal
fonte
0

Aqui está uma versão volumosa, mas rápida:

def nbdigit ( x ):
    if x >= 10000000000000000 : # 17 -
        return len( str( x ))
    if x < 100000000 : # 1 - 8
        if x < 10000 : # 1 - 4
            if x < 100             : return (x >= 10)+1 
            else                   : return (x >= 1000)+3
        else: # 5 - 8                                                 
            if x < 1000000         : return (x >= 100000)+5 
            else                   : return (x >= 10000000)+7
    else: # 9 - 16 
        if x < 1000000000000 : # 9 - 12
            if x < 10000000000     : return (x >= 1000000000)+9 
            else                   : return (x >= 100000000000)+11
        else: # 13 - 16
            if x < 100000000000000 : return (x >= 10000000000000)+13 
            else                   : return (x >= 1000000000000000)+15

Apenas 5 comparações para números não muito grandes. No meu computador, é cerca de 30% mais rápido que a math.log10versão e 5% mais rápido que a versão len( str()). Ok ... não é tão atraente se você não usá-lo furiosamente.

E aqui está o conjunto de números que eu usei para testar / medir minha função:

n = [ int( (i+1)**( 17/7. )) for i in xrange( 1000000 )] + [0,10**16-1,10**16,10**16+1]

NB: não gerencia números negativos, mas a adaptação é fácil ...

Captain'Flam
fonte
-13
>>> a=12345
>>> a.__str__().__len__()
5
ghostdog74
fonte
6
Não chame diretamente métodos especiais. Isso está escrito len(str(a)).
Mike Graham
8
@ ghostdog74 Só porque há uma tomada elétrica, não significa que você precise colocar os dedos nela.
3
então, se você é tão contra, por que não me diz o que há de errado em usá-lo?
ghostdog74
11
Os métodos "Magic" __ existem para que os internos do Python retornem, não para o seu código chamar diretamente. É o padrão do Hollywood Framework: não ligue para nós, nós ligaremos para você. Mas a intenção dessa estrutura é que sejam métodos mágicos para os built-ins padrão do Python usarem, de modo que sua classe possa personalizar o comportamento do built-in. Se for um método para o seu código chamar diretamente, atribua ao método um nome que não seja "__". Isso separa claramente os métodos que se destinam ao consumo do programador, versus os que são fornecidos para retorno de chamada a partir dos recursos internos do Python.
PaulMcG
7
É uma péssima idéia, porque todo mundo no universo conhecido usa str () e len (). Isso é diferente por ser diferente, o que é inerentemente uma coisa ruim - sem mencionar que é apenas feio como o inferno. -1.
Glenn Maynard