Довжина цілого числа в Python


232

Як в Python ви знаєте кількість цифр у цілому?


1
Я не розумію вашого запитання. Ви мали на увазі величину цілого числа? Ви хочете знайти кількість цифр? Поясніть будь ласка.
батбрат

Відповіді:


317

Якщо ви хочете, щоб довжина цілого числа була як у кількості цифр у цілому, ви завжди можете перетворити її у рядок типу str(133)та знайти її довжину як len(str(123)).


18
Звичайно, якщо ви шукаєте кількість цифр, це призведе до занадто великого результату для від'ємних чисел, оскільки він буде рахувати негативний знак.
Кріс Апчерч

37
Гей, це повільне рішення. Я зробив факториал випадкового 6-значного числа і виявив його довжину. Цей метод зайняв 95,891 секунди. А Math.log10метод зайняв лише 7,486343383789062e-05 секунд, приблизно в 1501388 разів швидше!
FadedCoder

1
Це не просто повільно, але витрачає набагато більше пам’яті і може спричинити неприємності у великій кількості. використовувати Math.log10замість цього.
Пейман

245

Без перетворення в рядок

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

Також обробляти нульові та від’ємні числа

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

Ви, напевно, хочете поставити це у функції :)

Ось кілька орієнтирів. Це len(str())вже позаду навіть для зовсім невеликої кількості

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
Використання log10 для цього - рішення математика; використання len (str ()) - це рішення програміста і є більш чітким та простим.
Гленн Мейнард

68
@Glenn: Я, звичайно, сподіваюся, що ви не маєте на увазі це погане рішення. Наївне рішення програміста O (log10 n) добре працює в спеціальному коді прототипування, але я набагато краще бачити математики елегантним рішенням O (1) у виробничому коді чи публічному API. +1 для гніблера.
Джульєтта

5
@gnibbler: +1. Ніколи не усвідомлював, що log10 можна використовувати для пошуку величини числа. Бажаю, щоб я міг проголосувати більше одного разу :).
Абас

14
Привіт! Я йду щось дивне, чи може хтось із вас пояснити мені, чому int(math.log10(x)) +1за 99999999999999999999999999999999999999999999999999999999999999999999999( 71 дев'ять ) повертається 72 ? Я думав, що можу покластися на метод log10, але мені доведеться використовувати len (str (x)) замість :(
Marecky

6
Я вважаю, що я знаю причину дивної поведінки, вона пов'язана з неточностями з плаваючою комою, наприклад. math.log10(999999999999999)дорівнює 14.999999999999998тому int(math.log10(999999999999999))стає 14. Але тоді math.log10(9999999999999999)дорівнює 16.0. Можливо, використання round- це рішення цієї проблеми.
jamylak

43

Усі рішення math.log10 доставлять вам проблеми.

math.log10 є швидким, але створює проблеми, коли ваше число перевищує 999999999999997. Це пов’язано з тим, що в плавучі є занадто багато .9s, що призводить до того, що результат буде округлюватися.

Рішення полягає у використанні методу лічильника часу для чисел, що перевищують цей поріг.

Щоб зробити це ще швидше, створіть 10 ^ 16, 10 ^ 17 тощо, і збережіть як змінні у списку. Таким чином, це як пошук таблиці.

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

Дякую. Це хороший зустрічний приклад для math.log10. Цікаво побачити, як бінарне подання перевертає значення, даючи математично невірний результат.
WloHu

тоді len (str (num)) буде краще
Vighnesh Raut

2
@Vighnesh Raut: І величини повільніші
Чайтанья Бангера

"Покладатися на операції з плаваючою комою дають точні результати небезпечно" - Марк Дікінсон, член основної команди розробників
Sreeragh AR

26

Python 2.* ints бере 4 або 8 байт (32 або 64 біта), залежно від збірки Python. sys.maxint( 2**31-1для 32-бітових ints, 2**63-1для 64-розрядних ints) підкаже, яку з двох можливостей отримує.

У Python 3 ints (як longs у Python 2) може приймати довільні розміри до обсягу доступної пам'яті; sys.getsizeofдає індикацію добре для будь-якого заданого значення, хоча це також розраховувати деякі фіксовані накладні витрати:

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

Якщо, як свідчать інші відповіді, ви думаєте про якесь рядкове представлення цілого значення, тоді просто візьміть lenце подання, будь то в базі 10 чи іншим чином!


На жаль, ця відповідь отримала мінус-ред. Це інформативно і з правдоподібною точкою питання (якби воно було лише більш конкретним щодо того, який саме "лен" бажано). +1
mvv

Це виглядає цікаво, але не впевнено, як витягти довжину
Tjorriemorrie

17

Минуло кілька років з моменту того, як було задано це питання, але я склав орієнтир з декількох методів для обчислення довжини цілого числа.

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

(функція libc вимагає певного налаштування, яке я не включив)

size_expце завдяки Брайану Преслопському, size_strзавдяки GeekTantra і size_mathзавдяки Джону Ла Роу

Ось результати:

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)

