Longitud de un entero en Python


233

En Python, ¿cómo encuentras el número de dígitos en un entero?


1
No entiendo tu pregunta. ¿Quiso decir el tamaño de un número entero? ¿Quieres encontrar el número de dígitos? Por favor aclarar
Batbrat

Respuestas:


317

Si desea la longitud de un número entero como el número de dígitos en el número entero, siempre puede convertirlo en una cadena como str(133)y encontrar su longitud como len(str(123)).


18
Por supuesto, si está buscando el número de dígitos, esto producirá un resultado que es demasiado grande para los números negativos, ya que contará el signo negativo.
Chris Upchurch

37
Oye, esta es una solución lenta. Hice un factorial de un número aleatorio de 6 dígitos y encontré su longitud. Este método tardó 95.891 segundos. ¡Y el Math.log10método tomó solo 7.486343383789062e-05 segundos, aproximadamente 1501388 veces más rápido!
FadedCoder

1
Esto no solo es lento, sino que consume mucha más memoria y puede causar problemas en grandes cantidades. utilizar Math.log10en su lugar.
Peyman

246

Sin conversión a cadena

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

Para manejar también números cero y 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 '-' 

Probablemente quieras poner eso en una función :)

Aquí hay algunos puntos de referencia. El len(str())ya está atrasado incluso para números bastante pequeños

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

55
Usar log10 para esto es la solución de un matemático; El uso de len (str ()) es la solución de un programador, y es más claro y simple.
Glenn Maynard

68
@Glenn: Ciertamente espero que no estés implicando que esta es una mala solución. La ingenua solución O (log10 n) del programador funciona bien en código de creación de prototipos ad-hoc, pero preferiría ver la elegante solución O (1) de matemáticos en código de producción o API pública. +1 para gnibbler.
Julieta

55
@gnibbler: +1. Nunca me di cuenta de que log10 se puede usar para encontrar la magnitud de un número. Ojalá pudiera votar más de una vez :).
Abbas

14
¡Hola! Voy algo extraño, ¿alguien de ustedes puede explicarme por qué int(math.log10(x)) +1para 99999999999999999999999999999999999999999999999999999999999999999999999( 71 nueves ) devuelve 72 ? Pensé que podía confiar en el método log10, pero tengo que usar len (str (x)) en su lugar :(
Marecky

66
Creo que sé la razón del extraño comportamiento, se debe a imprecisiones de coma flotante, por ejemplo. math.log10(999999999999999)es igual a 14.999999999999998lo que se int(math.log10(999999999999999))hace 14. Pero entonces math.log10(9999999999999999)es igual a 16.0. Quizás usar roundes una solución a este problema.
jamylak

43

Todas las soluciones de math.log10 te darán problemas.

math.log10 es rápido pero da problemas cuando su número es mayor que 999999999999997. Esto se debe a que el flotador tiene demasiados .9s, lo que hace que el resultado se redondee.

La solución es usar un método contador de tiempo para números por encima de ese umbral.

Para hacer esto aún más rápido, cree 10 ^ 16, 10 ^ 17, etc., y almacénelos como variables en una lista. De esa manera, es como una búsqueda en la mesa.

def getIntegerPlaces(theNumber):
    if theNumber <= 999999999999997:
        return int(math.log10(theNumber)) + 1
    else:
        counter = 15
        while theNumber >= 10**counter:
            counter += 1
        return counter

Gracias. Ese es un buen contraejemplo para math.log10. Es interesante ver cómo la representación binaria voltea los valores dando resultados matemáticamente incorrectos.
WloHu

entonces len (str (num)) sería mejor
Vighnesh Raut

2
@Vighnesh Raut: Y las magnitudes son más lentas
Chaitanya Bangera

"Es peligroso confiar en operaciones de punto flotante que dan resultados exactos" - Mark Dickinson, miembro del equipo central de desarrollo de Python bugs.python.org/issue3724
Sreeragh AR

26

Python 2.* inttoma 4 u 8 bytes (32 o 64 bits), dependiendo de su construcción Python. sys.maxint( 2**31-1para entradas de 32 bits, 2**63-1para entradas de 64 bits) le indicará cuál de las dos posibilidades obtiene.

En Python 3, ints (como longs en Python 2) puede tomar tamaños arbitrarios hasta la cantidad de memoria disponible; sys.getsizeofle da una indicación bueno para cualquier valor dado, a pesar de que no cuentan también algo de sobrecarga fija:

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

Si, como sugieren otras respuestas, está pensando en alguna representación de cadena del valor entero, simplemente tome lenesa representación, ya sea en la base 10 o de lo contrario.


Lo siento, esta respuesta tiene menos ed. Es informativo y hasta el punto plausible de la pregunta (si fuera más específico sobre qué 'len' se desea). +1
mjv

Esto parece interesante pero no está seguro de cómo extraer la longitud
Tjorriemorrie

17

Han pasado varios años desde que se hizo esta pregunta, pero he compilado una referencia de varios métodos para calcular la longitud de un número entero.

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

(la función libc requiere cierta configuración, que no he incluido)

size_expes gracias a Brian Preslopsky, size_stres gracias a GeekTantra, y size_mathes gracias a John La Rooy

Aquí están los 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)

