Długość liczby całkowitej w Pythonie

232

W Pythonie, jak znaleźć liczbę cyfr w liczbie całkowitej?

Strigoides
źródło
1
Nie rozumiem twojego pytania. Miałeś na myśli rozmiar liczby całkowitej? Czy chcesz znaleźć liczbę cyfr? Proszę o wyjaśnienie.
batbrat

Odpowiedzi:

317

Jeśli chcesz, aby liczba całkowita była równa liczbie cyfr w liczbie całkowitej, zawsze możesz przekonwertować ją na ciąg znaków str(133)i znaleźć jej długość len(str(123)).

GeekTantra
źródło
18
Oczywiście, jeśli szukasz liczby cyfr, spowoduje to, że wynik będzie zbyt duży dla liczb ujemnych, ponieważ policzy znak ujemny.
Chris Upchurch
37
Hej, to powolne rozwiązanie. Zrobiłem silnię losowej liczby 6-cyfrowej i znalazłem jej długość. Ta metoda zajęła 95,891 sekundy. I Math.log10metoda trwało tylko 7.486343383789062e-05 sekund, około 1501388 razy szybciej!
FadedCoder,
1
Jest to nie tylko wolne, ale zużywa znacznie więcej pamięci i może powodować problemy w dużych ilościach. użyj Math.log10zamiast tego.
Peyman
245

Bez konwersji na ciąg

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

Do obsługi liczb zerowych i ujemnych

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

Prawdopodobnie chciałbyś umieścić to w funkcji :)

Oto kilka punktów odniesienia. len(str())Ma już za sobą nawet dla bardzo małych ilościach

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
źródło
5
Użycie log10 do tego jest rozwiązaniem matematyka; Użycie len (str ()) jest rozwiązaniem dla programistów i jest jaśniejsze i prostsze.
Glenn Maynard
68
@Glenn: Mam nadzieję, że nie sugerujesz, że jest to złe rozwiązanie. Naiwne dla programisty rozwiązanie O (log10 n) działa dobrze w ad-hoc, prototypowym kodzie - ale wolałbym raczej, aby matematycy eleganckie rozwiązanie O (1) w kodzie produkcyjnym lub publicznym interfejsie API. +1 za gnibbler.
Julia
5
@gnibbler: +1. Nigdy nie zdawałem sobie sprawy, że log10 można wykorzystać do znalezienia wielkości liczby. Chciałbym móc głosować więcej niż raz :).
Abbas,
14
Cześć! Idę coś dziwnego, może ktoś z was proszę mi wyjaśnić, dlaczego int(math.log10(x)) +1do 99999999999999999999999999999999999999999999999999999999999999999999999( 71 dziewiątek ) zwraca 72 ? Myślałem, że mogę polegać na metodzie log10, ale zamiast tego muszę użyć len (str (x)) :(
Marecky
6
Wierzę, że znam przyczynę dziwnego zachowania, jest to spowodowane niedokładnościami zmiennoprzecinkowymi, np. math.log10(999999999999999)jest równy 14.999999999999998tak się int(math.log10(999999999999999))staje 14. Ale wtedy math.log10(9999999999999999)jest równy 16.0. Być może używanie roundjest rozwiązaniem tego problemu.
jamylak
43

Wszystkie rozwiązania math.log10 sprawią ci problemy.

math.log10 jest szybki, ale stwarza problem, gdy liczba jest większa niż 99999999999999997. Jest tak, ponieważ liczba zmiennoprzecinkowa ma zbyt wiele .9s, co powoduje zaokrąglenie wyniku w górę.

Rozwiązaniem jest użycie metody licznika while dla liczb powyżej tego progu.

Aby uczynić to jeszcze szybszym, utwórz 10 ^ 16, 10 ^ 17 itd. I zapisz jako zmienne na liście. W ten sposób przypomina wyszukiwanie tabeli.

def getIntegerPlaces(theNumber):
    if theNumber <= 999999999999997:
        return int(math.log10(theNumber)) + 1
    else:
        counter = 15
        while theNumber >= 10**counter:
            counter += 1
        return counter
Calvintwr
źródło
Dziękuję Ci. To dobry przykład na przeciw math.log10. Ciekawie jest zobaczyć, jak reprezentacja binarna zmienia wartości, dając matematycznie niepoprawny wynik.
WloHu,
wtedy len (str (num)) byłoby lepiej
Vighnesh Raut
2
@Vighnesh Raut: I wielkości wolniejsze
Chaitanya Bangera
„Niebezpiecznie jest polegać na operacjach zmiennoprzecinkowych dających dokładne wyniki” - Mark Dickinson, członek głównego zespołu programistycznego Python bugs.python.org/issue3724
Sreeragh AR
26

Python 2.* intzajmuje 4 lub 8 bajtów (32 lub 64 bity), w zależności od kompilacji Pythona. sys.maxint( 2**31-1dla 32-bitowych liczb całkowitych, 2**63-1dla 64-bitowych liczb całkowitych) powie ci, która z dwóch możliwości jest dostępna.

W Pythonie 3 ints (podobnie jak longw Pythonie 2) może przyjmować dowolne rozmiary do ilości dostępnej pamięci; sys.getsizeofdaje wskazówkę dobre dla danej wartości, choć ma również liczyć jakiś stały narzut:

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

Jeśli, jak sugerują inne odpowiedzi, myślisz o jakimś ciągu reprezentującym wartość całkowitą, to po prostu weź lentę reprezentację, czy to w bazie 10, czy w inny sposób!

Alex Martelli
źródło
Przepraszam, ta odpowiedź została pomniejszona. Jest to pouczające i realistyczne dla pytania (jeśli byłoby tylko bardziej szczegółowe na temat tego, która „len” jest pożądana). +1
mjv
Wygląda to interesująco, ale nie jestem pewien, jak wyodrębnić długość
Tjorriemorrie,
17

Minęło kilka lat, odkąd zadano to pytanie, ale opracowałem punkt odniesienia dla kilku metod obliczania długości liczby całkowitej.

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

(funkcja libc wymaga pewnej konfiguracji, której nie zawarłem)

size_expto dzięki Brianowi Preslopsky'emu, size_strto dzięki GeekTantrze i size_mathdzięki Johnowi La Rooyowi

Oto wyniki:

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)