(Відмова від відповідальності: функція виконується на входах від 1 до 1 000 000)

Тут наведені результати 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)

Як бачите, mod_size( len("%i" % i)) - найшвидший, трохи швидший за використання str(i)та значно швидший за інші.


Ви дійсно повинні включати налаштування libc libc = ctyle.CDLL('libc.so.6', use_errno=True)(гадаючи, що це все). І це не працює для чисел, більших, ніж те, sys.maxsizeщо числа з плаваючою комою не можуть бути "дуже великими". Отже, будь-яке число вище цього, я думаю, ви застрягли в одному з повільніших методів.
Тортується

15

Нехай число буде, nтоді кількість цифр в nзадається:

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

Зауважте, що це дасть правильні відповіді для + ve цілих чисел <10e15. Крім того, межі точності зворотного типу math.log10забиває і відповідь може бути відключена на 1. Я просто використовував би len(str(n))поза цим; для цього потрібен O(log(n))час, такий же, як ітерація над повноваженнями 10.

Дякуємо @SetiVolkylany за притягнення до цього обмеження. Дивовижно, наскільки правильні рішення мають застереження в деталях реалізації.


1
Це не працює, якщо n поза діапазоном [-999999999999997, 999999999999997]
PADYMKO

@SetiVolkylany, я перевірив його до 50 цифр для python2.7 та 3.5. Просто зробіть assert list(range(1,51)) == [math.floor(math.log10(n))+1 for n in (10**e for e in range(50))].
BiGYaN

2
спробуйте його з Python2.7 або Python3.5 >>> math.floor(math.log10(999999999999997))+1 15.0 >>> math.floor(math.log10(999999999999998))+1 16.0. Подивіться мою відповідь stackoverflow.com/a/42736085/6003870 .
ПАДИМКО

12

Ну, не перетворюючи на рядок, я б зробив щось на кшталт:

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

    x = abs(x)

    if x < 10:
        return 1

    return 1 + lenDigits(x / 10)

Мінімалістична рекурсія FTW


1
Ви досягнете межі рекурсії для великої кількості.
nog642

9

Порахуйте кількість цифр без перетворення цілого числа в рядок:

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

Хороший дозволяє уникнути перетворення рядків повністю.
Патрік Мутуку

7

Як згадував шановний користувач @Calvintwr, функція math.log10має проблеми в ряді, що знаходиться поза діапазоном [-999999999999997, 999999999999997], де ми отримуємо помилки з плаваючою комою. У мене була ця проблема з JavaScript (Google V8 і NodeJS) і C (компілятор GNU GCC), тому 'purely mathematically'рішення тут неможливо.


Виходячи з цієї суті та відповіді шановного користувача @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

Я перевірив це на номерах довжиною до 20 (включно) і все в порядку. Це повинно бути достатньо, тому що максимальне ціле число довжини в 64-бітній системі становить 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

Весь приклад кодів, протестованих за допомогою Python 3.5


3

Що стосується нащадків, без сумніву, це самий повільний варіант вирішення цієї проблеми:

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

Якщо припустити, що ви запитуєте про найбільшу кількість, яку ви можете зберігати в ціле число, значення залежить від реалізації. Я пропоную вам не думати таким чином під час використання python. У будь-якому випадку, досить велике значення може зберігатися в "цілому" пітона. Пам'ятайте, Python використовує набір качок!

Редагувати: Я відповів перед тим, як уточнити, що запитуючий бажає кількості цифр. Для цього я погоджуюся з методом, запропонованим прийнятою відповіддю. Більше нічого додати!


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

1

Це можна зробити для цілих чисел швидко, використовуючи:

len(str(abs(1234567890)))

