Länge einer Ganzzahl in Python


231

Wie finden Sie in Python die Anzahl der Stellen in einer Ganzzahl?


1
Ich verstehe deine Frage nicht. Meinten Sie die Größe einer ganzen Zahl? Möchten Sie die Anzahl der Ziffern ermitteln? Bitte klären Sie.
Batbrat

Antworten:


316

Wenn Sie die Länge einer Ganzzahl wie die Anzahl der Stellen in der Ganzzahl angeben möchten, können Sie sie jederzeit in eine Zeichenfolge wie konvertieren str(133)und ihre Länge wie finden len(str(123)).


18
Wenn Sie nach der Anzahl der Ziffern suchen, führt dies natürlich zu einem Ergebnis, das für negative Zahlen zu groß ist, da das negative Vorzeichen gezählt wird.
Chris Upchurch

37
Hey, das ist eine langsame Lösung. Ich habe eine Fakultät mit einer zufälligen 6-stelligen Zahl erstellt und deren Länge gefunden. Diese Methode dauerte 95,891 Sekunden. Und die Math.log10Methode dauerte nur 7.486343383789062e-05 Sekunden, ungefähr 1501388 mal schneller!
FadedCoder

1
Dies ist nicht nur langsam, sondern verbraucht viel mehr Speicher und kann in großer Zahl Probleme verursachen. Verwenden Sie Math.log10stattdessen.
Peyman

245

Ohne Konvertierung in einen String

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

Um auch mit Nullen und negativen Zahlen umzugehen

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

Du würdest das wahrscheinlich in eine Funktion einfügen wollen :)

Hier sind einige Benchmarks. Das len(str())ist schon für ganz kleine Zahlen im Rückstand

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

5
Die Verwendung von log10 hierfür ist eine Lösung für Mathematiker. Die Verwendung von len (str ()) ist eine Programmierlösung und klarer und einfacher.
Glenn Maynard

68
@Glenn: Ich hoffe auf jeden Fall, dass Sie nicht implizieren, dass dies eine schlechte Lösung ist. Die naive O (log10 n) -Lösung des Programmierers funktioniert gut in Ad-hoc-Prototyping-Code - aber ich würde die elegante O (1) -Lösung von Mathematikern lieber in Produktionscode oder einer öffentlichen API sehen. +1 für Gnibbler.
Julia

5
@gnibbler: +1. Nie realisiert, dass log10 verwendet werden kann, um die Größe einer Zahl zu ermitteln. Ich wünschte, ich könnte mehr als einmal abstimmen :).
Abbas

