将优化的埃拉托色尼筛从 Python 移植到 C++

2023-12-09

前段时间,我在 python 中使用了(速度极快)primesieve,我在这里找到了它:列出 N 以下所有素数的最快方法

准确地说,这个实现:

def primes2(n):
    """ Input n>=6, Returns a list of primes, 2 <= p < n """
    n, correction = n-n%6+6, 2-(n%6>1)
    sieve = [True] * (n/3)
    for i in xrange(1,int(n**0.5)/3+1):
      if sieve[i]:
        k=3*i+1|1
        sieve[      k*k/3      ::2*k] = [False] * ((n/6-k*k/6-1)/k+1)
        sieve[k*(k-2*(i&1)+4)/3::2*k] = [False] * ((n/6-k*(k-2*(i&1)+4)/6-1)/k+1)
    return [2,3] + [3*i+1|1 for i in xrange(1,n/3-correction) if sieve[i]]

现在我可以通过自动跳过 2、3 等的倍数来稍微掌握优化的想法,但是当涉及到将此算法移植到 C++ 时,我陷入了困境(我对 python 有很好的理解,并且对C++,但对于摇滚乐来说已经足够了)。

我目前自己滚动的是这个(isqrt()只是一个简单的整数平方根函数):

template <class T>
void primesbelow(T N, std::vector<T> &primes) {
    T sievemax = (N-3 + (1-(N % 2))) / 2;
    T i;
    T sievemaxroot = isqrt(sievemax) + 1;

    boost::dynamic_bitset<> sieve(sievemax);
    sieve.set();

    primes.push_back(2);

    for (i = 0; i <= sievemaxroot; i++) {
        if (sieve[i]) {
            primes.push_back(2*i+3);
            for (T j = 3*i+3; j <= sievemax; j += 2*i+3) sieve[j] = 0; // filter multiples
        }
    }

    for (; i <= sievemax; i++) {
        if (sieve[i]) primes.push_back(2*i+3);
    }
}

这个实现很不错,会自动跳过 2 的倍数,但如果我可以移植 Python 实现,我认为它会快得多(50%-30% 左右)。

比较结果(希望这个问题能够成功回答),当前执行时间与N=100000000, g++ -O3在 Q6600 Ubuntu 10.10 上为 1230 毫秒。

现在我希望得到一些帮助,帮助我理解上面的 Python 实现的作用,或者你可以帮我移植它(虽然没有那么有帮助)。

EDIT

关于我觉得困难的一些额外信息。

我对校正变量等所使用的技术以及一般情况下如何组合在一起感到困难。一个解释不同埃拉托色尼优化的网站的链接(除了那些简单的网站说“好吧,你只需跳过 2、3 和 5 的倍数”,然后用 1000 行 C 文件猛击你)会很棒。

我不认为我会对 100% 直接和文字移植有任何问题,但毕竟这是为了学习,这是完全没有用的。

EDIT

查看原始 numpy 版本中的代码后,它实际上非常容易实现,并且经过一些思考也不太难理解。这是我想出的C++版本。我将其完整版本发布在这里,以帮助更多的读者,以防他们需要一个不超过 200 万行代码的非常高效的 p​​rimesieve。这个 primesieve 在与上述相同的机器上大约 415 毫秒内完成 100000000 以下的所有素数。速度提升了 3 倍,比我预期的要好!

#include <vector>
#include <boost/dynamic_bitset.hpp>

// http://vault.embedded.com/98/9802fe2.htm - integer square root
unsigned short isqrt(unsigned long a) {
    unsigned long rem = 0;
    unsigned long root = 0;

    for (short i = 0; i < 16; i++) {
        root <<= 1;
        rem = ((rem << 2) + (a >> 30));
        a <<= 2;
        root++;

        if (root <= rem) {
            rem -= root;
            root++;
        } else root--;

    }

    return static_cast<unsigned short> (root >> 1);
}

// https://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
// https://stackoverflow.com/questions/5293238/porting-optimized-sieve-of-eratosthenes-from-python-to-c/5293492
template <class T>
void primesbelow(T N, std::vector<T> &primes) {
    T i, j, k, l, sievemax, sievemaxroot;

    sievemax = N/3;
    if ((N % 6) == 2) sievemax++;

    sievemaxroot = isqrt(N)/3;

    boost::dynamic_bitset<> sieve(sievemax);
    sieve.set();

    primes.push_back(2);
    primes.push_back(3);

    for (i = 1; i <= sievemaxroot; i++) {
        if (sieve[i]) {
            k = (3*i + 1) | 1;
            l = (4*k-2*k*(i&1)) / 3;

            for (j = k*k/3; j < sievemax; j += 2*k) {
                sieve[j] = 0;
                sieve[j+l] = 0;
            }

            primes.push_back(k);
        }
    }

    for (i = sievemaxroot + 1; i < sievemax; i++) {
        if (sieve[i]) primes.push_back((3*i+1)|1);
    }
}

