我有一段代码,我想测量它的时间效率。由于从代码本身估计这种复杂性很难,我想把它放在循环中并对结果计时。一旦收集到足够的数据点(大小 - >时间),我就可以看到哪条曲线最适合。
使用给定大小的随机输入数据多次重复操作可以消除由于OS决定在不良时刻进行多任务而导致的波动,从而产生更精确的时间。增加问题的大小可以提供更多的点,理想情况下间距很大。
我的测试代码工作正常(初始,非定时预热循环以减少加载时间;然后,从10的大小开始,以10%的增量扩展到1000000,重复运行直到5s已经过去或5次完整运行完成)。但是,我通过猜测来得出这些数字。
是否已接受,"科学"如何扩展重复和问题大小以实现更快,更准确的时间尺寸图?是否存在可以支撑所有无聊位的代码(或库),我应该知道之前的代码滚动我,自己的?特别是,我可以认为,当发现时间上的颠簸时,可以采取更多措施 - 虽然可以简单地考虑相对平稳的读数"足够好"。
修改
我知道计算大O复杂度的经典方法。它适用于具有良好代表性操作的自包含算法(例如,"比较"或"交换")。当不满足这些条件时,它不像宣传的那样工作(例如:LLVM的编译时C ++模板实例化成本,这是一个庞大而复杂的,我不知道相关的代表操作是什么)。这就是为什么我把它当作一个黑盒子,并试图从外面测量时间而不是代码检查。
答案 0 :(得分:5)
测量时间复杂度可能非常困难(如果可能的话),我从未在算法论文中看到过这种情况。如果您无法根据(伪)代码或算法描述计算时间复杂度,那么也许您可以使用启发式来简化分析。
也许您还可以计算算法某些部分的复杂性,如果它们的复杂性明显小得多,则忽略其他部分。
如果没有任何帮助,通常的方法是显示算法如何在机器上缩放,就像你写的那样。 但是有许多因素会影响结果。只是注意其中一些:
总而言之:我认为你只能得到一个想法,你的算法如何扩展,但你无法通过测量运行时来精确地获得复杂性的上限。也许这适用于非常小的例子,但对于较大的例子,你将得不到正确的结果。
你能做的最好的事情是:
通过这种方式,您可以查看更改是否改进了算法,其他人可以验证您的结果。
关于输入:
答案 1 :(得分:2)
我不知道有任何软件或之前完成的工作。而且,从根本上说,我认为你不能得到值得信赖的“O(无论如何)”形式的答案。您的测量结果很嘈杂,您可能正在尝试将n log(n)操作与n sqrt(n)操作区分开来,并且与一个干净的数学分析不同,所有丢弃的常量仍然在混乱中和你在一起。
那就是说,如果我想得出最好的估计,我会经历这个过程:
答案 2 :(得分:2)
首先,我不知道一种可接受的,“科学的”扩展重复和问题大小的方法,以实现更快,更准确的时间尺寸图,所以我不能就此事发表任何意见。
除此之外,为了更好地测量时间复杂度,我建议测量固定大小的平均执行时间,并将其与上一周期中测量的平均执行时间进行比较。之后,增加输入数据的大小并重复测量。
这类似于Numerical Analysis到estimate errors of numerical methods中使用的方法之一。您只需调整它来估算算法实现执行时间的平均误差。
所以,简而言之:
如果不清楚,请告诉我。
答案 3 :(得分:1)
假设您在循环中运行以下内容。在迭代 i = 0,1,2,.... ,对于某些固定的 n_0> 0 和非常大的 n ,您在 1的范围内 2 i + n_0 等距离(直到舍入)点对函数进行采样, ...,n 。然后,您可以执行以下任一操作或两者的组合:
使用偶数点训练样条曲线并在奇数点上进行测试(反之亦然)。如果 l2 错误低于某个阈值,则确定迭代就足够了。
使用所有点训练样条线,并在值上测试,例如 2n 。再次,如果 l2 错误低于某个阈值,则决定迭代是否足够。
第1点强调插值误差,第2点强调外推误差。实际上,我认为您最多能够识别样条函数描述的函数。
根据您使用的拟合方法,您可能需要为样条方法拟合一些元参数。在这种情况下,您可能需要在每次迭代时使用多个 ~2 i 样本,因为您可能需要使用其中一些样本进行参数调整交叉验证。
答案 4 :(得分:0)
如果您想要获得复杂性的黑盒估计,请使用“比率法”。例如:如果您坐在紧密循环中执行固定长度的作业,例如将随机记录插入数据库,则会在每次迭代结束时记录时间戳。随着更多数据进入,时间戳将开始变得更远。因此,然后绘制连续时间戳之间的时间差。
如果你将该图除以lg [n]并继续上升,那么它比lg [n]更糟糕。尝试除以:lg [n],n,n lg [n],n n等。当您除以估计值过高的函数时,则曲线趋势为零。当你除以一个太低的函数时,情节将继续攀升。如果你有一个很好的估计,那么你的数据集中有一个点可以放置图形四处漂移的上限和下限,以便你可以检查。