有没有办法优化此代码以查找数字的除数?
Posted
技术标签:
【中文标题】有没有办法优化此代码以查找数字的除数?【英文标题】:Is there a way to optimize this code for finding the divisors of a number? 【发布时间】:2020-04-09 17:49:48 【问题描述】:我在Julia
中编写了一个程序来有效地计算数字n
的除数。该算法是原创的(据我所知),大致基于Sieve of Eratosthenes。它基本上是这样工作的:
对于给定的素数
p
,让p^k || n
;列表中的每个数字m
满足p^k+1 | m
被删除,并重复此过程 每个素数p < n
。
使用传统的埃拉托色尼筛法在原位计算素数。
function ν(p, n) #returns the smallest power of p that does not divide n
q = 1
for i = 0:n
if mod(n, q) != 0
return (i, q)
end
q *= p
end
end
function divisors(n) #returns a list of divisors of n
dsieve, psieve = BitArray([true for i = 1:n]), BitArray([true for i = 1:n])
psieve[1] = false
for i = 1:n
if psieve[i] && dsieve[i]
#sieving out the non-primes
for j = i^2:i:n
psieve[j] = false
end
#sieving out the non-divisors
v = ν(i, n)[2]
for j = v:v:n
dsieve[j] = false
end
end
end
return dsieve #the code for converting this BitArray to an array of divisors has been omitted for clarity
end
虽然这工作得很好,但我发现同时使用两个筛子效率低下。我认为可以通过允许筛数组中的每个元素取三个不同的值(对应于unchecked
、divisor
和not divisor
)来解决这个问题,但是这样就不能再实现为BitArray
.
我也尝试过修改函数ν
以提高效率:
function ν₀(p, n) #the same as ν, but implemented differently
q = p
while mod(n, q) == 0
q = q^2
end
q = floor(Int64, √q)
q < p ? 1 : q * ν₀(p, n÷q) #change 1 to p to get the smallest power of p that does not divide n
end
虽然这更复杂,但它比之前的算法快一点——尤其是当p
除以n
的功率很大时。
注意:我知道有更好的算法可以找到数字的除数。我只是想知道上述算法可以优化到什么程度。如前所述,使用两个筛子相当麻烦,如果能找到一种方法,在不影响效率的情况下消除传统的素数筛子,那就太好了。
【问题讨论】:
【参考方案1】:我可以指出几件事-
dsieve, psieve = BitArray([true for i = 1:n]), BitArray([true for i = 1:n])
为每个数组分配两次(列表组合,然后是转换)。这样就可以了:(编辑:@DNF 在这里指出了VectorBool
的优越性)
dsieve = fill(true, n)
psieve = fill(true, n)
接下来,我们可以确保通过使用任何更快的索引来利用
for i in eachindex(psieve)
而不是手动范围。然后你可以在for循环前面加上
@inbounds for i in eachindex(psieve)
或者更进一步,如果您使用的是 Julia 1.3 或更高版本,并对其进行多线程处理(假设您在运行之前设置了 JULIA_NUM_THREADS
)
@inbounds Threads.@threads for i in eachindex(psieve)
【讨论】:
我相信使用VectorBool
比使用BitVector
更快。后者节省了内存,并且对于一些分块操作和缩减来说可能很快,但处理单个元素的速度较慢。将dsieve
和psieve
实例化为fill(true, n)
。
感谢您提供有用的建议,Miles Lucas 和 @DNF。我对 Julia 编程还是很陌生,所以我不熟悉大多数内置函数和优化。实施这些建议后,执行时间大大减少。以上是关于有没有办法优化此代码以查找数字的除数?的主要内容,如果未能解决你的问题,请参考以下文章