#c #sieve-of-eratosthenes #sieve
#c #сито Эратосфена #сито
Вопрос:
Я прочитал о решете Эратосфена, решая вопрос по проекту Эйлера. Я уверен, что вы, ребята, знаете, о каком вопросе я говорю. Итак, вот в чем дело. Моему коду удается правильно отображать все простые числа до 1 миллиона. Однако, когда я пробую ту же реализацию для 2 миллионов, это приводит к ошибке сегментации… У меня есть определенное представление о том, почему возникает ошибка, но я не знаю, как ее исправить… Вот код для простых чисел до 1 миллиона.
#include<stdio.h>
int main(void)
{
int i,k=2;
int j;
int n=1000000;
int prime[2000000]={};
for(i=0;i<n;i ) // initializes the prime number array
{
prime[i]=i;
}
for(i=2;i<n;i ) // Implementation of the Sieve
{
if(prime[i]!=0)
{
for(j=2;j<n;j )
{
{
prime[j*prime[i]]=0;
if(prime[i]*j>n)
break;
}
}
}
}
for(i=0;i<n;i ) // Prints the prime numbers
if(prime[i]!=0)
{
printf("%dn"prime[i]);
}
return(0);
}
}
Комментарии:
1. Вы для того, чтобы перейти
int n=1000000;
наint n=2000000;
2. Это действительно похоже на возможный доступ к массиву за пределами:
prime[j*prime[i]]=0
.3. Из примечания, вы, вероятно, должны использовать какой-то другой тип данных, чем
int
. Не гарантируется, что Int будет иметь какой-либо конкретный размер, отличный от 16 бит. В качестве проблемы со стилем я бы рекомендовалlong
для чисел выше 32 кб.4. Если он собирается индексировать большой массив, он мог бы также использовать
size_t
Ответ №1:
Вы выделяете огромный массив в стеке:
int prime[2000000]={};
Четыре байта, умноженные на два миллиона, равны восьми мегабайтам, что часто является максимальным размером стека. Выделение большего количества приводит к ошибке сегментации.
Вместо этого вы должны выделить массив в куче:
int *prime;
prime = malloc(2000000 * sizeof(int));
if(!prime) {
/* not enough memory */
}
/* ... use prime ... */
free(prime);
Ответ №2:
Вот моя реализация.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
int* sieve(int n) {
int* A = calloc(n, sizeof(int));
for(int i = 2; i < (int) sqrt(n); i ) {
if (!A[i]) {
for (int j = i*i; j < n; j =i) {
A[j] = 1;
}
}
}
return A;
}
Я сравнил его для первых 1 000 000 000 чисел на i5 Kaby Lake.
🐻 time ./sieve 1000000000
./sieve 1000000000 16.21s user 1.05s system 99% cpu 17.434 total
Я просто перевел этот псевдокод из Википедии.
Ответ №3:
Здесь моя реализация (Java) была намного проще в том смысле, что вам действительно нужен только один массив, просто начните циклы for с 2.
редактировать: решение @cheesehead, вероятно, было лучше, я только что прочитал описание сита и подумал, что это будет хорошим мыслительным упражнением.
// set max;
int max = 100000000;
// logic
boolean[] marked = new boolean[max]; // all start as false
for (int k = 2; k < max;) {
for (int g = k * 2; g < max; g = k) {
marked[g] = true;
}
k ;
while (k < max amp;amp; marked[k]) {
k ;
}
}
//print
for (int k = 2; k < max; k ) {
if (!marked[k]) {
System.out.println(k);
}
}
Ответ №4:
Простая реализация сита Эратосфена
Подход: я создал логический вектор размером n 1 (скажем, n = 9, затем от 0 до 9), который выполняется во всех местах. Теперь, для i = 2, отметьте все места, кратные 2, как false (например, 4,6 и 8 при n = 9). Для i = 3 отметьте все места, кратные 3, как false (например, 6 и 9 при n = 9). Теперь для i = 4 условие i * i<=n равно false, потому что 4 * 4 = 16> 9. Итак, теперь выведите все места, которые содержат истинное значение.
void sieve(int n)
{
vector<bool> isPrime(n 1,true);
for(int i=2;i*i<=n;i ){
if(isPrime[i])
{
for(int j=2*i;j<=n;j=j i)
isPrime[j]=false;
}
}
for(int i=2;i<=n;i ){
if(isPrime[i])
cout<<i<<" ";
}
}
Комментарии:
1. Этот ответ — всего лишь вариант ответов Чизхеда и Уильяма Уорнера. Это не отвечает на вопрос в отношении ошибки сегментации