(Descargo de responsabilidad: la función se ejecuta en las entradas 1 a 1,000,000)

Aquí están los resultados de 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 puede ver, mod_size( len("%i" % i)) es el más rápido, un poco más rápido que el uso str(i)y significativamente más rápido que otros.


Realmente deberías incluir la configuración de libc, libc = ctyle.CDLL('libc.so.6', use_errno=True)(supongo que esto es todo). Y no funciona para números mayores que sys.maxsizeporque los números de coma flotante no pueden ser "muy grandes". Entonces, cualquier número por encima de eso, supongo que estás atrapado con uno de los métodos más lentos.
Torxed

15

Sea el número, nentonces el número de dígitos nestá dado por:

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

Tenga en cuenta que esto dará respuestas correctas para + ve enteros <10e15. Más allá de eso, los límites de precisión del tipo de retorno de math.log10patadas y la respuesta pueden estar apagados en 1. Simplemente usaría len(str(n))más allá de eso; esto requiere O(log(n))tiempo, lo mismo que iterar sobre potencias de 10.

Gracias a @SetiVolkylany por llevar mi atención a esta limitación. Es sorprendente cómo las soluciones aparentemente correctas tienen advertencias en los detalles de implementación.


1
No funciona si n está fuera del rango [-999999999999997, 999999999999997]
PADYMKO

@SetiVolkylany, lo probé hasta 50 dígitos para python2.7 y 3.5. Solo haz un assert list(range(1,51)) == [math.floor(math.log10(n))+1 for n in (10**e for e in range(50))].
BiGYaN

2
pruébelo con Python2.7 o Python3.5 >>> math.floor(math.log10(999999999999997))+1 15.0 >>> math.floor(math.log10(999999999999998))+1 16.0. Mira mi respuesta stackoverflow.com/a/42736085/6003870 .
PADYMKO

12

Bueno, sin convertirme en cadena, haría algo como:

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

    x = abs(x)

    if x < 10:
        return 1

    return 1 + lenDigits(x / 10)

Recursividad minimalista FTW


1
Alcanzará el límite de recursión para grandes números.
nog642

9

Cuente el número de dígitos sin convertir enteros en una cadena:

x=123
x=abs(x)
i = 0
while x >= 10**i:
    i +=1
# i is the number of digits

Nice one evita la conversión de cadenas por completo.
Patrick Mutuku

8

Como mencionó el querido usuario @Calvintwr, la función math.log10tiene un problema en un número fuera de un rango [-999999999999997, 999999999999997], donde obtenemos errores de coma flotante. Tuve este problema con JavaScript (Google V8 y NodeJS) y C (el compilador GNU GCC), por lo que una 'purely mathematically'solución es imposible aquí.


Basado en esta esencia y la respuesta, el querido usuario @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

Lo probé en números con una longitud de hasta 20 (inclusive) y todo bien. Debe ser suficiente, porque el número entero máximo de longitud en un sistema de 64 bits es 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 los ejemplos de códigos probados con Python 3.5


3

Para la posteridad, sin duda, la solución más lenta a este problema es:

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)


1

Suponiendo que está solicitando el mayor número que puede almacenar en un entero, el valor depende de la implementación. Sugiero que no pienses de esa manera cuando uses Python. En cualquier caso, se puede almacenar un valor bastante grande en un 'entero' de Python. ¡Recuerde, Python usa la escritura de pato!

Editar: Di mi respuesta antes de la aclaración de que el autor de la pregunta quería el número de dígitos. Para eso, estoy de acuerdo con el método sugerido por la respuesta aceptada. ¡Nada más que agregar!


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