我会尽力解释。这sieve数组有一个不寻常的索引方案;它为每个与 1 或 5 mod 6 一致的数字存储一个位。因此,一个数字6*k + 1将被存储在位置2*k and k*6 + 5将被存储在位置2*k + 1. The 3*i+1|1操作是相反的:它采用以下形式的数字2*n并将它们转换成6*n + 1,并取2*n + 1并将其转换为6*n + 5 (the +1|1事物转变0 to 1 and 3 to 5)。主循环迭代k遍历具有该属性的所有数字,从5 (when i is 1); i是对应的索引sieve对于数字k。第一个切片更新为sieve然后清除筛子中具有以下形式索引的所有位k*k/3 + 2*m*k (for m自然数);这些索引的相应数字开始于k^2并增加6*k在每一步。第二个切片更新从索引处开始k*(k-2*(i&1)+4)/3(数字k * (k+4) for k一致于1 mod 6 and k * (k+2)否则)并类似地将数量增加6*k在每一步。

这是另一种解释尝试:让candidates是至少为 5 并且与任一数字全等的所有数字的集合1 or 5 mod 6。如果将该集合中的两个元素相乘,则会得到该集合中的另一个元素。让succ(k)对于一些k in candidates是下一个元素(按数字顺序)candidates大于k。在这种情况下,筛子的内循环基本上是(使用正常索引sieve):

for k in candidates:
  for (l = k; ; l += 6) sieve[k * l] = False
  for (l = succ(k); ; l += 6) sieve[k * l] = False

由于存储元素的限制sieve,这与:

for k in candidates:
  for l in candidates where l >= k:
    sieve[k * l] = False

