Модераторы: bsa
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Ошибка в Решето Эратосфена 
:(
    Опции темы
n199a
  Дата 7.7.2013, 20:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 129
Регистрация: 17.11.2011

Репутация: нет
Всего: нет



Принцип действия решета:
Другая задача, которую решили математики Древней Греции — нахождение всех простых
чисел в интервале от 1 до заданного числа N. Самым быстрым и поныне считается алгоритм
Эратосфена (275-195 гг. до н.э.). Существует предание, что Эратосфен выписал в ряд на папи-
русе все натуральные числа и затем прокалывал каждое второе (то есть делящееся на 2), потом
— каждое третье, и т.д. В конце этой процедуры остаются «непроколотыми» только простые
числа, которые делятся только на себя и на 1.
Вместо папируса мы будем использовать массив A, в котором элемент A[i] для всех i от
1 до N принимает два возможных значения:
1, число «не проколото» и является кандидатом на простые;
0, число «проколото» и больше не рассматривается.

Вопрос:
Зачем прокалывать каждое второе я понял - если их проколоть, останутся нечетные (делятся на 1 и на себя).
А вот зачем прокалывать потом каждое 3-е, потом каждое 4-ое?

1  2  3  4  5  6  7  8  9  10  11  12
    x      x      x      x        x          x        //каждое второе
        x          x          x                x        //кажое 3-е
            x              x                    x       //каждое 4-ое


Код

#include <stdio.h>
int main() {
    unsigned char *A;    //unsigned - символьные переменные (1 байт)
    int i, k, N;
    printf("Введите максимальное число: ");
    scanf("%d", &N);
    A = new unsigned char[N+1];    //выделить память под массив
    if (A = NULL) return 1;        //выход в случае ошибки
    for (i = 1; i <= N; i++)
        A[i] = 1;
    for (k = 2; k*k <= N; k++)
        if (A[k] != 0)
            for (i = k+k; i <= N; i += k)
                A[i] = 0;
    for (i = 1; i <= N; i++)
        if (A[i] == 1) printf("%d\n", i);
}


После ввода числа аварийно завершается программа.
Непонятные моменты:
for (i = 1; i <= N; i++) A[i] = 1;
1) Вводили указатель *A, тут получился уже массив A[i]
2) В массиве A[i] i-ый элемент будет равен единице. Что-то не так  smile 

Это сообщение отредактировал(а) n199a - 7.7.2013, 20:43
PM MAIL   Вверх
bsa
Дата 7.7.2013, 21:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 85
Всего: 196



Цитата(n199a @  7.7.2013,  21:36 Найти цитируемый пост)
Вводили указатель *A
где? Его не вводили, а определяли.
Цитата(n199a @  7.7.2013,  21:36 Найти цитируемый пост)
тут получился уже массив A[i]
когда ты выделил память с помощью new ты получил динамический массив на N+1 элемент
Цитата(n199a @  7.7.2013,  21:36 Найти цитируемый пост)
for (i = 1; i <= N; i++) A[i] = 1;
кстати, в языке Си массивы индексируются с 0.

PM   Вверх
feodorv
Дата 7.7.2013, 21:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(n199a @  7.7.2013,  21:36 Найти цитируемый пост)
Зачем прокалывать каждое второе я понял - если их проколоть, останутся нечетные (делятся на 1 и на себя).

Вот нечётные не обязательно делятся только на 1 и на себя. Рассмотрите такие числа как 9, 15, 21, 25 и т.д.

Цитата(n199a @  7.7.2013,  21:36 Найти цитируемый пост)
А вот зачем прокалывать потом каждое 3-е, потом каждое 4-ое?

Как раз, чтобы исключить числа, которые делятся на 3,4 etc.

Цитата(n199a @  7.7.2013,  21:36 Найти цитируемый пост)
После ввода числа аварийно завершается программа.

Ну как бы это сказать... Если путать "равно" и "двойное равно"...
Цитата(n199a @  7.7.2013,  21:36 Найти цитируемый пост)
    if (A = NULL) return 1;

Более того, не нужно проверять на NULL значение, возвращаемое от new (в случае нехватки памяти будет брошено исключение).


Цитата(n199a @  7.7.2013,  21:36 Найти цитируемый пост)
Непонятные моменты:
for (i = 1; i <= N; i++) A[i] = 1;

