对于为什么我的算法运行速度比它应该慢感到困惑
Confused as to why my algorithm is running slower than it should be
纯粹为了好玩,我决定写一个简单的算法来找到2到x之间的所有素数,其中x是你想要的任何数字。我使用clock_t
来计算算法完成不同x值所需的时间。(我让x=0,然后25000,然后50000,然后75000,…(最多1,000,000)。例如,当x = 25000时,我进入一个For循环,i
从2到25000,对于i
的每个值,我通过将其除以2和自身之间的每个数字来检查它是否为素数,寻找余数为0。
算法如下:
vector<int> calcPrimesWithoutPrechecking(int upperLimit)
{
vector<int> res;
for(int i = 2; i <= upperLimit; i++)
{
int currentNum = i;
bool foundDivisible = false;
for(int j = 2; j < currentNum; j++)
{
if(currentNum % j == 0)
{
foundDivisible = true;
break;
}
}
if(!foundDivisible)
{
res.push_back(i);
}
}
return res;
}
我想我可以通过检查我们正在测试的数字的最后一位来加快速度。如果那个数字是0 2 4 5 6 8,那么我甚至不用检查它是不是质数因为我知道它不是质数(当然2 3 5是质数,所以这些是在开始处理的)我叫它预检。以下是带有预检的算法:
vector<int> calcPrimesWithPrechecking(int upperLimit)
{
vector<int> res;
res.push_back(2);res.push_back(3);res.push_back(5);
for(int i = 6; i <= upperLimit; i++)
{
bool foundDivisible = false;
int lastDig = i%10;
if(lastDig == 0
|| lastDig == 2
|| lastDig == 4
|| lastDig == 6
|| lastDig == 8
|| lastDig == 5)
{
foundDivisible = true;
}
int currentNum = i;
for(int j = 2; j < currentNum && !foundDivisible; j++)
{
if(currentNum % j == 0)
{
foundDivisible = true;
break;
}
}
if(!foundDivisible)
{
res.push_back(i);
}
}
return res;
}
我将结果输出到控制台,并将它们写入一个文本文件。然后我将时间复制到excel中,并绘制它们。然而,由于某些原因,带有预检查的算法速度较慢。我几乎可以肯定它会更快。当我运行程序时,我故意关闭电脑上的每个程序,并以释放模式运行它。我已经在调试中测试了每个算法,它们确实都按预期工作。
这是我的数据。
x轴是我们要检查的质数(例如25000意味着我们要寻找2到25000之间的所有质数),y轴是得到所有质数的时间(以秒为单位)。
谁能解释一下为什么第二个算法,理论上应该减少许多计算,实际上更慢?
使用预检查的实现稍微慢一点的原因是,它需要做更多的工作来消除许多在内部循环的第一步之后就会消除的数字。
以数字8
为例:预检查需要找到一个除数余数并进行五次比较才能消除它,而不进行预检查的程序也消除了8
,但只进行了一次除2和与零的比较。
您可能看到的唯一一个稍微占上风的数字是5
,但这些数字不像偶数那么常见,否则您的程序会损失CPU周期。
加快速度的更好方法是完全避免偶数:回想一下,3
之后的所有素数都是6*k+1
或6*k-1
的形式之一。现在你的迭代速度几乎是原来的三倍!
另一件事是,你不需要检查候选素数的平方根之后的除数(你能证明为什么这样吗?)这一改变将会给你带来巨大的进步。
最后,一个非常有用的技巧是存储到目前为止发现的所有质数,并将它们用作你的试除数。这将大大提高内部循环的速度。
因为它并没有省去很多计算。如果一个数字是偶数,在检查它是否能被2整除(这是你在循环中检查的第一个数字)时,会立即发现它。这比你在这里做的快多了:
int lastDig = i%10;
if(lastDig == 0
|| lastDig == 2
|| lastDig == 4
|| lastDig == 6
|| lastDig == 8
|| lastDig == 5)
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 为什么我的代码在输出中增加了93天
- 为什么我的for循环不能正确获取argv
- 当我在main中声明了我的2d数组时,为什么我的程序会退出
- 为什么我的 std::ref 无法按预期工作?
- 为什么我的删除节点函数实际上没有删除节点?
- 为什么我的 IExtractIcon 处理程序没有被调用?
- 为什么我的多线程作业队列崩溃
- 为什么我的排序算法会更改数组值
- 为什么我的变量没有更新,我的 LED 没有亮起?
- 为什么我的程序在for循环中k=0时返回垃圾值
- 为什么我的点没有在 OpenGL 中绘制鼠标所在的位置?
- 为什么我的共享库中存在展开符号
- 为什么我的C++代码中出现'Segmentation Fault: 11'行?
- 为什么我的递归函数按降序打印,然后按升序打印?
- 为什么我的 heap.h 文件给我一个LNK2001错误?
- 为什么我的好友类无法访问私人会员?
- 为什么我的C++程序的程序集输出充满了 .ascii,没有汇编代码?
- 为什么我的模板化函数需要从一个迭代器转换到另一个迭代器?