这将删除所有倍数k in candidates(以外k本身)在某个点(或者当当前k被用作l更早或当它被用作k now).

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将优化的埃拉托色尼筛从 Python 移植到 C++ 的相关文章

  • Python,多线程,获取网页,下载网页

    我想在一个站点批量下载网页 我的 urls txt 文件中有 5000000 个 url 链接 大约有300M 如何让多线程链接这些网址并下载这些网页 或者如何批量下载这些网页 我的想法 with open urls txt r as f
  • 如何在交互式绘图(Python)中获得鼠标指向的(x,y)位置?

    我使用 ipython 笔记本 带有魔法 matplotlib nbagg 我正在审查matplotlib widget Cursor但仅查看光标widgets Cursor http matplotlib org 1 4 3 exampl
  • 如何在 Linq 中获得左外连接?

    我的数据库中有两个表 如下所示 顾客 C ID city 1 Dhaka 2 New york 3 London 个人信息 P ID C ID Field value 1 1 First Name Nasir 2 1 Last Name U
  • 将 Excel 导入到 Datagridview

    我使用此代码打开 Excel 文件并将其保存在 DataGridView 中 string name Items string constr Provider Microsoft Jet OLEDB 4 0 Data Source Dial
  • 检查多个 pd.DataFrame 是否相等

    是否有一种 Pythonic 方式 无循环或递归 来检查是否超过两个pd DataFrames 例如 pd DataFrames 列表 彼此相等吗 就像是 all x equals dfs 0 for x in dfs with dfs数据
  • 在一个字节中存储 4 个不同的值

    我有一个任务要做 但我不知道从哪里开始 我不期待也绝对不想要代码中的答案 我想要一些关于该怎么做的指导 因为我感到有点失落 将变量打包和解包到一个字节中 您需要在一个字节中存储 4 个不同的值 这些值为 NAME RANGE BITS en
  • 使用 Python 脚本打开特定文件类型?

    如何使 Python 脚本成为特定文件类型 例如 foo 的默认应用程序 例如 当我双击 Finder Explorer 中的文件时 我希望该文件在 Python 脚本中打开 这可以在 Win 和 或 OS X 中实现吗 如果重要的话 该应
  • Visual Studio 中的测试单独成功,但一组失败

    当我在 Visual Studio 中单独运行测试时 它们都顺利通过 然而 当我同时运行所有这些时 有些通过 有些失败 我尝试在每个测试方法之间暂停 1 秒 但没有成功 有任何想法吗 在此先感谢您的帮助 你们可能有一些共享数据 检查正在使用
  • Scrapy的redirect_urls异常.KeyError

    我是 Scrapy 和 Python 的新手 最近推出了我的第一个蜘蛛 有一个功能似乎以前有效 但现在它只适用于我试图废弃的一些网站 代码行是 item url direct response request meta redirect u
  • 使用 statsmodels.formula.api 中的 ols - 如何删除常数项?

    我正在遵循第一个例子statsmodels教程 http statsmodels sourceforge net devel http statsmodels sourceforge net devel 如何指定在 ols 中不使用常数项进
  • Python 中的十进制到二进制半精度 IEEE 754

    我只能使用以下命令将十进制转换为二进制单精度 IEEE754struct pack模块 或者使用相反的方法 float16 或 float32 numpy frombuffer 是否可以使用 Numpy 将十进制转换为二进制半精度浮点数 我
  • 如何使用 pygame.mixer 重复音乐?

    我创建了以下使用 pygame mixer 播放 mp3 音乐的代码 然而 音乐不会重复 有什么想法可以让音乐重复播放吗 这是代码 playlist list playlist append put music here mp3 playl
  • 如何限制scrapy请求对象?

    所以我有一个蜘蛛 我认为它正在泄漏内存 结果当我检查 telnet 控制台 gt gt gt prefs 时 它只是从链接丰富的页面中抓取了太多链接 有时它会超过 100 000 个 现在我已经一遍又一遍地浏览文档和谷歌 但我找不到一种方法
  • 有人可以提供一个使用 Amazon Web Services 的 itemsearch 的 C# 示例吗

    我正在尝试使用 Amazon Web Services 查询艺术家和标题信息并接收回专辑封面 使用 C 我找不到任何与此接近的示例 所有在线示例都已过时 并且不适用于 AWS 的较新版本 有一个开源项目CodePlex http www c
  • .NET中的LinkedList是循环链表吗?

    我需要一个循环链表 所以我想知道是否LinkedList是循环链表吗 每当您想要移动列表中的 下一个 块时 以循环方式使用它的快速解决方案 current current Next current List First 电流在哪里Linke
  • gcc 的配置选项如何确定默认枚举大小(短或非短)?

    我尝试了一些 gcc 编译器来查看默认枚举大小是否很短 至少一个字节 强制使用 fshort enums 或无短 至少 4 个字节 强制使用 fno short enums user host echo Static assert 4 si
  • 在多个图表上绘制一条线

    I don t know how this thing is called or even how to describe it so the title may be a little bit misleading The first a
  • 英特尔 Pin 与 C++14

    问题 我有一些关于在 C 14 或其他 C 版本中使用英特尔 Pin 的问题 使用较新版本从较旧的 C 编译代码很少会出现任何问题 但由于 Intel Pin 是操作指令级别的 如果我使用 C 11 或 C 14 编译它 是否会出现任何不良
  • memset 未填充数组

    u32 iterations 5 u32 ecx u32 malloc sizeof u32 iterations memset ecx 0xBAADF00D sizeof u32 iterations printf 8X n ecx 0
  • 如何使用 Word Automation 获取页面范围

    如何使用办公自动化找到 Microsoft Word 中第 n 页的范围 似乎没有 getPageRange n 函数 并且不清楚它们是如何划分的 这就是您从 VBA 执行此操作的方法 转换为 Matlab COM 调用应该相当简单 Pub

