Longueur d'un entier en Python

233

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

Strigoides
la source
1
Je ne comprends pas ta question. Voulez-vous dire la taille d'un entier? Voulez-vous trouver le nombre de chiffres? Précisez s'il vous plaît.
batbrat

Réponses:

317

Si vous voulez la longueur d'un entier comme dans le nombre de chiffres de l'entier, vous pouvez toujours le convertir en chaîne comme str(133)et trouver sa longueur comme len(str(123)).

GeekTantra
la source
18
Bien sûr, si vous recherchez le nombre de chiffres, cela produira un résultat trop grand pour les nombres négatifs, car il comptera le signe négatif.
Chris Upchurch
37
Hé, c'est une solution lente. J'ai fait une factorielle d'un nombre aléatoire à 6 chiffres et trouvé sa longueur. Cette méthode a pris 95,891 secondes. Et la Math.log10méthode n'a pris que 7.486343383789062e-05 secondes, environ 1501388 fois plus rapide!
FadedCoder
1
Ce n'est pas seulement lent, mais consomme beaucoup plus de mémoire et peut causer des problèmes en grand nombre. utiliser à la Math.log10place.
Peyman
246

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 voudriez probablement mettre cela dans une fonction :)

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

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
la source
5
Utiliser log10 pour cela est une solution de mathématicien; l'utilisation de len (str ()) est une solution de programmeur, plus claire et plus simple.
Glenn Maynard
68
@Glenn: J'espère certainement que vous n'impliquez pas que c'est une mauvaise solution. La solution naïve O (log10 n) du programmeur fonctionne bien dans le code de prototypage ad hoc - mais je préfère de loin voir la solution O (1) élégante des mathématiciens dans le code de production ou une API publique. +1 pour grignoteur.
Juliet
5
@ grignoteur: +1. Jamais réalisé que log10 peut être utilisé pour trouver la grandeur d'un nombre. J'aimerais pouvoir voter plus d'une fois :).
Abbas
14
Salut! Je fais quelque chose d'étrange, est-ce que n'importe qui d'entre vous peut m'expliquer pourquoi int(math.log10(x)) +1pour 99999999999999999999999999999999999999999999999999999999999999999999999( 71 neuf ) renvoie 72 ? Je pensais que je pouvais compter sur la méthode log10 mais je dois utiliser len (str (x)) à la place :(
Marecky
6
Je crois que je connais la raison de ce comportement étrange, il est dû à des inexactitudes en virgule flottante, par exemple. math.log10(999999999999999)est égal à devient 14.999999999999998ainsi . Mais alors est égal à . Peut-être que l'utilisation est une solution à ce problème. int(math.log10(999999999999999))14math.log10(9999999999999999)16.0round
jamylak
43

Toutes les solutions de 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 flotteur a trop de 0,9, provoquant l'arrondi du résultat.

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

Pour rendre cela encore plus rapide, créez 10 ^ 16, 10 ^ 17 ainsi de suite et stockez-les sous forme de variables dans une liste. De cette façon, c'est comme une recherche 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
Calvintwr
la source
Je vous remercie. C'est un bon contre-exemple pour math.log10. Il est intéressant de voir comment la représentation binaire retourne les valeurs donnant un résultat mathématiquement incorrect.
WloHu
alors len (str (num)) serait mieux
Vighnesh Raut
2
@Vighnesh Raut: Et les amplitudes plus lentes
Chaitanya Bangera
"Il est dangereux de s'appuyer sur des opérations en virgule flottante pour obtenir des résultats exacts" - Mark Dickinson, membre de l'équipe de développement Python principale bugs.python.org/issue3724
Sreeragh AR
26

Les Python 2.* intprennent 4 ou 8 octets (32 ou 64 bits), selon votre build Python. sys.maxint( 2**31-1pour les 32 bits, 2**63-1pour les 64 bits) vous dira laquelle des deux possibilités obtient.

En Python 3, ints (comme longs en Python 2) peut prendre des tailles arbitraires jusqu'à la quantité de mémoire disponible; sys.getsizeofvous donne une bonne indication pour une valeur donnée, même si elle ne compte aussi des frais généraux fixes:

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

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

Alex Martelli
la source
Désolé, cette réponse a été réduite. Elle est informative et va dans le sens plausible de la question (si elle n'était que plus précise sur le «len» souhaité). +1
mjv
Cela semble intéressant mais
je
17

Cela fait plusieurs années que cette question a été posée, mais j'ai compilé une référence de plusieurs méthodes pour calculer la longueur d'un entier.

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 fonction libc nécessite une configuration, que je n'ai pas incluse)

size_expmerci à Brian Preslopsky, size_strmerci à GeekTantra et size_mathmerci à 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 voir, mod_size( len("%i" % i)) est le plus rapide, légèrement plus rapide que l'utilisation str(i)et nettement plus rapide que les autres.

Il n'y a personne
la source
Vous devriez vraiment inclure la configuration de la libc, libc = ctyle.CDLL('libc.so.6', use_errno=True)(devinant que c'est tout). Et cela ne fonctionne pas pour les nombres supérieurs à sys.maxsizeparce que les nombres à virgule flottante ne peuvent pas être "très grands". Donc, tout nombre supérieur à cela, je suppose que vous êtes coincé avec l'une des méthodes les plus lentes.
Torxed
15

Soit le nombre nalors le nombre de chiffres nest donné par:

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

Notez que cela donnera des réponses correctes pour les entiers + ve <10e15. Au-delà de cela, les limites de précision du type de retour de math.log10coups de pied et la réponse peuvent être désactivées par 1. Je voudrais simplement utiliser len(str(n))au-delà de cela; cela nécessite du O(log(n))temps qui équivaut à itérer sur des puissances de 10.

Merci à @SetiVolkylany d'avoir apporté mon attention à cette limitation. Il est étonnant de constater à quel point les solutions apparemment correctes comportent des avertissements dans les détails de mise en œuvre.

BiGYaN
la source
1
Cela ne fonctionne pas si n en dehors de la plage [-999999999999997, 999999999999997]
PADYMKO
@SetiVolkylany, je l'ai testé jusqu'à 50 chiffres pour python2.7 et 3.5. Faites juste un assert list(range(1,51)) == [math.floor(math.log10(n))+1 for n in (10**e for e in range(50))].
BiGYaN
2
essayez-le avec Python2.7 ou Python3.5 >>> math.floor(math.log10(999999999999997))+1 15.0 >>> math.floor(math.log10(999999999999998))+1 16.0. Regardez ma réponse stackoverflow.com/a/42736085/6003870 .
PADYMKO
12

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)

FTW récursivité minimaliste

odradek
la source
1
Vous atteindrez la limite de récursivité pour les grands nombres.
nog642
9

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

x=123
x=abs(x)
i = 0
while x >= 10**i:
    i +=1
# i is the number of digits
datanew
la source
Nice on évite complètement la conversion de chaîne.
Patrick Mutuku
8

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


Sur la base de cet essentiel et de 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 numéros jusqu'à 20 (inclus) et très bien. Cela doit être suffisant, car le nombre entier de longueur maximale 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

PADYMKO
la source
3

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

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
la source
2
from math import log10
digits = lambda n: ((n==0) and 1) or int(log10(abs(n)))+1
Robert William Hanks
la source
1

En supposant que vous demandez le plus grand nombre que vous pouvez stocker dans un entier, la valeur dépend de l'implémentation. Je suggère que vous ne pensiez pas de cette façon lorsque vous utilisez python. Dans tous les cas, une valeur assez importante peut être stockée dans un «entier» python. Rappelez-vous, Python utilise la frappe de 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!

batbrat
la source
1
def length(i):
  return len(str(i))

la source
1

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

len(str(abs(1234567890)))

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

absrenvoie le nombre SANS aucun négatif (uniquement l'amplitude du nombre), le strconvertit / convertit en chaîne et lenrenvoie la longueur de chaîne de cette chaîne.

Si vous souhaitez qu'il fonctionne pour les flottants, vous pouvez utiliser l'une des méthodes suivantes:

# 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.

Frogboxe
la source
Je pense qu'il serait plus simple de tronquer le numéro d'entrée lui-même (par exemple avec un transtypage en int) que de tronquer sa représentation de chaîne décimale: len(str(abs(int(0.1234567890))))renvoie 1.
David Foerster
Non, ça ne marcherait pas. Si vous transformez 0,17 en entier, vous obtenez 0 et la longueur de celui-ci serait différente de la longueur de 0,17
Frogboxe
Dans le premier cas, en tronquant tout à partir de la représentation sous forme de chaîne et en l'incluant, vous calculez effectivement la longueur de la partie intégrante du nombre, ce que fait également ma suggestion. Pour 0,17, les deux solutions renvoient 1.
David Foerster
0

Format 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 être un problème s'il arrondit la partie décimale de la notation scientifique à un autre chiffre. Je l'ai défini arbitrairement grand, mais pourrait refléter le longueur du plus grand nombre que vous connaissez.

Brian Preslopsky
la source
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
la source
Bien que ce code puisse résoudre la question, y compris une explication de comment et pourquoi cela résout le problème aiderait vraiment à améliorer la qualité de votre message, et entraînerait probablement plus de votes positifs. N'oubliez pas que vous répondrez à la question aux lecteurs à l'avenir, pas seulement à la personne qui pose la question maintenant. Veuillez modifier votre réponse pour ajouter des explications et donner une indication des limitations et hypothèses applicables.
Adrian Mole
0

Si vous devez demander à un utilisateur de donner une entrée et que vous devez ensuite compter le nombre de numéros, vous pouvez suivre ceci:

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

print(len(count_number))

Remarque: Ne prenez jamais un int comme entrée utilisateur.

Sagar Biswas
la source
Un cas assez spécifique que vous décrivez ici car il est en fait lié à la longueur d'une chaîne. De plus, je pourrais entrer n'importe quel caractère non numérique et vous croiriez toujours qu'il s'agit d'un nombre.
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
la source
0

Mon code pour le même est le suivant; j'ai utilisé la méthode log10:

from math import *

def digit_count (nombre):

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

J'ai dû spécifier en cas de 1 et 0 car log10 (1) = 0 et log10 (0) = ND et donc la condition mentionnée n'est pas remplie. Cependant, ce code ne fonctionne que pour les nombres entiers.

Devvrat Chaubal
la source
0

Voici une version volumineuse mais rapide:

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

Seulement 5 comparaisons pour des nombres pas trop grands. Sur mon ordinateur, elle est environ 30% plus rapide que la math.log10version et 5% plus rapide que len( str())celle. Ok ... pas si attrayant si vous ne l'utilisez pas furieusement.

Et voici l'ensemble de nombres que j'ai utilisé pour tester / mesurer ma fonction:

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

NB: il ne gère pas les nombres négatifs, mais l'adaptation est facile ...

Captain'Flam
la source
-13
>>> a=12345
>>> a.__str__().__len__()
5
ghostdog74
la source
6
N'appelez pas directement des méthodes spéciales. C'est écrit len(str(a)).
Mike Graham
8
@ ghostdog74 Ce n'est pas parce qu'il y a une prise électrique que vous devez y mettre les doigts.
3
donc si vous êtes contre, pourquoi ne me dites-vous pas ce qui ne va pas avec ça?
ghostdog74
11
Les méthodes "magiques" __ sont là pour que les internes de Python puissent rappeler, pas pour que votre code appelle directement. C'est le modèle Hollywood Framework: ne nous appelez pas, nous vous appellerons. Mais l'intention de ce cadre est que ce sont des méthodes magiques pour les intégrées Python standard à utiliser, afin que votre classe puisse personnaliser le comportement de l'intégration. Si c'est une méthode que votre code appelle directement, donnez à la méthode un nom différent de "__". Cela sépare clairement les méthodes qui sont destinées à la consommation du programmeur, par rapport à celles qui sont fournies pour le rappel des fonctionnalités intégrées de Python.
PaulMcG
7
C'est une mauvaise idée car tout le monde dans l'univers connu utilise str () et len ​​(). C'est différent pour le plaisir d'être différent, ce qui est intrinsèquement une mauvaise chose - sans compter que c'est tout simplement laid comme l'enfer. -1.
Glenn Maynard