2013-04-12 68 views
0

我想實現Eratosthenes Sieve的算法,但我不知道爲什麼這個程序崩潰的大型項目。最初我使用vector,但現在我正在使用動態內存分配來實現這一點。Eratosthenes實現的篩

#include<iostream> 
#include<cmath> 
#include<cstdlib> 
using namespace std; 

unsigned isqrt(unsigned value) { 
    return static_cast<unsigned>(sqrt(static_cast<float>(value))); 
} 

int main() 
{ 
    int t; 
    cin >> t; 
    long long * N; 
    long long * M; 
    long long n, m; 
    N = new long long[t]; 
    M = new long long[t]; 
    for(int i = 0; i < t ; i++){ 
     cin >> M[i] >> N[i]; 
    } 

    for(int i = 0; i < t ; i++){ 
     n = N[i]; 
     m = M[i]; 

     bool * A; 
     A = new bool[n]; 
     if(A == 0) 
     { 
      cout << "Memory cannot be allocated"; 
      return 0; 
     } 

     for(int i=0;i < n;i++){ 
      A[i]=true; 
     } 
     A[0] = false; 
     A[1] = false; 

     unsigned sqrt = isqrt(n); 
     for(int i = 2; i <= sqrt; i++) 
     { 
      if(A[i] == true){ 
       for(int j = i*i; j <= n; j = j + i) 
       { 
        A[j] = false; 
       } 
      } 
     } 

     for(int i = m;i < n;i++) 
     { 
      if(A[i] == true) 
       cout << i << "\n"; 
     } 

     delete[] A; 
    } 

    delete[] M; 
    delete[] N; 
    return 0; 
} 

程序崩潰對於較大的nm(〜10^16)值。請幫助我。

+2

我沒有看到問題,也沒有看到問題/錯誤。 – 2013-04-12 20:50:28

+0

程序粉碎 - 不是問題? – 4pie0

+0

'unsigned sqrt = isqrt(n)'**是** **。重新計算每個輸入對的篩網是多餘的。它應該只計算一次。 –

回答

4
for(int j = i*i; j <= n; j = j + i) 
        ^^ 

如果j == n然後A[j] = false將分配給過去陣列的端部的元素。測試應該是j < n

+0

但是,爲什麼只有在m和n值較大時纔會出現這種情況,而不是小值? –

+2

@mozart非法訪問內存導致C++中的未定義行爲。未定義行爲的結果不一定是可預測的。這與Java和Python等語言不同,它們幾乎總是以可預測和一致的方式崩潰。 –

+0

如此標準,這應該是禁止的 – 4pie0

-1

在調試器中運行以確定崩潰的位置並從那裏進行調試。這一點很可能會很明顯。

您可以從IDE或從命令行執行此操作。在後一種情況下編譯-g並運行程序,如gdb。谷歌的東西像「gdb cheatsheet」開始。

+0

SPOJ如何編譯和運行這些問題?它給了我SIGABRT。我沒有看到函數abort()的執行的任何原因。 –

+0

@mozart我不知道SPOJ是什麼。 – djechlin

+0

謝謝。無論如何,我的意思是 - > http://www.spoj.com –

1

如果n大到足以引起內存分配錯誤,程序將會崩潰,由於不正確的內存分配的錯誤處理

A = new bool[n]; 
     if(A == 0) 
     { 
      cout << "Memory cannot be allocated"; 
      return 0; 
     } 

新的錯誤不返回0,但拋出的std :: bad_alloc的那並不是」 t會被捕獲,這反過來會導致意外(),然後終止(),最後abort()被調用。
正確的版本是:

try 
    { 
    A = new bool[n]; 
    } 
    catch (std::bad_alloc& ba) 
    { 
    std::cerr << "Memory cannot be allocated: " << ba.what() << '\n'; 
    } 
2

如果你打算寫埃拉托色尼在C++篩子,怎麼樣,如果你確實使用 C++,不要試圖把它當作C的一些瘋狂的交叉和彙編語言。

#include <vector> 
#include <iostream> 

unsigned long primes = 0; 

int main() { 
    int number = 10000000; 
    std::vector<bool> sieve(number,false); 
    sieve[0] = sieve[1] = true; 

    for(int i = 2; i<number; i++) { 
     if(!sieve[i]) { 
      ++primes; 
      for (int temp = 2*i; temp<number; temp += i) 
       sieve[temp] = true; 
     } 
    } 
    std::cout << "found: " << primes << " Primes\n"; 
    return 0; 
} 
+0

這樣實現它沒有問題,但輸入是非常大的(〜10^16),這就是爲什麼我想使用指針而不是'矢量' 。該模板引入額外的開銷,但我實際上知道,我必須實現Eratosthenes分割Sieve解決問題。 –

+0

@mozart:你認爲模板增加了什麼開銷? [提示:它至少通常會做相反的事情,將每個bool存儲爲單個位,其中每個bool至少存儲一個字節。] –

+0

@SumitGera如果m〜10^16,那麼它的sqrt是〜 ...?不,你不需要*分段*篩選這個問題。核心篩沒有得到*擴展*;你應該只計算一次,然後分別篩選每個* offset *段和核心素數。 –