А что тут непонятного... Инициализируется массив единицами (как бы изначально считаем, что все числа - простые, а потом исключаем составные путём  A[i] = 0).

Добавлено через 1 минуту и 52 секунды
Цитата(bsa @  7.7.2013,  22:37 Найти цитируемый пост)
кстати, в языке Си массивы индексируются с 0.

Тут просто значение индекса и значение числа - одно и то же (это разумно для этой задачи), 0-ой индекс не используется, а памяти выделяется на 1 элемент больше
Цитата(n199a @  7.7.2013,  21:36 Найти цитируемый пост)
    A = new unsigned char[N+1];

 smile 


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
bsa
Дата 7.7.2013, 23:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 85
Всего: 196



feodorv, я заметил.  smile 
PM   Вверх
n199a
Дата 8.7.2013, 12:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 129
Регистрация: 17.11.2011

Репутация: нет
Всего: нет



Цитата(feodorv @  7.7.2013,  21:46 Найти цитируемый пост)
Более того, не нужно проверять на NULL значение, возвращаемое от new (в случае нехватки памяти будет брошено исключение).

Что означает - брошено исключение?
В учебнике пишут, что, может затереться любой участок памяти и произойдёт непредвиденный сбой.
Цитата(feodorv @  7.7.2013,  21:46 Найти цитируемый пост)
Как раз, чтобы исключить числа, которые делятся на 3,4 etc.

Если так прокалывать, то проколются ВСЕ числа, смотри:
1  2  3  4  5  6  7  8  9  10  11  12
    x      x      x      x        x          x        //каждое второе
        x          x          x                x        //кажое 3-е
            x              x                    x       //каждое 4-ое
                x                    x
                   x                            x
                        x
                            x
                               x
                                    x
                                            x
                                                  x
Что тут исключается? В итоге то полностью каждое число проколется. Что останется?

Добавлено @ 12:10
Цитата(feodorv @  7.7.2013,  21:46 Найти цитируемый пост)
Ну как бы это сказать... Если путать "равно" и "двойное равно"...

Не понял намек.
Я про то, что, после ввода числа вылазит ошибка (отправить отчет и не отправлять отчет об ошибке). Т.е. программа нерабочая. Я в этом смысле. Что тут не так, может у вас нормально будет?

Это сообщение отредактировал(а) n199a - 8.7.2013, 12:12
PM MAIL   Вверх
SenkraD
Дата 8.7.2013, 13:00 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 933
Регистрация: 3.2.2006
Где: Украина::Киев

Репутация: нет
Всего: 23



  • Вам говорят, что строчка №8 не нужна, так как данная операции никогда не венет NULL (о хаках, и переопределения, и особых вызовах  пока не говорим).
  • текущая строчка №8 и делает вам креш!!! if (A = NULL) - это не сравнение, а присваивание, о чем вам и писали, когда говрили, что вы путаете операции. Для правильности if нужно изменить так: if (A == NULL) или так if (!A)


Это сообщение отредактировал(а) SenkraD - 8.7.2013, 13:02


--------------------
 Имеющий язык - да не убоится спросить! 
user posted image
PM MAIL ICQ   Вверх
feodorv
Дата 8.7.2013, 13:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(n199a @  8.7.2013,  13:09 Найти цитируемый пост)
Не понял намек.

Ну всё же кристально ясно. = это присваивание, == а это сравнение. И что делаете Вы?
Цитата(n199a @  7.7.2013,  21:36 Найти цитируемый пост)
    if (A = NULL) return 1;  

Вы присваиваете (не сравниваете!!!) указателю A значение NULL (то есть 0). Получается, что Ваш код эквивалентен такому
Код

if(0) return 1;

Поскольку 0 - это всегда "ложь", то программа продолжает работать дальше, но уже с A, равному NULL. И что дальше? А дальше
Цитата(n199a @  7.7.2013,  21:36 Найти цитируемый пост)
    for (i = 1; i <= N; i++)
        A[i] = 1;

То есть попытка присвоения значения по нулевому указателю. А это даёт то самое
Цитата(n199a @  8.7.2013,  13:09 Найти цитируемый пост)
после ввода числа вылазит ошибка (отправить отчет и не отправлять отчет об ошибке). Т.е. программа нерабочая.

Правильно так:
Код

if (A == NULL) return 1;

Двойное равно, однако  smile 