14
Hallo! Ich gehe etwas Seltsames, kann mir jemand von euch bitte erklären, warum int(math.log10(x)) +1für 99999999999999999999999999999999999999999999999999999999999999999999999( 71 Neunen ) 72 zurückgegeben werden ? Ich dachte, ich könnte mich auf die log10-Methode verlassen, aber ich muss stattdessen len (str (x)) verwenden :(
Marecky

6
Ich glaube, ich kenne den Grund für das seltsame Verhalten, es liegt an Gleitkomma-Ungenauigkeiten, z. math.log10(999999999999999)ist gleich 14.999999999999998so int(math.log10(999999999999999))wird 14. Aber dann math.log10(9999999999999999)ist gleich 16.0. Vielleicht ist die Verwendung roundeine Lösung für dieses Problem.
Jamylak

43

Alle math.log10-Lösungen geben Ihnen Probleme.

math.log10 ist schnell, gibt jedoch Probleme, wenn Ihre Zahl größer als 999999999999997 ist. Dies liegt daran, dass der Float zu viele 0,9 Sekunden hat, wodurch das Ergebnis aufgerundet wird.

Die Lösung besteht darin, eine while-Zählermethode für Zahlen über diesem Schwellenwert zu verwenden.

Um dies noch schneller zu machen, erstellen Sie 10 ^ 16, 10 ^ 17 usw. und speichern Sie sie als Variablen in einer Liste. Auf diese Weise ist es wie eine Tabellensuche.

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

Danke dir. Das ist ein gutes Gegenbeispiel für math.log10. Es ist interessant zu sehen, wie die binäre Darstellung die Werte umdreht und ein mathematisch falsches Ergebnis liefert.
WloHu

dann wäre len (str (num)) besser
Vighnesh Raut

2
@ Vighnesh Raut: Und Größenordnungen langsamer
Chaitanya Bangera

"Es ist gefährlich, sich auf Gleitkommaoperationen zu verlassen, die genaue Ergebnisse liefern" - Mark Dickinson, Mitglied des Python-Entwicklungsteams bugs.python.org/issue3724
Sreeragh AR

26

Pythons 2.* intbenötigen je nach Python-Build entweder 4 oder 8 Byte (32 oder 64 Bit). sys.maxint( 2**31-1für 32-Bit-Ints, 2**63-1für 64-Bit-Ints) zeigt Ihnen, welche der beiden Möglichkeiten sich ergibt.

In Python 3 kann ints (wie longs in Python 2) beliebige Größen bis zur Menge des verfügbaren Speichers annehmen. sys.getsizeofgibt Ihnen einen guten Hinweis für einen bestimmten Wert, obwohl auch ein fester Overhead berücksichtigt wird :

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

Wenn Sie, wie andere Antworten vermuten lassen, über eine Zeichenfolgendarstellung des ganzzahligen Werts nachdenken, nehmen Sie einfach die lenDarstellung dieser Darstellung, sei es in Basis 10 oder auf andere Weise!


Entschuldigung, diese Antwort wurde negativ bewertet. Es ist informativ und auf den plausiblen Punkt der Frage (wenn es nur genauer wäre, welches 'len' gewünscht wird). +1
mjv

Das sieht interessant aus, ist sich aber nicht sicher, wie man die Länge extrahiert
Tjorriemorrie

17

Es ist einige Jahre her, seit diese Frage gestellt wurde, aber ich habe einen Benchmark mit mehreren Methoden zur Berechnung der Länge einer ganzen Zahl erstellt.

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

(Die libc-Funktion erfordert einige Einstellungen, die ich nicht aufgenommen habe.)

size_expist dank Brian Preslopsky, size_strist dank GeekTantra und size_mathist dank John La Rooy

Hier sind die Ergebnisse:

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)

(Haftungsausschluss: Die Funktion wird an den Eingängen 1 bis 1.000.000 ausgeführt.)

Hier sind die Ergebnisse für sys.maxsize - 100000zu 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)

Wie Sie sehen können, ist mod_size( len("%i" % i)) am schnellsten, etwas schneller als die Verwendung str(i)und deutlich schneller als andere.


Sie sollten wirklich das libc-Setup einschließen libc = ctyle.CDLL('libc.so.6', use_errno=True)( ich vermute, das ist es). Und es funktioniert nicht für Zahlen, die größer sind als sys.maxsizeweil Gleitkommazahlen nicht "sehr groß" sein können. Also jede Zahl darüber, ich denke, Sie stecken mit einer der langsameren Methoden fest.
Torxed

15

Die Zahl sei ndann die Anzahl der Ziffern in nist gegeben durch:

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

Beachten Sie, dass dies korrekte Antworten für + ve ganze Zahlen <10e15 gibt. Darüber hinaus treten die Genauigkeitsgrenzen des Rückgabetyps ein math.log10und die Antwort kann um 1 abweichen. Ich würde einfach len(str(n))darüber hinaus verwenden. Dies erfordert O(log(n))Zeit, die dem Iterieren über Potenzen von 10 entspricht.

Vielen Dank an @SetiVolkylany, dass Sie mich auf diese Einschränkung aufmerksam gemacht haben. Es ist erstaunlich, wie scheinbar korrekte Lösungen Einschränkungen bei den Implementierungsdetails aufweisen.


1
Es funktioniert nicht, wenn n außerhalb des Bereichs liegt [-999999999999997, 999999999999997]
PADYMKO

@ SetiVolkylany, ich habe es bis zu 50 Stellen für Python2.7 und 3.5 getestet. Mach einfach eine assert list(range(1,51)) == [math.floor(math.log10(n))+1 for n in (10**e for e in range(50))].
BiGYaN

