C 投影欧拉问题10-高效算法
我尝试了Project Euler的问题10,使用了非常简单的算法,运行时间看起来像几个小时。所以我在谷歌上搜索了一个有效的算法,并通过。 代码复制如下:C 投影欧拉问题10-高效算法,c,C,我尝试了Project Euler的问题10,使用了非常简单的算法,运行时间看起来像几个小时。所以我在谷歌上搜索了一个有效的算法,并通过。 代码复制如下: int main(int argc, char * argv[]) { int p, i; int mark_limit; long long sum = 0; memset(bitmask, '\0', sizeof(bitmask)); mark_limit = (int)sqrt(limit);
int main(int argc, char * argv[])
{
int p, i;
int mark_limit;
long long sum = 0;
memset(bitmask, '\0', sizeof(bitmask));
mark_limit = (int)sqrt(limit);
for (p=2 ; p <= mark_limit ; p++)
{
if (! ( bitmask[p>>3]&(1 << (p&(8-1))) ) )
{
/* It is a prime. */
sum += p;
for (i=p*p;i<=limit;i+=p)
{
bitmask[i>>3] |= (1 << (i&(8-1)));
}
}
}
for (; p <= limit; p++)
{
if (! ( bitmask[p>>3]&(1 << (p&(8-1))) ) )
{
sum += p;
}
}
intmain(intargc,char*argv[])
{
int p,i;
int标记_限制;
长和=0;
memset(位掩码,'\0',sizeof(位掩码));
mark_limit=(int)sqrt(limit);
对于(p=2;p>3)&(13)|=(13)&(1>3)&(13)|=(1>3)]&(1位掩码充当一个位数组。由于不能单独寻址位,因此必须先访问字节,然后修改其中的一位。右移3等于除以8,这将使您位于正确的字节。然后,将一位移到适当的位置,再将余数移到适当的位置
x> >3相当于x/8
x&(8-1)相当于x%8
但在一些较旧的系统上,位操作可能更快
该行设置第i位,其中i被确定为非素数,因为它是另一个素数的倍数:
bitmask[i>>3] |= (1 << (i&(8-1)));
bitmask[i>>3]|=(1该代码是一个经过修改的Eratosthenes筛。他将一个数字压缩成一个位:0
=prime,1
=composite。位移位是为了在字节数组中找到正确的位
bitmask[p>>3]
相当于
bitmask[p / 8]
它在位掩码[]
数组中选择正确的字节
(p&(8-1))
等于p&7
,它选择p
的较低3位。这相当于p%8
总的来说,我们正在选择字节位掩码[p/8]
的位(p%8)
。也就是说,我们正在位掩码[]
数组中选择表示数字p的位
1位操作从来没有更快过。最早的C编译器能够自动完成。大多数编译器即使在优化关闭的情况下也能完成。@Dietrich Epp实际上还有很多编译器无法完成优化,除非明确要求。如果程序性能至关重要(只有这样),而且代码应该是可移植的,优化“轮班分工”可能是个好主意手动,即使它使代码变得丑陋,而且远不如可读。@ Lundin:这有点令人惊讶。你能给出任何例子吗?@沃恩:那么X/8和X% 8如何能够确定素数吗?这样你就可以用BIT或向量(专门容器)在C++中得到相同的打包。没有位技巧。即使在C语言中,你也应该使用抽象从位到数组的映射的函数。编写这样的代码是不好的风格。你能进一步解释为什么使用“8”吗?p可以大得多,比如100000。8有什么特别之处,它被用作“基”在这些位移位中?还有,为什么1@Standstill,筛是一个逻辑位数组。如果位N
为on或true,则数字N
为素数。这些位被实现为8位字节数组。这就是神奇数字8的来源。筛可以同样轻松地用16/32/64位元素实现在这种情况下,常数将被更改为匹配。位移位和屏蔽操作用于寻址所需的字节,然后寻址其中的特定位。@STANDSTART:@BLASTBURN是正确的,8
是一个字节中的位数。手动从p=5
到p=11
通过一些示例来了解f或其他。ANDing是检查位掩码[p/8]中的位
已设置:1&1=1
,0&1=0
。该位标志着p
是否为素数。我建议您仔细阅读Eratosthenes的筛选。编写您自己的更简单的实现,这将帮助您了解这里的代码在做什么。谢谢。我认为这些信息足以让我进行研究。
bitmask[p / 8]
(p&(8-1))