(Zastrzeżenie: funkcja działa na wejściach od 1 do 1 000 000)

Oto wyniki sys.maxsize - 100000do 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)

Jak widać, mod_size( len("%i" % i)) jest najszybszy, nieco szybszy niż używanie str(i)i znacznie szybszy niż inne.

Nikogo tu nie ma
źródło
Naprawdę powinieneś dołączyć konfigurację libc libc = ctyle.CDLL('libc.so.6', use_errno=True)(zgadując, że to jest to). I to nie działa dla liczb większych niż sys.maxsizeponieważ liczby zmiennoprzecinkowe nie mogą być „bardzo duże”. Więc każda liczba powyżej tego, myślę, że utknąłeś z jedną z wolniejszych metod.
Torxed
15

Niech liczba będzie nwtedy liczbą cyfr npodaną przez:

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

Zauważ, że da to prawidłowe odpowiedzi dla liczb całkowitych + ve <10e15. Poza tym limity precyzji typu zwrotu math.log10zaczynają się, a odpowiedź może być wyłączona o 1. Chciałbym po prostu użyć len(str(n))tego; wymaga to O(log(n))czasu, który jest taki sam, jak iteracja po potęgach 10.

Dzięki @SetiVolkylany za zwrócenie mojej uwagi na to ograniczenie. To niesamowite, jak pozornie poprawne rozwiązania mają zastrzeżenia w szczegółach implementacji.

