2012-09-04 161 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[]數組進行預先排序來實現的。