Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
有没有办法公平地实施Brian Kernighan';在Python中计算一的s算法?_Python_Algorithm_Performance_Loops_Built In - Fatal编程技术网

有没有办法公平地实施Brian Kernighan';在Python中计算一的s算法?

有没有办法公平地实施Brian Kernighan';在Python中计算一的s算法?,python,algorithm,performance,loops,built-in,Python,Algorithm,Performance,Loops,Built In,我对Brian Kernighan在python中计算一个数的算法的实现与在字符串中计算一个数的内置函数在性能上的巨大差异感到惊讶 在我看来,转换成一个字符串然后数一个似乎是个坏主意 现在,在寻找性能时,循环和不使用内置函数似乎是个坏主意 import random x = random.randint(0,1<<1000000) def count_ones(number): c = 0 while(number !=0 ): number =

我对Brian Kernighan在python中计算一个数的算法的实现与在字符串中计算一个数的内置函数在性能上的巨大差异感到惊讶

在我看来,转换成一个字符串然后数一个似乎是个坏主意

现在,在寻找性能时,循环和不使用内置函数似乎是个坏主意

import random

x = random.randint(0,1<<1000000)

def count_ones(number):
    c = 0
    while(number !=0 ):
        number = number&(number-1)
        c = c + 1
    return c


%timeit bin(x).count("1")
%timeit count_ones(x)


5.09 ms ± 20 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
25 s ± 544 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
随机导入

x=random.randint(0,1Kernighan的算法最适用于适合的数据,在现代硬件上通常为64位。对于较长的数字,该算法在数字长度上变为二次型,因为每次迭代都会在数字的整个长度上进行计算。该算法可以手动优化,因为很明显,一旦借阅停止agating,不会因按位and而改变任何内容

即使进行了优化,我们仍然处于画家Shlemiel的领地;计算是二次的,因为每次迭代时扫描总是从同一个位置开始,每次扫描都越来越远

无论如何,即使是一个老练的乐观主义者也会发现优化和Python的bignum实现没有一个老练的乐观主义者,例如,它没有将减量与按位和相结合

按位和按bignum显然可以在适当的位置完成,因此很容易编写:

number &= number - 1
希望能进行原位手术,但这对CPython没有任何影响;CPython的Bignum是不可变的,所以不可能发生原位突变

简而言之,Python将为每次迭代创建两个新的百万位数字。这并不奇怪它需要一段时间。相反,令人惊讶的是它只需要25秒


根据版本和平台的不同,CPython bignum操作以15位或30位为单位执行。(对适合30位的整数的计算略有优化。但64位远远超出该范围,因此不要期望将数字限制为64位以避免bignum开销。)假设您的平台使用30位单元,在预期的50万次迭代中运行算法意味着执行660多亿次单字计算(一次减法和一次按位计算(1000000/30=33334)-字bignums),再加上一百万个130KB的内存分配。在25秒内完成这项工作一点也不糟糕。它证明了现代CPU的速度有多快,并且警告说,在数字变大之前,不注意使用二次算法是多么容易。

我可能会尝试这样做:
sum(x&(1 0代表范围内的n)(x.位长度()
…不确定CPython中的内置函数在机器代码中的性能如何,而wunning Python需要运行整个解释器,因此使用内置函数通常比实现自定义算法更快。即使编译为机器代码会更快。在PyPy上运行时可能会更快。如果y你有Python 3.6+,
def bincount\u f(n):返回f'{n:b}。count(“1”)
bincount\u fmt
稍快,但仍然比
bin(n).count(“1”)
慢。或者如果x&(1)但这还不是全部。您的算法实际上具有与数字表示大小相关的二次时间,因此它对于bigint仍然不是有效的。