2012-09-04 162 views
0
for(a=1; a <= 25; a++){ 
    num1 = m[a]; 
    for(b=1; b <= 25; b++){ 
    num2 = m[b]; 
    for(c=1; c <= 25; c++){ 
     num3 = m[c]; 
     for(d=1; d <= 25; d++){ 
     num4 = m[d]; 
     for(e=1; e <= 25; e++){ 
      num5 = m[e]; 
      for(f=1; f <= 25; f++){ 
      num6 = m[f]; 
      for(g=1; g <= 25; g++){ 
       num7 = m[g]; 
       for(h=1; h <= 25; h++){ 
       num8 = m[h]; 
       for(i=1; i <= 25; i++){ 
        num = num1*100000000 + num2*10000000 + 
         num3* 1000000 + num4* 100000 + 
         num5* 10000 + num6* 1000 + 
         num7*  100 + num8*  10 + m[i]; 
        check_prime = 1; 

        for (y=2; y <= num/2; y++) 
        { 
        if (num % y == 0) 
         check_prime = 0; 
        } 

        if (check_prime != 0) 
        { 
        array[x++] = num; 
        } 
        num = 0; 
       }}}}}}}}} 

上面的代码花了很多时间来完成执行..实际上它甚至没有完成执行,我可以做什么来优化循环和加快执行?我是新手到cpp来优化嵌套循环

+3

For-mat-ting ... –

+6

您正在检查25^8个不同的数字是否与天真的因素搜索素数相符。这**肯定需要很长时间。 – Hbcdev

+0

25^8素数检查永远不会过快,但是通过将'for(y = 2; y <= num/2; y ++){...}'更改为'if(num> 2 && (y = 3; y * y <= num && check_prime; y + = 2){...}' – stefan

回答

1

您正在检查25 = 3,814,697,265,625数字是否为总数。这是很多主要测试,并且总是需要很长时间。即使在最好的情况下(对于性能来说),当所有数组条目(在m中)都是0(不必介意测试认为0是一个素数),以便试验分割循环从不运行,它将需要数小时才能运行。当m的所有条目均为正数时,代码将持续数百或数千年,此后每个数字将被试用除以50,000,000以上的数字。

望着总理检查,

check_prime = 1; 

for (y = 2; y <= num/2; y++) 
{ 
    if (num % y == 0) 
     check_prime = 0; 
} 

第一刺目的效率低下是一个除数已经发现的num的compositeness成立后也继续循环。 一旦知道结果就立即打开循环。

check_prime = 1; 

for (y = 2; y <= num/2; y++) 
{ 
    if (num % y == 0) 
    { 
     check_prime = 0; 
     break; 
    } 
} 

在不幸的情况下,所有的号码,你的测试是黄金,这不会改变任何事情,但如果所有(或几乎所有的近足够大的值)的数字是复合材料,它会将运行时间减少至少5000倍。

接下来的事情是,你分为num/2。这没有必要。为什么你停在num/2,而不是在num - 1?那么,因为你发现num的最大合适除数不能大于num/2,因为如果(num >) k > num/2,那么2*k > numnum不是k的倍数。

这很好,不是每个人都能看到的。

但你可以进一步追求这一思路。如果num/2num的除数,则表示num = 2*(num/2)(使用整数除法,但num = 3除外)。但是num是偶数,并且它的合成度已经由除数2确定了,所以如果成功的话,num/2的分割将不会被尝试。

那么需要考虑的最大除数的下一个可能候选项是什么? num/3当然。但如果这是num的除数,那么num = 3*(num/3)(除非num < 9)以及除以3已经解决了这个问题。

往前走,如果k < √numnum/knum,然后num = k*(num/k)除数,我们看到num具有较小的除数,即k(甚至可能是更小的)。

所以num的最小非平凡除数小于或等于√num因此,循环仅需要运行y <= √numy*y <= num。如果在该范围内未找到除数,则num是首要的。

现在的问题是是否循环

for(y = 2; y*y <= num; ++y) 

root = floor(sqrt(num)); 
for(y = 2; y <= root; ++y) 

第一需要一次乘法用于每次迭代循环条件,循环外的平方根中的第二个计算。

哪个更快?

这取决于num的平均大小以及许多是否为素数(更准确地说,取决于最小素数除数的平均大小)。计算平方根需要比乘法长得多,为了补偿成本,循环必须运行许多迭代(平均) - 无论“多”意味着超过20,超过100或超过1000,取决于。由于num大于10^8,这可能是这种情况,可能计算平方根是更好的选择。

现在我们已经限定的审判庭循环迭代的次数√num是否num是复合材料或素数,减少了至少5000因数运行时间(假设所有m[index] > 0,所以总是num >= 10^8),而不管测试的数字中有多少个素数。如果大多数值为num需要的是具有小质因子的复合材料,则缩小因子要大得多,通常运行时间几乎完全用于测试质数。

通过减少除数的候选数可以获得进一步的改进。如果num可以被4,6,8 ......整除,那么它也可以被2整除,所以即使y > 2num % y也不会产生0。这意味着所有这些部门都是多余的。通过特殊的外壳2和增量在2个步骤除数候选人,

if (num % 2 == 0) 
{ 
    check_prime = 0; 
} else { 
    root = floor(sqrt(num)); 
    for(y = 3; y <= root; y += 2) 
    { 
     if (num % y == 0) 
     { 
      check_prime = 0; 
      break; 
     } 
    } 
} 

