在Python中,如何找到整数中的位数?


当前回答

如果您正在寻找一个不使用内置函数的解决方案。 唯一需要注意的是当你发送a = 000时。

def number_length(a: int) -> int:
    length = 0
    if a == 0:
        return length + 1
    else:
        while a > 0:
            a = a // 10
            length += 1
        return length
    

if __name__ == '__main__':
    print(number_length(123)
    assert number_length(10) == 2
    assert number_length(0) == 1
    assert number_length(256) == 3
    assert number_length(4444) == 4

其他回答

一种快速的解决方案,它使用floor(log10(n))的自我修正实现,基于“更好的方法来计算整数n和b的log(n,b)的floor ?”

import math

def floor_log(n, b):
    res = math.floor(math.log(n, b))
    c = b**res
    return res + (b*c <= n) - (c > n)

def num_digits(n):
    return 1 if n == 0 else 1 + floor_log(abs(n), 10)

这非常快,只要n < 10**(2**52)(这非常非常大)就可以工作。

正如其他答案所示,使用log10会导致大n的错误结果,而使用len(str(…))或手动循环会导致大n的性能变慢。Jodag的答案提供了一个非常好的替代方案,它只适用于可能会使您的计算机崩溃的整数,但我们可以做得更好,甚至更快(对于n足够小的数学。Log2保证是准确的),避免使用对数,而是使用二进制:

def num_digits(n: int) -> int:
    assert n > 0
    i = int(0.30102999566398114 * (n.bit_length() - 1)) + 1
    return (10 ** i <= n) + i

让我们来分析一下。首先是奇怪的n.bit_length()。这将以二进制形式计算长度:

assert 4 == (0b1111).bit_length()
assert 8 == (0b1011_1000).bit_length()
assert 9 == (0b1_1011_1000).bit_length()

与对数不同,这对于整数来说既快速又精确。结果是,这个结果正好是(log2(n)) + 1。为了单独得到地板(log2(n)),我们减去1,因此n.bit_length() - 1。

接下来,我们乘以0.30102999566398114。这相当于log10(2)稍微舍入。这利用了对数规则,以便从地板(log2(n))计算地板(log10(n))的估计值。

现在,您可能想知道我们在这一点上可能有多差,因为尽管0.30102999566398114 * log2(n) ~ log10(n),但对于floor(0.30102999566398114 * floor(log2(n))) ~ floor(log10(n)),情况并非如此。回想一下x - 1 < floor(x) <= x,我们可以做一些快速的计算:

log2(n) - 1 < floor(log2(n)) <= log2(n)

log10(n) - 0.30102999566398114 < 0.30102999566398114 * floor(log2(n)) <= log10(n)

floor(log10(n) - 0.30102999566398114) < floor(0.30102999566398114 * floor(log2(n))) <= floor(log10(n))

请注意,floor(log10(n) - 0.30102999566398114)至少是floor(log10(n)) - 1,这意味着我们与结果最多相差1。这是最后的修正,我们检查10 ** i <= n,当结果太小时导致额外的1 +,当结果刚刚好时导致0 +。

类似于Jodag的答案,这种方法实际上对非常非常大的n无效,大约在10 ** 2 ** 52左右,其中i的误差超过-1。然而,这种大小的整数可能会使您的计算机崩溃,所以这应该足够了。

from math import log10
digits = lambda n: ((n==0) and 1) or int(log10(abs(n)))+1

计算w/o将整数转换为字符串的位数:

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

下面是一个体积大但速度快的版本:

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%。Log10版本,比len(str())快5%。 好吧……如果你不疯狂地使用它,就没那么吸引人了。

下面是我用来测试/测量我的函数的一组数字:

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

注意:它不管理负数,但适应很容易…