web-dev-qa-db-fra.com

Longueur d'un entier en Python

En Python, comment trouvez-vous le nombre de chiffres dans un entier?

169
Strigoides

Si vous voulez que la longueur d'un entier corresponde au nombre de chiffres qu'il contient, vous pouvez toujours le convertir en chaîne telle que str(133) et trouver sa longueur comme len(str(123))

220
GeekTantra

Sans conversion en chaîne

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

Pour gérer également les nombres zéro et négatifs

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 '-' 

Vous voudrez probablement mettre cela dans une fonction :)

Voici quelques repères. len(str()) est déjà en retard, même pour des nombres assez petits 

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
181
John La Rooy

Toutes les solutions math.log10 vous poseront des problèmes.

math.log10 est rapide mais pose problème lorsque votre nombre est supérieur à 999999999999997. Cela est dû au fait que le nombre flottant contient trop de valeurs.

La solution consiste à utiliser une méthode de compteur de temps pour les nombres supérieurs à ce seuil.

Pour rendre cela encore plus rapide, créez 10 ^ 16, 10 ^ 17 etc. ainsi de suite et stockez-les sous forme de variables dans une liste. De cette façon, cela ressemble à une consultation de table.

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

Python 2.*ints prend 4 ou 8 octets (32 ou 64 bits), en fonction de votre construction Python. sys.maxint (2**31-1 pour les ints 32 bits, 2**63-1 pour les ints 64 bits) vous indiquera laquelle des deux possibilités est obtenue.

Dans Python 3, ints (comme longs dans Python 2) peut prendre des tailles arbitraires allant jusqu'à la quantité de mémoire disponible; sys.getsizeof vous donne une bonne indication pour toute valeur donnée, bien qu'il compte compte également une surcharge fixe:

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

Si, comme le suggèrent d'autres réponses, vous songez à une représentation sous forme de chaîne de la valeur entière, prenez simplement la variable len de cette représentation, que ce soit en base 10 ou autrement!

20
Alex Martelli

Soit le nombre n alors le nombre de chiffres dans n est donné par:

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

Notez que cela donnera des réponses correctes pour les nombres entiers supérieurs <10e15. Au-delà de cela, la limite de précision du type de retour de math.log10 commence et la réponse peut être décalée de 1. J'utiliserais simplement len(str(n)) au-delà; Cela nécessite O(log(n)) time, ce qui est identique à une itération sur des puissances de 10.

Merci à @SetiVolkylany d’avoir attiré mon attention sur cette limitation. Il est étonnant de voir à quel point les solutions apparemment correctes comportent des réserves quant aux détails de la mise en œuvre.

13
BiGYaN

Eh bien, sans convertir en chaîne, je ferais quelque chose comme:

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

    x = abs(x)

    if x < 10:
        return 1

    return 1 + lenDigits(x / 10)

Récursion minimaliste FTW

11
odradek

Comme mentionné le cher utilisateur @Calvintwr, la fonction math.log10 a un problème dans un nombre en dehors d'une plage [-999999999999997, 999999999999997], où nous obtenons des erreurs en virgule flottante. J'ai eu ce problème avec JavaScript (Google V8 et NodeJS) et C (le compilateur GNU GCC), de sorte qu'une solution 'purely mathematically' est impossible ici.


Basé sur ceci Gist et la réponse le cher utilisateur @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

Je l'ai testé sur des nombres allant jusqu'à 20 (inclus) et tout va bien. Cela doit être suffisant, car le nombre entier max de longueur sur un système 64 bits est 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

Tous les exemples de codes testés avec Python 3.5

5
Seti Volkylany

Pour la postérité, la solution la plus lente à ce problème est sans doute la plus lente:

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)
3

Cela fait plusieurs années que cette question a été posée, mais j'ai compilé un point de repère de plusieurs méthodes pour calculer la longueur d'un entier. 

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

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

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

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

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

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

(la fonction libc nécessite une configuration que je n'ai pas incluse)

size_exp grâce à Brian Preslopsky, size_str grâce à GeekTantra et size_math grâce à John La Rooy

Voici les résultats:

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)

(Avertissement: la fonction est exécutée sur les entrées 1 à 1 000 000)

Voici les résultats pour sys.maxsize - 100000 à 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)

Comme vous pouvez le constater, mod_size (len("%i" % i)) est le plus rapide, légèrement plus rapide que l’utilisation de str(i) et nettement plus rapide que d’autres.

3
NoOneIsHere
from math import log10
digits = lambda n: ((n==0) and 1) or int(log10(abs(n)))+1
2

Cela peut être fait rapidement pour les entiers en utilisant:

len(str(abs(1234567890)))

Qui obtient la longueur de la chaîne de la valeur absolue de "1234567890"

abs renvoie le nombre SANS aucun négatif (seulement la magnitude du nombre), str le convertit/le convertit en chaîne et len renvoie la longueur de chaîne de cette chaîne.

Si vous souhaitez que cela fonctionne pour les flotteurs, vous pouvez utiliser l’un des éléments suivants:

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

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

Pour référence future.

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

En supposant que vous demandiez le plus grand nombre que vous puissiez stocker dans un entier, la valeur dépend de la mise en œuvre. Je suggère que vous ne pensiez pas de cette façon lorsque vous utilisez python. Dans tous les cas, une valeur assez grande peut être stockée dans un "entier" python. N'oubliez pas que Python utilise la frappe au canard!

Edit: J'ai donné ma réponse avant la clarification que le demandeur voulait le nombre de chiffres. Pour cela, je suis d’accord avec la méthode suggérée par la réponse acceptée. Rien de plus à ajouter!

1
batbrat

Formater en notation scientifique et arracher l’exposant:

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

Je ne connais pas la vitesse, mais c'est simple. 

Veuillez noter le nombre de chiffres significatifs après la décimale (le "5" dans le ".5e" peut poser problème si la partie décimale de la notation scientifique est arrondie à un autre chiffre. longueur du plus grand nombre que vous connaissez. 

0
Brian Preslopsky

Comptez le nombre de chiffres sans convertir un entier en chaîne:

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