BiGYaN
źródło
1
Nie działa, jeśli n jest poza zakresem [-999999999999997, 999999999999997]
PADYMKO
@ SetiVolkylany, przetestowałem go do 50 cyfr dla python2.7 i 3.5. Po prostu zrób assert list(range(1,51)) == [math.floor(math.log10(n))+1 for n in (10**e for e in range(50))].
BiGYaN
2
wypróbuj go z Python2.7 lub Python3.5 >>> math.floor(math.log10(999999999999997))+1 15.0 >>> math.floor(math.log10(999999999999998))+1 16.0. Spójrz na moją odpowiedź stackoverflow.com/a/42736085/6003870 .
PADYMKO
12

Cóż, bez konwersji na ciąg zrobiłbym coś takiego:

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

    x = abs(x)

    if x < 10:
        return 1

    return 1 + lenDigits(x / 10)

Minimalistyczna rekurencja FTW

odradek
źródło
1
Osiągniesz limit rekurencji dla dużych liczb.
nog642
9

Policz liczbę cyfr bez konwersji liczby całkowitej na ciąg:

x=123
x=abs(x)
i = 0
while x >= 10**i:
    i +=1
# i is the number of digits
datanew
źródło
Fajny całkowicie unika konwersji łańcucha.
Patrick Mutuku
7

Jak wspomniano, drogi użytkowniku @Calvintwr, funkcja math.log10ma problem z liczbą spoza zakresu [-999999999999997, 99999999999999997], w której występują błędy zmiennoprzecinkowe. Miałem ten problem z JavaScript (Google V8 i NodeJS) i C (kompilator GNU GCC), więc 'purely mathematically'rozwiązanie jest tutaj niemożliwe.


Na podstawie tego GIST i odpowiedzi kochany użytkownika @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

Przetestowałem to na liczbach o długości do 20 (włącznie) i wszystko w porządku. Musi to wystarczyć, ponieważ maksymalna liczba całkowita w systemie 64-bitowym wynosi 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

Wszystkie przykłady kodów testowanych w Pythonie 3.5

PADYMKO
źródło
3

Dla potomnych, bez wątpienia najwolniejsze rozwiązanie tego problemu:

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
źródło
2
from math import log10
digits = lambda n: ((n==0) and 1) or int(log10(abs(n)))+1
Robert William Hanks
źródło
1

Zakładając, że pytasz o największą liczbę, jaką możesz zapisać w liczbie całkowitej, wartość zależy od implementacji. Sugeruję, abyś nie myślał w ten sposób, używając Pythona. W każdym razie całkiem spora wartość może być przechowywana w pythonowej „liczbie całkowitej”. Pamiętaj, że Python używa pisania kaczego!

Edycja: Udzieliłem odpowiedzi przed wyjaśnieniem, że pytający chciał liczby cyfr. W tym celu zgadzam się z metodą sugerowaną przez przyjętą odpowiedź. Nic więcej do dodania!

batbrat
źródło
1
def length(i):
  return len(str(i))

źródło
1

Można to zrobić szybko dla liczb całkowitych, używając:

len(str(abs(1234567890)))

Który pobiera długość ciągu wartości bezwzględnej „1234567890”

abszwraca liczbę BEZ jakichkolwiek negatywów (tylko wielkość liczby), strrzutuje / konwertuje ją na ciąg znaków i lenzwraca długość łańcucha tego ciągu.

Jeśli chcesz, aby działał dla liczb zmiennoprzecinkowych, możesz użyć jednej z następujących opcji:

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

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

Dla przyszłego odniesienia.

Frogboxe
źródło
Myślę, że łatwiej byłoby obciąć samą liczbę wejściową (np. Rzutem do int) niż skrócić jej reprezentację ciągu dziesiętnego: len(str(abs(int(0.1234567890))))zwraca 1.
David Foerster
Nie, to by nie działało. Jeśli
zamienisz
W pierwszym przypadku, obcinając wszystko i włączając kropkę dziesiętną z reprezentacji ciągu, skutecznie obliczasz długość integralnej części liczby, co też robi moja sugestia. Dla 0,17 oba rozwiązania zwracają 1.
David Foerster
0