2
Versuchen Sie es mit Python2.7 oder Python3.5 >>> math.floor(math.log10(999999999999997))+1 15.0 >>> math.floor(math.log10(999999999999998))+1 16.0. Schauen Sie sich meine Antwort an stackoverflow.com/a/42736085/6003870 an .
PADYMKO

12

Nun, ohne in einen String zu konvertieren, würde ich so etwas tun:

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

    x = abs(x)

    if x < 10:
        return 1

    return 1 + lenDigits(x / 10)

Minimalistische Rekursion FTW


1
Sie erreichen das Rekursionslimit für große Zahlen.
nog642

9

Zählen Sie die Anzahl der Stellen, ohne die Ganzzahl in eine Zeichenfolge umzuwandeln:

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

Nizza man vermeidet String-Konvertierung vollständig.
Patrick Mutuku

7

Wie der liebe Benutzer @Calvintwr erwähnt, hat die Funktion math.log10ein Problem in einer Zahl außerhalb eines Bereichs [-999999999999997, 999999999999997], bei dem Gleitkommafehler auftreten. Ich hatte dieses Problem mit JavaScript (Google V8 und NodeJS) und C (GNU GCC-Compiler), daher 'purely mathematically'ist hier keine Lösung möglich.


Basierend auf diesem Kern und der Antwort der liebe Benutzer @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

Ich habe es an Zahlen mit einer Länge von bis zu 20 (einschließlich) getestet. Dies muss ausreichen, da die maximale Ganzzahl auf einem 64-Bit-System 19 ( len(str(sys.maxsize)) == 19) beträgt .

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

Alle Beispiele für Codes, die mit Python 3.5 getestet wurden


3

Für die Nachwelt zweifellos die mit Abstand langsamste Lösung für dieses Problem:

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

Angenommen, Sie fragen nach der größten Zahl, die Sie in einer Ganzzahl speichern können, ist der Wert implementierungsabhängig. Ich schlage vor, dass Sie bei der Verwendung von Python nicht so denken. In jedem Fall kann ein ziemlich großer Wert in einer Python-Ganzzahl gespeichert werden. Denken Sie daran, Python verwendet Enten-Typisierung!

Bearbeiten: Ich gab meine Antwort vor der Klarstellung, dass der Fragesteller die Anzahl der Ziffern wollte. Dafür stimme ich der in der akzeptierten Antwort vorgeschlagenen Methode zu. Nichts mehr hinzuzufügen!


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

1

Es kann für ganze Zahlen schnell durchgeführt werden, indem Folgendes verwendet wird:

len(str(abs(1234567890)))

Welches erhält die Länge der Zeichenfolge des absoluten Wertes von "1234567890"

absGibt die Zahl OHNE Negative zurück (nur die Größe der Zahl), strwandelt sie in eine Zeichenfolge um und konvertiert sie und lengibt die Zeichenfolgenlänge dieser Zeichenfolge zurück.

Wenn Sie möchten, dass es für Floats funktioniert, können Sie eine der folgenden Methoden verwenden:

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

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

Zum späteren Nachschlagen.


Ich denke, es wäre einfacher, die eingegebene Nummer selbst abzuschneiden (z. B. mit einer Umwandlung in int), als ihre dezimale Zeichenfolgendarstellung abzuschneiden: len(str(abs(int(0.1234567890))))gibt 1 zurück.
David Foerster

Nein, das würde nicht funktionieren. Wenn Sie 0,17 in eine Ganzzahl verwandeln, erhalten Sie 0 und die Länge davon würde sich von der Länge von 0,17 unterscheiden
Frogboxe

Im ersten Fall berechnen Sie effektiv die Länge des integralen Teils der Zahl , indem Sie alles von und einschließlich des Dezimalpunkts von der Zeichenfolgendarstellung abschneiden , was auch mein Vorschlag tut. Für 0,17 geben beide Lösungen 1 zurück.
David Foerster

0

