【问题标题】:Why does my Assembly code run in linear time when it should run in O(N*sqrt(N)) time?为什么我的汇编代码应该在 O(N*sqrt(N)) 时间运行时以线性时间运行?
【发布时间】:2013-12-28 18:01:08
【问题描述】:

所以我正在用汇编语言编写一个素数生成器(以学习语言),当我开始对程序进行基准测试时,我发现它运行的是线性时间,而不是预期的 O(N * sqrt(N)) 时间。

为什么会这样?

我浏览并评论了代码并将其放在 github 上:https://github.com/kcolford/assembly_primes。它应该是相当可读的,但如果有人想让我更彻底地评论它(比如对每条指令的解释),我很乐意这样做,我只是认为没有必要。

我使用的汇编器和链接器是在 GNU binutils 中找到的,它是为运行 linux 内核的 x86_64 架构编写的。

【问题讨论】:

  • 1.你已经确认它给出了正确的答案? 2. 您的样本量足够大,以至于启动时间等是结果中的小噪音? 3. 你没有一个很大的线性系数来压倒一个小的 Nsqrt(N) 系数?
  • 汇编代码简洁而健壮,是的,所有答案都是正确的(python 脚本花了很长时间才能遍历整个文件),它最终处理了 100,000,000 个数字。唯一的开销存在于打印数字的 IO 例程中。
  • 自从我进行任何顺序计算以来已经很久了,但是你已经描述了它是最坏情况的运行时间,如果对于每个数字 N 它必须查看它必须查看所有素数高达 sqrt(N)。事实并非如此,如果我的挥手数学足够好(可能不是),它更像是 log(N),甚至是 log log(N)
  • 您正在构建一个先验素数表,该表用作任何值 N 的过滤器。您需要查看该表的增长率以确定二阶项。此表的增长率由prime number theorum 决定。我发布的时候是凌晨 1 点,这就是我挥手回答的原因。

标签: linux performance assembly x86-64


【解决方案1】:

Big-O 复杂度很难通过实验来衡量。就像 Phil Perry 建议的那样,经常有线性术语(或其他术语)压倒“小”运行的主要 O() 术语。这些隐藏在大 O 表示法中的额外术语始终存在于实际代码中,并且在分析某物的实际运行时间时是必需的。

当我在我的测试机器上测量你的示例代码时,我得到一个明显的非线性关系。由于声誉低,我无法发布情节,但这里有一张表格:

N (= n^2)     Time
  1000000    0.386
  4000000    1.846
  9000000    4.673
 16000000    9.275
 25000000   15.850
 36000000   24.690
 49000000   35.850
 64000000   49.887
 81000000   66.509
100000000   86.855

另外,我没有彻底查看您对算法的确切实现,但 Sieve of Eratosthenes 是 O(n log log n),而不是 O( n sqrt(n)).

还要注意,与数字运算相比,I/O 通常非常昂贵。在您的情况下,在我的测试机器上,在 n = 5000 时,I/O 几乎占总运行时间的 30%。这将是运行时分析中的重要线性项。您必须彻底分析代码正在执行的所有其他操作,以找出影响测量的其他因素。

【讨论】:

    猜你喜欢
    • 2021-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多