Цитата(n199a @  8.7.2013,  13:09 Найти цитируемый пост)
В учебнике пишут, что, может затереться любой участок памяти и произойдёт непредвиденный сбой.

Если указатель имеет мусорное значение (какое-то произвольное, от балды), то да. Если как у нас - вполне определённый 0 (NULL), то однозначно произойдёт сбой (ничего затираться не будет). В этом великая сила нулевого указателя (ну и ряда других специальных значений).


Цитата(n199a @  8.7.2013,  13:09 Найти цитируемый пост)
Что означает - брошено исключение?

Вам сюда. Выкиньте вообще эту строчку с проверкой на NULL.


Цитата(n199a @  8.7.2013,  13:09 Найти цитируемый пост)
Что тут исключается? В итоге то полностью каждое число проколется. Что останется?

Ну Вы тогда не поняли смысл решета. Не каждое smile 
Цитата(n199a @  7.7.2013,  21:36 Найти цитируемый пост)
           for (i = k+k; i <= N; i += k)

Где здесь каждое? Для 40:
Цитата

Введите максимальное число: 1
2
3
5
7
11
13
17
19
23
29
31
37



PS Пардон, что на "вы", не заметил, что можно на "ты".

Добавлено через 31 секунду
SenkraD,  smile 


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
volatile
Дата 8.7.2013, 23:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(n199a @  7.7.2013,  20:36 Найти цитируемый пост)
            for (i = k+k; i <= N; i += k)

Если не ошибаюсь, здесь можно поствить умножение.
Будет быстрее.
for (i = k*k; i <= N; i += k)

и если new заменить на malloc, то будет программа на С.
(а так ни рыба, ни мясо.)

PM MAIL   Вверх
feodorv
Дата 9.7.2013, 00:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(volatile @  9.7.2013,  00:08 Найти цитируемый пост)
Если не ошибаюсь, здесь можно поствить умножение.
Будет быстрее.
for (i = k*k; i <= N; i += k)

Не))) Нужно пройтись по всем кратным k: 2k, 3k, 4k ... до N (по мере возможности))) Так исключаются составные числа, в разложение которых входит k. Само k не берём в рассмотрение, так как оно как раз простое (кроме единицы, которая не входит в цикл, так как отсчёт начинается от 2, но которую, по большому счёту тоже стоит исключить из списка простых чисел) из-за проверки   
Цитата(n199a @  7.7.2013,  21:36 Найти цитируемый пост)
        if (A[k] != 0)

(а если A[k] равно 0, то k - составное, и смысла в просеивании нет - уже всё просеяно до нас)))


Цитата(volatile @  9.7.2013,  00:08 Найти цитируемый пост)
и если new заменить на malloc, то будет программа на С.
(а так ни рыба, ни мясо.)

Это да  smile 


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
volatile
Дата 9.7.2013, 01:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(feodorv @  9.7.2013,  00:15 Найти цитируемый пост)
Не))) Нужно пройтись по всем кратным k: 2k, 3k, 4k ... до N (

feodorv, допустим в какой-то момент k = 7
Зачем проходицца по 2*7, 3*7, 4*7 ?
Прежде чем к стало 7, оно было 2, 3, 4 и т.д.
То есть, числа кратные 2,3,4,5,6 уже и так зачеркнуты.
Первое число которое может быть не зачеркнутым это 7*7
Следовательно можно начинать сразу с 7*7
Разве нет?

Добавлено @ 01:37
Щас поздно уже, мозги не варят, завтра проверю.


Это сообщение отредактировал(а) volatile - 9.7.2013, 01:40
PM MAIL   Вверх
feodorv
Дата 9.7.2013, 02:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(volatile @  9.7.2013,  02:36 Найти цитируемый пост)
Разве нет?

Ха, а ведь весьма даже может быть!!!
Мда, век живи, век учись  smile 


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
volatile
Дата 9.7.2013, 12:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(volatile @  9.7.2013,  01:36 Найти цитируемый пост)
завтра проверю.

Ну собственно, проверять и нет особой необходимости. В википедии алгоритм так и приведен :
Цитата
для i := 2, 3, 4, ..., пока i^2 ≤ n:
  если A[i] = true:
    для j := i^2, i^2 + i, i^2 + 2i, ..., пока j ≤ n:
      A[j] := false

Решето Эратосфена

Кстати, для n199a, там есть гиф-анимашка, поясняющая работу, возможно поможет вам понять.


PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0985 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.