Довжина цілого числа в 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.