Яка отримує довжину рядка абсолютного значення "1234567890"

absповертає число БЕЗ будь-яких негативів (лише величина числа), strкидає / перетворює його в рядок і lenповертає довжину рядка цього рядка.

Якщо ви хочете, щоб він працював для поплавків, ви можете скористатися одним із наступних:

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

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

Для подальшого ознайомлення.


Я думаю, що було б простіше врізати саме вхідне число (наприклад, із закликом до int), ніж обрізати його десятковий рядок: len(str(abs(int(0.1234567890))))повернення 1.
Девід Фоерстер,

Ні, це не спрацює. Якщо ви перетворите 0,17 на ціле число, ви отримаєте 0, а довжина буде різною довжині 0,17
Frogboxe

У першому випадку, обрізаючи все, включаючи десяткову точку від представлення рядка, ви ефективно обчислюєте довжину невід'ємної частини числа, що і моя пропозиція. За 0,17 обидва рішення повертаються 1.
Девід Фоерстер

0

Форматуйте наукові позначення та зніміть показник:

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

Я не знаю про швидкість, але це просто.

Зверніть увагу на кількість значущих цифр після десяткових ("5" у ".5e" може бути проблемою, якщо вона округляє десяткову частину наукової нотації до іншої цифри. Я встановив її довільно великою, але міг би відображати значення довжина найбільшої кількості, про яку ви знаєте.


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

Хоча цей код може вирішити питання, включаючи пояснення, як і чому це вирішує проблему, справді допоможе покращити якість вашої публікації та, ймовірно, призведе до збільшення кількості голосів. Пам'ятайте, що ви відповідаєте на запитання читачів у майбутньому, а не лише про людину, яка зараз задає питання. Будь ласка, відредагуйте свою відповідь, щоб додати пояснення та вказати, які обмеження та припущення застосовуються.
Адріан Моль

0

Якщо вам доведеться попросити користувача ввести інформацію, а потім вам доведеться порахувати, скільки є номерів, ви можете виконати це:

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

print(len(count_number))

Примітка: Ніколи не приймайте int як введення користувача.


Досить конкретний випадок, який ви описуєте тут, оскільки він насправді пов'язаний з довжиною рядка. Крім того, я можу ввести будь-який нечисловий символ, і ви все одно повірите, що це число.
Бен

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

Мій код для цього такий, як я використовував метод log10:

from math import *

визначити_кілька (кількість):

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

Мені довелося вказати у випадку 1 і 0, оскільки log10 (1) = 0 і log10 (0) = ND, а отже, зазначена умова не виконується. Однак цей код працює лише для цілих чисел.


0

Ось об'ємна, але швидка версія:

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

Всього 5 порівнянь для не надто великих чисел. На моєму комп’ютері це приблизно на 30% швидше, ніж math.log10версія, і на 5% швидше, ніж версія len( str()). Гаразд ... не так привабливо, якщо ви не використовуєте це люто.

Ось набір чисел, які я використовував для тестування / вимірювання своєї функції:

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

NB: він не керує від'ємними числами, але адаптація проста ...


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

6
Не варто безпосередньо називати спеціальні методи. Це написано len(str(a)).
Майк Грехем

8
@ ghostdog74 Тільки тому, що є електрична розетка, не означає, що вам доведеться засунути пальці в неї.

3
Так що якщо ви проти цього, чому б ви не сказали мені, що поганого в його використанні?
ghostdog74

11
Методи "магії" __ існують для внутрішніх справ Python, щоб передзвонити, а не для того, щоб ваш код зателефонував безпосередньо. Це шаблон Framework Hollywood: не дзвоніть нам, ми вам зателефонуємо. Але мета цієї рамки полягає в тому, що це магічні методи для використання стандартних вбудованих Python, щоб ваш клас міг налаштувати поведінку вбудованого. Якщо це код, за допомогою якого ваш код може зателефонувати безпосередньо, дайте методу не "__" ім'я. Це чітко відокремлює ті методи, які призначені для споживання програміста, порівняно з тими, які передбачені для зворотного виклику від вбудованих Python.
PaulMcG

7
Це погана ідея, оскільки всі інші у відомій Всесвіті використовують str () та len (). Це по-різному заради того, щоб бути різним, що по суті є поганою справою - не кажучи вже про це просто некрасиво, як пекло. -1.
Гленн Мейнард
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.