1

Se puede hacer para enteros rápidamente usando:

len(str(abs(1234567890)))

Que obtiene la longitud de la cadena del valor absoluto de "1234567890"

absdevuelve el número SIN negativos (solo la magnitud del número), lo strconvierte / convierte en una cadena y lendevuelve la longitud de la cadena de esa cadena.

Si desea que funcione para flotadores, puede utilizar cualquiera de los siguientes:

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

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

Para futura referencia.


Creo que sería más simple truncar el número de entrada en sí (p. Ej., Con una conversión a int) que truncar su representación de cadena decimal: len(str(abs(int(0.1234567890))))devuelve 1.
David Foerster

No, eso no funcionaría. Si convierte 0.17 en un número entero, obtiene 0 y su longitud sería diferente a la longitud de 0.17
Frogboxe

En el primer caso, al truncar todo e incluir el punto decimal de la representación de cadena, está calculando efectivamente la longitud de la parte integral del número, que es lo que hace mi sugerencia también. Para 0.17 ambas soluciones devuelven 1.
David Foerster

0

Formatear en notación científica y extraer el exponente:

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

No sé acerca de la velocidad, pero es simple.

Tenga en cuenta el número de dígitos significativos después del decimal (el "5" en el ".5e" puede ser un problema si redondea la parte decimal de la notación científica a otro dígito. Lo configuré arbitrariamente grande, pero podría reflejar el longitud del mayor número que conoces.


0
def count_digit(number):
  if number >= 10:
    count = 2
  else:
    count = 1
  while number//10 > 9:
    count += 1
    number = number//10
  return count

Si bien este código puede resolver la pregunta, incluir una explicación de cómo y por qué esto resuelve el problema realmente ayudaría a mejorar la calidad de su publicación, y probablemente resultaría en más votos positivos. Recuerde que está respondiendo la pregunta para los lectores en el futuro, no solo la persona que pregunta ahora. Por favor, editar su respuesta para agregar explicaciones y dar una indicación de lo que se aplican limitaciones y supuestos.
Adrian Mole

0

Si tiene que pedirle a un usuario que dé su opinión y luego debe contar cuántos números hay, puede seguir esto:

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

print(len(count_number))

Nota: Nunca tome un int como entrada del usuario.


Aquí se describe un caso bastante específico, ya que en realidad está relacionado con la longitud de una cadena. Además, podría ingresar cualquier carácter no numérico y aún creería que es un 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

0

Mi código para el mismo es el siguiente; he usado el método log10:

from math import *

def digit_count (número):

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

Tuve que especificar en el caso de 1 y 0 porque log10 (1) = 0 y log10 (0) = ND y, por lo tanto, la condición mencionada no se cumple. Sin embargo, este código solo funciona para números enteros.


0

Aquí hay una versión voluminosa pero 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

Solo 5 comparaciones para números no demasiado grandes. En mi computadora es aproximadamente un 30% más rápido que la math.log10versión y un 5% más rápido que la versión len( str()). Ok ... no tan atractivo si no lo usas furiosamente.

Y aquí está el conjunto de números que usé para probar / medir mi función:

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

NB: no maneja números negativos, pero la adaptación es fácil ...


-13
>>> a=12345
>>> a.__str__().__len__()
5

66
No llame directamente a métodos especiales. Eso esta escrito len(str(a)).
Mike Graham

8
@ ghostdog74 El hecho de que haya una toma de corriente no significa que tenga que meter los dedos en ella.

3
así que si estás tan en contra, ¿por qué no me dices qué hay de malo en usarlo?
ghostdog74

11
Los métodos "mágicos" están allí para que los internos de Python vuelvan a llamar, no para que su código llame directamente. Es el patrón de Hollywood Framework: no nos llames, te llamaremos. Pero la intención de este marco es que estos son métodos mágicos para que los incorporados en Python estándar utilicen, de modo que su clase pueda personalizar el comportamiento del incorporado. Si es un método para que su código llame directamente, asigne al método un nombre que no sea "__". Esto separa claramente los métodos que están destinados al consumo del programador, en comparación con los que se proporcionan para la devolución de llamada de Python incorporado.
PaulMcG

77
Es una mala idea porque todos los demás en el universo conocido usan str () y len (). Esto es ser diferente en aras de ser diferente, lo cual es inherentemente algo malo, sin mencionar que es feo como el infierno. -1.
Glenn Maynard
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.