随机推荐

  • 为什么使用 Collection.empty[T] 而不是 new Collection[T]()

    我想知道是否有充分的理由使用Collection empty T 代替new Collection T 或相反 或者这只是个人喜好 Thanks Calling new Collection T 每次都会创建一个新实例 另一方面 Colle
  • Azure 应用程序网关出现错误 404,但后端探测正常

    我已经设置了应用程序网关 并在我的域中添加了 CNMAME 以指向应用程序网关的 DNS 名称 应用网关最终将指向3个站点 我创建了 3 个 Web 应用程序 并将每个应用程序添加到后端池中 我最初使用默认的 HTTP 设置 appGate
  • 使用 Selenium 使用 WindowHandles 跟踪和迭代选项卡和窗口的最佳方法

    我们正在与 Selenium webdriver 合作 为 Internet Explorer 11 进行 UI 测试 在测试的 Web 应用程序中 会弹出几个屏幕 在一些测试中 我们最终得到了三个浏览器窗口 因此也得到了三个 Driver
  • Django日月事件日期查询

    我有一个 Django 模型 如下所示 class Event models Model name model CharField etc date model DateField etc 我需要的是一种获取给定日期和月份的所有事件的方法
  • 在画布中创建多个可拖动的圆圈

    我在 HTML 画布中制作多个可拖动的圆圈时遇到问题 我真的不知道我做错了什么 希望有人能指出我的错误 这里是菜鸟 所以请不要猛烈抨击 我在这里附上了我的代码 var canvas document getElementById canva
  • 使用 Kivy 检索 MySQL

    我有一个 Kivy 代码 其输出是 我想更换Box No 从 MySQL 检索字符串 到目前为止 我已经尝试将 MySQL 实现到 python 脚本中 class RemoveScreen MyLayout def init self k
  • 为什么在 Android 模拟器中单击“调试”时 React Native 应用程序会崩溃?

    在 Android 模拟器中单击 调试 时 React Native 应用程序显示错误 尝试在空对象引用上调用接口方法 java lang String com facebook react bridge Cat alystInstance
  • 不使用 + 运算符将两个数字相加的最佳方法是什么?

    我和一个朋友正在反复玩脑筋急转弯 但我不知道如何解决这个问题 我的假设是某些按位运算符是可能的 但不确定 在 C 语言中 使用按位运算符 include
  • 如何在 Visual Studio 2019 中将清单文件添加到我的 C# 程序?

    我有一个简单的应用程序 我想强制在管理模式下运行 为此 我需要编辑清单文件 我看到教程显示通过单击 项目 gt 添加 gt 新项目 来添加它 但那里没有适合我的清单文件 我尝试制作自己的文件 并将其从项目属性设置为清单文件 但我不知道在那里
  • 传递给 readFileSync 的匿名函数不返回任何数据

    我写了一个简单的JS对象 它有功能csvFileToArray 函数应返回解析后的 CSV 数组 问题是我没有传递给匿名函数的输出readFileSync test1已正确记录到控制台 但是test2 is not 这是我第一次使用 nod
  • 如何使用 bash 从 URL 字符串获取维度

    我在 mac 上使用 bash 并有一个 URL 字符串 我想从包含如下尺寸的 URL 中提取宽度和高度值 url domain com project asset 300x250 july2 url domain com project
  • 使用 Office Web Apps,您可以通过 webdav 打开文档吗?

    我们正在将旧的桌面应用程序转换为支持网络的等效应用程序 然而 有一个功能造成了困难 即编辑 MS Word 文档 当前提出的解决方案是通过 WebDAV 发布 DOC 和 DOCX 文件 并使用自定义 ActiveX 组件启动 WinWor
  • scanf 一个大的十六进制值

    我在尝试使用 scanf 从用户处获取大的十六进制数字 12 个字符 时遇到问题 它似乎只得到最后8个字符 例如 ABFFFFFFFF将变成0000FFFFFFFF 这是我的代码 unsigned long long address sca
  • datetimepicker 在单击外部时将日期设置为今天的日期

    我到处寻找这个问题的答案 但没有运气 所以现在我不得不问 我有 Trent Richardson 的日期时间选择器 由于某种原因 设置的选项非常少 当我单击外部而不选择日期时 它会自动将日期字段设置为今天的日期 有人知道发生了什么事吗 这是
  • java进程中有很多线程

    为什么一个简单的 Java GUI 应用程序要创建这么多线程 Java 使用线程来做很多事情 当然是应用程序的主线程 应用程序启动的任何线程 例如 SwingWorker Swing 有一个单独的事件调度线程以及一些其他内务线程 计时器 其
  • 解码音频和视频并处理两个流——ffmpeg、sdl、opencv

    我的目标是独立处理 mpeg 2 文件的音频和视频 并保持两个流的同步性 视频时长最多约为 1 或 2 分钟 首先 按照这个post opencv 用于读取视频 并执行处理 ffmpeg 用于音频 SDL 用于播放两者 听起来很完美 考虑到
  • 如何删除正文周围的边距空间或清除默认的 css 样式

    我诚然是一个初学者 但在发布此内容之前我也做了相当多的搜索 我的 div 元素周围似乎有额外的空间 我还想指出的是 我尝试了 border 0 padding 0 等多种组合 但似乎没有什么可以消除空白 这是代码
  • 从字符串中删除特定标记

    我必须从字符串变量中删除特定标记 例如 如果字符串变量是这样的 GUID 456709876790 我需要删除 GUID 从字符串中分离出来 只需要 456709876790 如何做呢 两种选择 当你刚刚从start 你可以很容易地使用子字
  • 在ggplot中使用geom_vline()复制图例

    我想创建这个图形 aux graf structure list lines structure c 2L 2L 1L 3L Label c h0 ic median class factor values c 21 19755 23 06
  • 将优化的埃拉托色尼筛从 Python 移植到 C++

    前段时间 我在 python 中使用了 速度极快 primesieve 我在这里找到了它 列出 N 以下所有素数的最快方法 准确地说 这个实现 def primes2 n Input n gt 6 Returns a list of pri