分割数来执行和运行时间大致减半(假设已经够糟糕的情况下,对偶数的工作是可以忽略不计)。

现在,每当y是3(除3本身)的倍数,num % y将只当num不是3的倍数来计算,所以这些划分也是多余的。你也可以通过特殊套管3消除它们,并让y只能穿过不能被3整除的奇数(从y = 5开始,交替增加2和4)。这大约剩余工作的三分之一(如果存在足够的不良情况)。

继续是消除过程,我们只需要通过素数划分num不超过√num发现无论是黄金还是不是。

所以平时它是要找到不超过你会检查最大num的平方根的素数是一个好主意,将其存储在一个数组和循环

root = floor(sqrt(num)); 
for(k = 0, y = primes[0]; k < prime_count && (y = primes[k]) <= root; ++k) 
{ 
    if (num % y == 0) 
    { 
     check_prime = 0; 
     break; 
    } 
} 

除非最大值num能例如,如果你总是拥有num < 2^31,那么你应该在比特筛中找到该限制的素数,这样你就可以查找num是否在恒定时间内是质数(一个2^31位需要256 MB,如果你只有奇数的标志[需要特殊的外壳来检查num是否是偶数],你只需要128 MB来检查恒定时间的数字< 2^31的原始性,可以进一步减少筛子所需的空间)。

到目前为止对于主要测试本身。

如果m数组包含由2或5整除数,它可能是值得的重新排序的循环,具有用于i循环中的最外层,和由2或5跳过内部循环,如果m[i]整除 - 所有在添加之前其他数字乘以10的幂,因此num将是2的倍数。 5而不是素数。

但是,尽管如此,运行代码仍需要很长时间。九个嵌套循环讨厌错误的设计。

你试图做什么?也许我们可以帮助找到正确的设计。

+0

thnx帮助!!#%0 == 0){check_prime = 0;}实际上,我试图做的是给5×5网格输入n找到最大的素数,可以通过网格中输入的数字的组合(即小于1000000000)进行组合。 – JTN

+0

@jithinc所以这些数字都在'm []'数组中,都小于10吗?这个5x5网格中可能的条目范围是什么? –

+1

@jithinc因此,您应该按降序生成数字(如何做到最好取决于'm'上的约束条件,是否所有条目都小于10?哪些数字是重复的?),一旦找到了素数,就是这样,它是最大的。 –

6

用代码使用合理的算法替换此代码,如Sieve of Eratosthenes。最重要的“优化”是首先选择正确的算法。

如果您的数字排序算法是随机交换它们,直到它们按顺序排列,则无论您优化随机条目的选择,交换它们还是检查它们是否按顺序,都无关紧要。坏的算法无论如何都会导致糟糕的表现。

0

通过计算数字的每个部分,我们可以消除大量的冗余计算,因为它变得可用。这也示出了用于素性的试除法测试2-3轮高达数的平方根:

// array m[] is assumed sorted in descending order  NB! 
// a macro to skip over the duplicate digits 
#define I(x) while(x<25 && m[x+1]==m[x]) ++x; 
for(a=1; a <= 25; a++) { 
num1 = m[a]*100000000; 
for(b=1; b <= 25; b++) if (b != a) { 
    num2 = num1 + m[b]*10000000; 
    for(c=1; c <= 25; c++) if (c != b && c != a) { 
    num3 = num2 + m[c]*1000000; 
    for(d=1; d <= 25; d++) if (d!=c && d!=b && d!=a) { 
    num4 = num3 + m[d]*100000; 
    for(e=1; e <= 25; e++) if (e!=d && e!=c && e!=b && e!=a) { 
    num5 = num4 + m[e]*10000; 
    for(f=1; f <= 25; f++) if (f!=e&&f!=d&&f!=c&&f!=b&&f!=a) { 
     num6 = num5 + m[f]*1000; 
     limit = floor(sqrt(num6+1000)); /// 
     for(g=1; g <= 25; g++) if (g!=f&&g!=e&&g!=d&&g!=c&&g!=b&&g!=a) { 
     num7 = num6 + m[g]*100; 
     for(h=1; h <= 25; h++) if (h!=g&&h!=f&&h!=e&&h!=d&&h!=c&&h!=b&&h!=a) { 
     num8 = num7 + m[h]*10; 
     for(i=1; i <= 25; i++) if (i!=h&&i!=g&&i!=f&&i!=e&&i!=d 
                  &&i!=c&&i!=b&&i!=a) { 
      num = num8 + m[i]; 
      if(num % 2 /= 0 && num % 3 /= 0) { 
      is_prime = 1; 
      for (y=5; y <= limit; y+=6) { 
       if (num % y == 0) { is_prime = 0; break; } 
       if (num % (y+2) == 0) { is_prime = 0; break; } 
      } 
      if (is_prime) { return(num); } // largest prime found 
      }I(i)}I(h)}I(g)}I(f)}I(e)}I(d)}I(c)}I(b)}I(a)} 

此代码还消除了重复的索引。正如你在评论中指出的那样,你从5x5网格中挑选出你的号码。这意味着您必须使用所有不同的索引。这将减少从25^9 = 3,814,697,265,62525*24*23*...*17 = 741,354,768,000的测试数量。

由于您现在已经指出m[]数组中的所有条目都小于10,因此肯定会有重复项,这些重复项在搜索时需要跳过。正如丹尼尔指出的那样,从顶端寻找,首先发现的素数将是最大的。这是通过按降序对m[]数组进行预先排序来实现的。