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

233

В Python, как найти количество цифр в целом числе?

Strigoides
источник
1
Я не понимаю твой вопрос. Вы имели в виду размер целого числа? Хотите узнать количество цифр? Просьба уточнить.
Batbrat

Ответы:

317

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

GeekTantra
источник
18
Конечно, если вы ищете количество цифр, это даст слишком большой результат для отрицательных чисел, поскольку он будет считать отрицательный знак.
Крис Апчерч
37
Эй, это медленное решение. Я сделал факториал случайного 6-значного числа и нашел его длину. Этот метод занял 95,891 секунды. И Math.log10метод занял всего 7,486343383789062e-05 секунд, примерно в 1501388 раз быстрее!
FadedCoder
1
Это не просто медленно, но потребляет гораздо больше памяти и может вызвать проблемы в больших количествах. используйте Math.log10вместо этого.
Пейман
246

Без преобразования в строку

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
@ Гленн: Я, конечно, надеюсь, что вы не намекаете, что это плохое решение. Наивное решение 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. Это потому, что у float слишком много .9s, в результате чего результат округляется.

Решение состоит в том, чтобы использовать метод счетчика while для чисел выше этого порога.

Чтобы сделать это еще быстрее, создайте 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
Calvintwr
источник
Спасибо. Это хороший контрпример math.log10. Интересно посмотреть, как двоичное представление переворачивает значения, давая математически неверный результат.
WloHu
тогда len (str (num)) будет лучше
Vighnesh Raut
2
@Vighnesh Raut: И величины медленнее
Чайтанья Бангера
«Опасно полагаться на операции с плавающей запятой, дающие точные результаты», - Марк Дикинсон, член основной команды разработчиков Python bugs.python.org/issue3724
Sreeragh AR
26

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

В Python 3 ints (как longs в Python 2) может принимать произвольные размеры вплоть до объема доступной памяти; sys.getsizeofдает индикацию хорошо для любого заданного значения, хотя это также рассчитывать некоторые фиксированные накладные расходы:

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

Если, как показывают другие ответы, вы думаете о некотором строковом представлении целочисленного значения, то просто возьмите lenэто представление, будь то в базе 10 или иначе!

Алекс Мартелли
источник
Извините, этот ответ получил минус-ред. Он информативен и правдоподобен в вопросе (если бы он был только более конкретным в отношении того, какой «лен» желателен). +1
mjv
Это выглядит интересно, но не уверен, как извлечь длину
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)и значительно быстрее, чем другие.

NoOneIsHere
источник
Вы действительно должны включить установку libc libc = ctyle.CDLL('libc.so.6', use_errno=True)(догадываясь, что это так). И это не работает для чисел больше, чем sys.maxsizeпотому что числа с плавающей запятой не могут быть "очень большими". Так что любое число выше этого, я думаю, вы застряли с одним из более медленных методов.
Torxed
15

Пусть число будет nтогда количеством цифр вn выражении:

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

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

Спасибо @SetiVolkylany за мое внимание к этому ограничению. Удивительно, как казалось бы правильные решения имеют недостатки в деталях реализации.

BiGYaN
источник
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 .
PADYMKO
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
datanew
источник
Хороший избегает преобразования строк полностью.
Патрик Мутуку
8

Как упомянул уважаемый пользователь @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

PADYMKO
источник
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)
Стефан ван ден Аккер
источник
2
from math import log10
digits = lambda n: ((n==0) and 1) or int(log10(abs(n)))+1
Роберт Уильям Хэнкс
источник
1

Предполагая, что вы запрашиваете наибольшее число, которое вы можете сохранить в целом числе, значение зависит от реализации. Я полагаю, что вы не думаете так при использовании Python. В любом случае, довольно большое значение может быть сохранено в «целое число» Python. Помните, Python использует утку печатать!

Изменить: я дал свой ответ до разъяснения, что спрашивающий хотел количество цифр. Для этого я согласен с методом, предложенным принятым ответом. Больше нечего добавить!

batbrat
источник
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

Для дальнейшего использования.

Frogboxe
источник
Я думаю, что было бы проще усечь сам входной номер (например, с приведением к 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
Del_sama
источник
Хотя этот код может решить вопрос, в том числе объяснение того, как и почему это решает проблему, действительно поможет улучшить качество вашего сообщения и, вероятно, приведет к большему количеству голосов. Помните, что вы отвечаете на вопрос для читателей в будущем, а не только для того, кто спрашивает сейчас. Пожалуйста, измените свой ответ, чтобы добавить объяснения и указать, какие ограничения и предположения применяются.
Адриан Моль
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 *

def digit_count (число):

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: он не управляет отрицательными числами, но адаптация проста ...

Captain'Flam
источник
-13
>>> a=12345
>>> a.__str__().__len__()
5
ghostdog74
источник
6
Не вызывайте напрямую специальные методы. Это написано len(str(a)).
Майк Грэм
8
@ ghostdog74 То, что есть электрическая розетка, вовсе не означает, что вы должны в нее сунуть пальцы.
3
так что если вы так против, почему бы вам не сказать мне, что не так с его использованием?
ghostdog74
11
«Магические» ___ методы существуют для внутренних вызовов Python, а не для вашего кода для прямого вызова. Это шаблон Hollywood Framework: не звоните нам, мы вам позвоним. Но цель этого фреймворка заключается в том, что эти магические методы используются стандартными встроенными модулями Python, чтобы ваш класс мог настроить поведение встроенного. Если для вашего кода это метод, вызываемый напрямую, дайте методу имя, отличное от «__». Это четко отделяет те методы, которые предназначены для использования программистом, от методов, которые предоставляются для обратного вызова от встроенных Python.
PaulMcG
7
Это плохая идея, потому что все остальные в известной вселенной используют str () и len (). Это разные вещи ради того, чтобы быть разными, что по своей сути плохо, не говоря уже о том, что это просто ужасно. -1.
Гленн Мейнард