Algorithm 求一组素数乘积的算法,顺序大于x
考虑有限集{2,3,5,…,n}。我对素数感兴趣,但这个问题可以适用于任何一组数字。我想以升序找到这些数的所有可能乘积,尤其是大于或等于某个数x的乘积。有人知道一个很好的算法吗 编辑以澄清:Algorithm 求一组素数乘积的算法,顺序大于x,algorithm,primes,number-theory,hamming-numbers,smooth-numbers,Algorithm,Primes,Number Theory,Hamming Numbers,Smooth Numbers,考虑有限集{2,3,5,…,n}。我对素数感兴趣,但这个问题可以适用于任何一组数字。我想以升序找到这些数的所有可能乘积,尤其是大于或等于某个数x的乘积。有人知道一个很好的算法吗 编辑以澄清: 输入集合中的每个因子可以使用任意次数。如果输入是{2,3,5,7},输出将是{2,3,4,5,6,7,8,9,10,12,14,15,16,18,}。当算法产生的结果大于或等于某个数字x时,该算法可以立即停止。为此,有两种算法。首先,您可以计算这些数字之间所有可能的乘积,然后对它们进行排序。虽然这似乎是一种
输入集合中的每个因子可以使用任意次数。如果输入是{2,3,5,7},输出将是{2,3,4,5,6,7,8,9,10,12,14,15,16,18,}。当算法产生的结果大于或等于某个数字x时,该算法可以立即停止。为此,有两种算法。首先,您可以计算这些数字之间所有可能的乘积,然后对它们进行排序。虽然这似乎是一种幼稚的方法,但您可以通过“记住”上一个产品、划分一个数字并将不同的数字相乘来加快速度。这将大大减少必要的操作数量,如果通过排列的正确顺序,可以最小化总乘法 另一方面,你能做的是计算所有原始数的集合,两个原始数对的积的集合,3的积的集合。。。等等。然后,您可以对每个单独的集合进行排序,这应该不难确保它们几乎都已排序,然后合并将集合排序到一个已排序的产品列表中。这将需要更多的操作,但最终会产生一个几乎排序的列表,这可能需要更少的时间来构建整个列表
另一种算法是取所有感兴趣的素数的乘积,并称之为p。构造另一个包含所有原始素数平方的列表。现在,将所有数循环到P,并测试它们是否可以被素数平方数组中的任何值整除。如果是的话,扔掉它们。如果没有,则将它们添加到输出数组中。您可以通过只测试sqrti的可分性来优化它,其中i是for循环中的迭代。不过,这可能仍然比上述方法慢。为此,我们想到了两种算法。首先,您可以计算这些数字之间所有可能的乘积,然后对它们进行排序。虽然这似乎是一种幼稚的方法,但您可以通过“记住”上一个产品、划分一个数字并将不同的数字相乘来加快速度。这将大大减少必要的操作数量,如果通过排列的正确顺序,可以最小化总乘法 另一方面,你能做的是计算所有原始数的集合,两个原始数对的积的集合,3的积的集合。。。等等。然后,您可以对每个单独的集合进行排序,这应该不难确保它们几乎都已排序,然后合并将集合排序到一个已排序的产品列表中。这将需要更多的操作,但最终会产生一个几乎排序的列表,这可能需要更少的时间来构建整个列表
另一种算法是取所有感兴趣的素数的乘积,并称之为p。构造另一个包含所有原始素数平方的列表。现在,将所有数循环到P,并测试它们是否可以被素数平方数组中的任何值整除。如果是的话,扔掉它们。如果没有,则将它们添加到输出数组中。您可以通过只测试sqrti的可分性来优化它,其中i是for循环中的迭代。不过,这可能仍然比上述方法慢。您可能还希望在输出中包含2^0*3^0*5^0*7^0=1 实现这一点的方法是使用优先级队列。如果k在序列中,那么2k、3k、5k和7k也在序列中。以1开始输出,然后将2、3、5和7添加到优先级队列中。从队列顶部弹出2,并将2*2=4、2*3=6、2*5=10和2*7=14添加到队列中;此时的队列将包含3、4、5、6、7、10和14。从队列顶部弹出3,并将3*2=6、3*3=9、3*5=15和3*7=21添加到队列中。等等 你会发现许多元素是重复的;例如,在上面的示例中,我们两次向优先级队列添加了6。您可以添加重复项,并在每次弹出队列时检查该元素是否与序列的前一个成员相同,也可以在队列中保留一个单独的项目列表,并在第一时间避免添加重复项
我将在讨论仅包含不同元素的优先级队列。您可能还希望在输出中包含2^0*3^0*5^0*7^0=1 实现这一点的方法是使用优先级队列。如果k在序列中,那么2k、3k、5k和7k也在序列中。以1开始输出,然后将2、3、5和7添加到优先级队列中。从队列顶部弹出2,并将2*2=4、2*3=6、2*5=10和2*7=14添加到队列中;此时的队列将包含3、4、5 、6、7、10和14。从队列顶部弹出3,并将3*2=6、3*3=9、3*5=15和3*7=21添加到队列中。等等 你会发现许多元素是重复的;例如,在上面的示例中,我们两次向优先级队列添加了6。您可以添加重复项,并在每次弹出队列时检查该元素是否与序列的前一个成员相同,也可以在队列中保留一个单独的项目列表,并在第一时间避免添加重复项
我讨论一个优先级队列,它只包含不同的元素。由于每个素数都允许出现多次,所以序列是无限的。所以我们不能生成所有产品,然后对它们进行排序。我们必须迭代地生成序列 如果a是序列的一个成员,那么{2*a,3*a,5*a…n*a}也将是序列的成员,稍后会出现 所以,我想到的算法是,为下一个序列成员提供一个排序的、无重复的缓冲区。我们提取并呈现最小值,并将其所有倍数插入缓冲区
由于很难预测起始数字x的缓冲区内容,因此该算法应从一开始就开始,忽略结果,直到它们达到x阈值。由于每个素因子都允许多次出现,因此序列是无限的。所以我们不能生成所有产品,然后对它们进行排序。我们必须迭代地生成序列 如果a是序列的一个成员,那么{2*a,3*a,5*a…n*a}也将是序列的成员,稍后会出现 所以,我想到的算法是,为下一个序列成员提供一个排序的、无重复的缓冲区。我们提取并呈现最小值,并将其所有倍数插入缓冲区
由于很难预测起始编号x的缓冲区内容,因此此算法应从起始处开始,忽略结果,直到结果达到x阈值。编辑:使其按升序生成所有产品;让用户随心所欲地过滤它们。这是一个普遍的问题 示例用法
Prelude Hamming> take 10 $ dropWhile (< 1000) $ genHamming [2,3,5]
[1000,1024,1080,1125,1152,1200,1215,1250,1280,1296]
Prelude Hamming>
编辑:使其按升序生成所有产品;让用户随心所欲地过滤它们。这是一个普遍的问题 示例用法
Prelude Hamming> take 10 $ dropWhile (< 1000) $ genHamming [2,3,5]
[1000,1024,1080,1125,1152,1200,1215,1250,1280,1296]
Prelude Hamming>
每一个大于1的整数都是一组素数的乘积,因为它是素数因子的乘积。从所需的最小数开始,划掉初始集合中没有素因子的所有数可能会更容易。继续此过程,直到结果集足够大。实际上,你是在做一个改进的埃拉托什尼筛,去掉初始集以外的所有素数的倍数。每个大于1的整数都是“素数集”的乘积,因为它是其素数因子的乘积。从所需的最小数开始,划掉初始集合中没有素因子的所有数可能会更容易。继续此过程,直到结果集足够大。实际上,你正在做一个埃拉托斯坦的改进筛,除去初始集合中所有的素数倍数。哈斯克尔代码,如图所示 哈姆::[Integer]->[Integer] hamm[]=[] hamm p:ps=xs-例如hamm[2,3,5] 其中xs=merge hamm ps-H{p}∪ ps=S, p:map p*xs-S⊇ {p}∪ Hps∪ {p*x | x∊ S} 合并a@x:xsb@y:ys | x
因为我们的应用程序是用python编写的,所以我提出了以下实现,希望与大家分享:
def powers(x):
y = x
while True:
yield y
y *= x
def products(factors):
y0 = factors[0]
if len(factors) == 1:
yield from powers(y0)
else:
yield y0
g1 = products(factors)
y1 = y0 * next(g1)
g2 = products(factors[1:])
y2 = next(g2)
while True:
if y1 < y2:
yield y1
y1 = y0 * next(g1)
else:
yield y2
y2 = next(g2)
if __name__ == "__main__":
import itertools
for n in itertools.islice(products([2, 3, 5, 7]), 10**6):
print(n)
毫无疑问,可以改进对生成器的递归使用,但在实践中,对于我们的应用程序来说,性能已经足够好了。除此之外,我仍然对如何有效地从给定的最小值开始感兴趣,如Will Ness'中所述。感谢所有做出贡献的人。因为我们的应用程序是用python编写的,所以我提出了以下实现,希望与大家分享:
def powers(x):
y = x
while True:
yield y
y *= x
def products(factors):
y0 = factors[0]
if len(factors) == 1:
yield from powers(y0)
else:
yield y0
g1 = products(factors)
y1 = y0 * next(g1)
g2 = products(factors[1:])
y2 = next(g2)
while True:
if y1 < y2:
yield y1
y1 = y0 * next(g1)
else:
yield y2
y2 = next(g2)
if __name__ == "__main__":
import itertools
for n in itertools.islice(products([2, 3, 5, 7]), 10**6):
print(n)
毫无疑问,可以改进对生成器的递归使用,但在实践中,对于我们的应用程序来说,性能已经足够好了。除此之外,我仍然对如何有效地从给定的最小值开始感兴趣,如Will Ness'中所述。感谢所有的贡献者。你是说你想要2*2、2*3、2*5、2*n、3*3、3*5、3*n、5*5、5*n等等的结果吗?所有可能的素数乘积都是按升序排列的:。我不相信他要的序列是A00027。在我看来,理想的序列是所有可能的素数乘积的排序集。这意味着我们不能有2*2=4或2*3*3=18,因为存在重复项。为了澄清,应该包括2*2以及2*3*3和2*2*2。输入集中的每个因子都可以被使用任意次数。为什么不使用一个筛子呢?x有多大?素数集有多大?你是说你想要2*2,2*3,2*5,2*n,3*3,3*5,3*n,5*5,5*n等等的结果?所有可能的素数乘积都是升序:。我不相信他要的序列是A00027。在我看来,理想的序列是所有可能的素数乘积的排序集。这意味着我们不能有2*2=4或2*3*3=18,因为存在重复项。为了澄清,应该包括2*2以及2*3*3和2*2*2。输入集中的每个因子都可以被使用任意次数。为什么不使用一个筛子呢?x有多大?素数集有多大?优先级队列的大小为^2/3,因此会影响复杂性,这是不必要的,我曾经推导过,但现在记不起来了。这也意味着序列在队列中的^2/3个值上超过了第n个值。原来的Dijkstra算法只保留n个指针,n个给定的基素数,返回到已经生成的序列中,同样在距第n个元素^2/3的深度处;哪些指针输入优先级队列,但大小为固定的n,所以不会影响复杂性。所以就个人而言,我不喜欢这里的PQ,但当然是YMMV优先级队列的大小将为^2/3,因此将不必要地影响复杂性。我曾经推导过这个,但现在记不起来了。这也意味着序列在队列中的^2/3个值上超过了第n个值。原来的Dijkstra算法只保留n个指针,n个给定的基素数,返回到已经生成的序列中,同样在距第n个元素^2/3的深度处;哪些指针输入优先级队列,但大小为固定的n,所以不会影响复杂性。所以就个人而言,我不喜欢这里的PQ,但当然是YMMV在每个步骤上插入给定k个基素数的所有k个倍数会导致序列过多。原始的Dijkstra算法将k个指针保留回已经生成的序列中,并只将一个最小倍数插入序列中,使生成该序列的所有指针前进。下面是一个例子。在每个步骤上为给定的k个基素数插入所有k个倍数会导致序列过度生成。最初的Dijkstra算法将k个指针保留回已经生成的序列中,并只将一个最小倍数插入序列中,从而推进生成该序列的所有指针。