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)).
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))+1elif n ==0:
digits =1else:
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
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.
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:
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!
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 stringdef math_size(i):return1+ math.floor(math.log10(i))# 1 + floor of log10 of idef exp_size(i):return int("{:.5e}".format(i).split("e")[1])+1# e.g. `1e10` -> `10` + 1 -> 11def 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:
Timefor libc size:1.2204μs
Timefor string size:309.41 ns
Timefor math size:329.54 ns
Timefor exp size:1.4902μs
Timefor mod size:249.36 ns
Timefor 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:
Timefor libc size:1.4686μs
Timefor string size:395.76 ns
Timefor math size:485.94 ns
Timefor exp size:1.6826μs
Timefor mod size:364.25 ns
Timefor 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.
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.
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:return1return1+ lenDigits(x /10)
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.
import math
def get_count_digits(number: int):"""Return number of digits in a number."""if number ==0:return1
number = abs(number)if number <=999999999999997:return math.floor(math.log10(number))+1
count =0while number:
count +=1
number //=10return 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).
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 ==0or num ==-1:return1if number_of_calls ==1else0else:return1+ num_digits(num/10, number_of_calls+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!
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
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.
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))
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 =0if n ==0:return1while(n >=10**count):
count +=1
n += n%10return count
print(digits(25))# Should print 2print(digits(144))# Should print 3print(digits(1000))# Should print 4print(digits(0))# Should print 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.
def nbdigit ( x ):if x >=10000000000000000:# 17 -return len( str( x ))if x <100000000:# 1 - 8if x <10000:# 1 - 4if x <100:return(x >=10)+1else:return(x >=1000)+3else:# 5 - 8 if x <1000000:return(x >=100000)+5else:return(x >=10000000)+7else:# 9 - 16 if x <1000000000000:# 9 - 12if x <10000000000:return(x >=1000000000)+9else:return(x >=100000000000)+11else:# 13 - 16if x <100000000000000:return(x >=10000000000000)+13else: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 ...
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.
Respostas:
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 comolen(str(123))
.fonte
Math.log10
método levou apenas 7,486343383789062e-05 segundos, aproximadamente 1501388 vezes mais rápido!Math.log10
vez disso.Sem conversão para string
Para também lidar com números zero e negativos
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úmerosfonte
int(math.log10(x)) +1
que99999999999999999999999999999999999999999999999999999999999999999999999
( 71 ) retorna 72 ? Eu pensei que eu poderia contar com método log10, mas eu tenho que usar len (str (x)) em vez :(math.log10(999999999999999)
é igual a14.999999999999998
assimint(math.log10(999999999999999))
se torna14
. Mas entãomath.log10(9999999999999999)
é igual a16.0
. Talvez o usoround
seja uma solução para esse problema.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.
fonte
math.log10
. É interessante ver como a representação binária inverte os valores, resultando matematicamente incorreto.Os Python
2.*
int
usam 4 ou 8 bytes (32 ou 64 bits), dependendo da sua compilação do Python.sys.maxint
(2**31-1
para entradas de 32 bits,2**63-1
para entradas de 64 bits) informará qual das duas possibilidades é obtida.No Python 3,
int
s (comolong
s no Python 2) podem levar tamanhos arbitrários até a quantidade de memória disponível;sys.getsizeof
dá-lhe uma boa indicação para qualquer valor dado, embora não também contam alguma sobrecarga fixa:Se, como outras respostas sugerem, você estiver pensando em alguma representação de string do valor inteiro, basta pegar a
len
representação, seja na base 10 ou não!fonte
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.
(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, esize_math
é graças a John La RooyAqui estão os resultados:
(Isenção de responsabilidade: a função é executada nas entradas 1 a 1.000.000)
Aqui estão os resultados para
sys.maxsize - 100000
asys.maxsize
:Como você pode ver,
mod_size
(len("%i" % i)
) é o mais rápido, um pouco mais rápido que o usostr(i)
e significativamente mais rápido que os outros.fonte
libc = ctyle.CDLL('libc.so.6', use_errno=True)
(supondo que seja isso). E não funciona para números maiores do quesys.maxsize
porque 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.Seja o número
n
então o número de dígitosn
é dado por: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.log10
entram em ação e a resposta pode ser reduzida em 1. Eu simplesmente usarialen(str(n))
além disso; isso requerO(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.
fonte
assert list(range(1,51)) == [math.floor(math.log10(n))+1 for n in (10**e for e in range(50))]
.>>> math.floor(math.log10(999999999999997))+1 15.0 >>> math.floor(math.log10(999999999999998))+1 16.0
. Veja minha resposta stackoverflow.com/a/42736085/6003870 .Bem, sem converter em string, eu faria algo como:
Recursão minimalista FTW
fonte
Conte o número de dígitos sem o número inteiro convertido em uma sequência:
fonte
Como mencionado o querido usuário @Calvintwr, a função
math.log10
tem 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
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
).Todos os exemplos de códigos testados com o Python 3.5
fonte
Para a posteridade, sem dúvida, a solução mais lenta para esse problema:
fonte
fonte
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!
fonte
fonte
Isso pode ser feito para números inteiros rapidamente usando:
Que obtém o comprimento da sequência do valor absoluto de "1234567890"
abs
retorna o número SEM quaisquer negativos (somente a magnitude do número),str
converte / converte em uma sequência elen
retorna o comprimento da sequência.Se você deseja que ele funcione para carros alegóricos, pode usar um dos seguintes:
Para referência futura.
fonte
int
) do que para truncar sua representação de seqüência decimal:len(str(abs(int(0.1234567890))))
retornos 1.Formate em notação científica e retire o expoente:
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.
fonte
fonte
Se você precisar pedir a um usuário para fornecer informações e, em seguida, contar quantos números existem, poderá seguir o seguinte:
Nota: nunca use int como entrada do usuário.
fonte
fonte
Meu código para o mesmo é o seguinte; eu usei o método log10:
def digit_count (number):
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.
fonte
Aqui está uma versão volumosa, mas rápida:
Apenas 5 comparações para números não muito grandes. No meu computador, é cerca de 30% mais rápido que a
math.log10
versão e 5% mais rápido que a versãolen( 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:
NB: não gerencia números negativos, mas a adaptação é fácil ...
fonte
fonte
len(str(a))
.