Sformatuj w notacji naukowej i odłóż wykładnik:

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

Nie wiem o prędkości, ale to proste.

Zwróć uwagę na liczbę cyfr znaczących po przecinku („5” w „.5e” może być problemem, jeśli zaokrągla w górę dziesiętną część notacji naukowej do innej cyfry. Ustawiam ją dowolnie dużą, ale może odzwierciedlać długość największej liczby, o której wiesz.

Brian Preslopsky
źródło
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
źródło
Chociaż ten kod może rozwiązać pytanie, w tym wyjaśnienie, w jaki sposób i dlaczego to rozwiązuje problem, naprawdę pomógłby poprawić jakość twojego postu i prawdopodobnie doprowadziłby do większej liczby głosów. Pamiętaj, że odpowiadasz na pytanie czytelników w przyszłości, a nie tylko osoby zadającej teraz pytanie. Proszę edytować swoje odpowiedzi, aby dodać wyjaśnień i dać wskazówkę co zastosować ograniczenia i założenia.
Adrian Mole
0

Jeśli musisz poprosić użytkownika o podanie danych, a następnie musisz policzyć, ile jest liczb, możesz to zrobić:

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

print(len(count_number))

Uwaga: Nigdy nie bierz int jako danych wejściowych użytkownika.

Sagar Biswas
źródło
Raczej specyficzny przypadek, który tu opisujesz, ponieważ jest on faktycznie związany z długością łańcucha. Mógłbym również wprowadzić dowolny znak nienumeryczny, a ty nadal uważasz, że jest to liczba.
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
źródło
0

Mój kod do tego samego wygląda następująco; użyłem metody log10:

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

Musiałem określić w przypadku 1 i 0, ponieważ log10 (1) = 0 i log10 (0) = ND, a zatem wspomniany warunek nie jest spełniony. Jednak ten kod działa tylko dla liczb całkowitych.

Devvrat Chaubal
źródło
0

Oto obszerna, ale szybka wersja:

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

Tylko 5 porównań dla niezbyt dużych liczb. Na moim komputerze jest to około 30% szybsza niż math.log10wersja i 5% szybsza niż ta len( str()). Ok ... nie tak atrakcyjny, jeśli nie użyjesz go wściekle.

A oto zestaw liczb, których użyłem do przetestowania / zmierzenia mojej funkcji:

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

Uwaga: nie zarządza liczbami ujemnymi, ale dostosowanie jest łatwe ...

Captain'Flam
źródło
-13
>>> a=12345
>>> a.__str__().__len__()
5
ghostdog74
źródło
6
Nie wywołuj bezpośrednio specjalnych metod. To jest napisane len(str(a)).
Mike Graham
8
@ ghostdog74 To, że jest gniazdo elektryczne, nie oznacza, że ​​musisz w niego włożyć palce.
3
więc jeśli jesteś przeciwko temu, dlaczego nie powiesz mi, co jest złego w korzystaniu z niego?
ghostdog74
11
Dostępne są metody „magiczne” __ dla wewnętrznych elementów Pythona, a nie dla kodu bezpośrednio. To wzór z Hollywood Framework: nie dzwoń do nas, zadzwonimy do ciebie. Ale celem tego frameworka jest to, że są to magiczne metody dla standardowych wbudowanych Pythonów do wykorzystania, aby twoja klasa mogła dostosować zachowanie wbudowanego. Jeśli jest to metoda bezpośredniego wywoływania kodu, nadaj tej metodzie nazwę inną niż „__”. To wyraźnie oddziela te metody, które są przeznaczone do wykorzystania przez programistę, od tych, które są dostępne dla wywołania zwrotnego z wbudowanych Python.
PaulMcG
7
To zły pomysł, ponieważ wszyscy inni w znanym wszechświecie używają str () i len (). To jest bycie innym ze względu na bycie innym, co z natury jest złą rzeczą - nie wspominając o tym, że jest po prostu brzydkie jak diabli. -1.
Glenn Maynard