Formatieren Sie in wissenschaftlicher Notation und reißen Sie den Exponenten ab:

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

Ich weiß nichts über Geschwindigkeit, aber es ist einfach.

Bitte beachten Sie die Anzahl der signifikanten Stellen nach der Dezimalstelle (die "5" in der ".5e" kann ein Problem sein, wenn sie den Dezimalteil der wissenschaftlichen Notation auf eine andere Ziffer aufrundet. Ich habe sie beliebig groß eingestellt, könnte aber die widerspiegeln Länge der größten Zahl, die Sie kennen.


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

Während dieser Code die Frage lösen kann, einschließlich einer Erklärung, wie und warum dies das Problem löst, würde dies wirklich dazu beitragen, die Qualität Ihres Beitrags zu verbessern, und wahrscheinlich zu mehr Up-Votes führen. Denken Sie daran, dass Sie in Zukunft die Frage für die Leser beantworten, nicht nur für die Person, die jetzt fragt. Bitte bearbeiten Sie Ihre Antwort, um Erklärungen hinzuzufügen und anzugeben, welche Einschränkungen und Annahmen gelten.
Adrian Mole

0

Wenn Sie einen Benutzer zur Eingabe auffordern müssen und dann zählen müssen, wie viele Zahlen vorhanden sind, können Sie Folgendes tun:

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

print(len(count_number))

Hinweis: Nehmen Sie niemals ein int als Benutzereingabe.


Ein ziemlich spezifischer Fall, den Sie hier beschreiben, da er tatsächlich mit der Länge einer Zeichenfolge zusammenhängt. Ich könnte auch jedes nicht numerische Zeichen eingeben und Sie würden immer noch glauben, dass es eine Zahl ist.
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

Mein Code für das gleiche ist wie folgt: Ich habe die log10-Methode verwendet:

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

Ich musste im Fall von 1 und 0 angeben, weil log10 (1) = 0 und log10 (0) = ND und daher die erwähnte Bedingung nicht erfüllt ist. Dieser Code funktioniert jedoch nur für ganze Zahlen.


0

Hier ist eine sperrige, aber schnelle Version:

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

Nur 5 Vergleiche für nicht zu große Zahlen. Auf meinem Computer ist es ungefähr 30% schneller als die math.log10Version und 5% schneller als die len( str()). Ok ... nein, so attraktiv, wenn du es nicht wütend benutzt.

Und hier sind die Zahlen, mit denen ich meine Funktion getestet / gemessen habe:

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

NB: Es werden keine negativen Zahlen verwaltet, aber die Anpassung ist einfach ...


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

6
Rufen Sie keine speziellen Methoden direkt auf. Das steht geschrieben len(str(a)).
Mike Graham

8
@ ghostdog74 Nur weil es eine Steckdose gibt, heißt das nicht, dass du deine Finger hineinstecken musst.

3
Also, wenn Sie so dagegen sind, warum sagen Sie mir nicht, was daran falsch ist?
Ghostdog74

11
"Magic" __ -Methoden gibt es für Python-Interna, auf die zurückgerufen werden kann, und nicht für den direkten Aufruf Ihres Codes. Es ist das Hollywood Framework-Muster: Rufen Sie uns nicht an, wir rufen Sie an. Die Absicht dieses Frameworks ist jedoch, dass dies magische Methoden sind, die von den Standard-Python-integrierten Funktionen verwendet werden können, damit Ihre Klasse das Verhalten der integrierten Funktionen anpassen kann. Wenn Ihr Code direkt aufgerufen werden kann, geben Sie der Methode einen Namen, der nicht "__" ist. Dies unterscheidet klar die Methoden, die für den Programmierverbrauch vorgesehen sind, von denen, die für den Rückruf von Python-integrierten Funktionen bereitgestellt werden.
PaulMcG

7
Es ist eine schlechte Idee, weil alle anderen im bekannten Universum str () und len () verwenden. Dies ist anders, um anders zu sein, was von Natur aus eine schlechte Sache ist - ganz zu schweigen davon, dass es höllisch hässlich ist. -1.
Glenn Maynard
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.