Во-первых, следует сказать - и уже упоминалось в других ответах - что код, который вы получили из книги, неверен (или, возможно, вы пропустили его копирование). Состояние внутреннего контура должно быть
for(j=2; j <= i/j; j++)
один важный урок из этого является то, что вы должны попробовать запустить даже примеры книги, чтобы увидеть, если они работают. Если вы запустили это, вы бы увидели, что он составляет 4,9,25,49 в качестве основного, когда это не так.
Но ваше чтение кода было неверным. Вы сказали, что 4 считается не простым, потому что 4%4 == 0
. Но на самом деле простое число разрешено делиться само по себе (любое число). Так что, действительно, тестирование простого числа путем деления его само по себе не сработает.
Давайте посмотрим, что это такое. Вы понимаете внешний цикл - это дает вам кандидаты, чтобы проверить, являются ли они главными или нет.
Затем он работает следующим образом: предположим, что текущий кандидат является простым. Попытайтесь разделить его на все возможные делители. Если какой-либо из делителей делит его равномерно, отметьте его как «не простое».
Если после того, как все возможные делители были протестированы, ни одна из них не дошла до точки, которая отмечает ее как «не премьер», тогда она действительно является главной, и вы можете ее распечатать.
Таким образом, петля i
представляет кандидатов, а петля j
представляет собой потенциальные делители. Возьмите номер 15
в качестве примера i
.
- Начало
j
с 2. i/j
является 15/2
который 7. 2 < 7
, поэтому мы идем внутри цикла.
- Есть 2 делитель 15? Нет, это не так. Ничего не сделано.
j
сейчас 3
. i/j
- 15/3
, который является 5
. 3 < 5
, поэтому мы продолжим.
- Является ли 3 делителем 15? Да! Поэтому установите
isprime=false
.
j
сейчас 4
. i/j
- 15/4
, который является 3
. 4 < 3
есть описание товара false, поэтому прекращаем.
Как вы можете видеть, шаг с j=3
выше набор isprime
в false
, поэтому мы не печатаем его - это не простое.
Теперь давайте возьмем реальное простое число, как 13:
- Начало
j
с 2. i/j
является 13/2
который 6. 2 < 6
, поэтому мы идем внутри цикла.
- Есть 2 делитель из 13? Нет, это не так. Ничего не сделано.
j
сейчас 3
. i/j
- 13/3
, который является 4
. 3 < 4
, поэтому мы продолжим.
- Есть 3 делитель из 13? Нет, это не так. Ничего не сделано.
j
сейчас 4
. i/j
- 13/4
, который является 3
. 4 < 3
есть описание товара false, поэтому прекращаем.
Ни один из следующих этапов: isprime
- false
. Он по-прежнему true
, поэтому число 13 является простым и мы его печатаем.
Теперь у нас есть трюк, какие кандидаты мы предлагаем для j
. Наивно, человек, пишущий это в первый раз, подумает, что кандидаты должны иметь все числа от 1 до i
, за исключением 1
и i
. Поэтому они напишут петлю, как:
for (j = 2; j < i; j++)
Но это расточительно. Зачем? Предположим, вы проверили номер 15. Вы обнаружили, что 3 является делителем для него. Как так? Потому что 15 = 3 x 5
. Но это означает, что 5
также является делителем. Вам не нужно проверять делитель, который, если вы разделите его, вы получите делитель, который вы уже тестировали. Поэтому нет необходимости тестировать 5
, потому что мы уже протестировали 3
.
Итак, опять же, наивные программисты могли бы решить, что мы можем просто проверить половину кандидатов:
for (j = 2; j <= i/2; j++)
Но на самом деле, с математической точки зрения, это еще расточительно. Действительно, мы должны идти только до квадратного корня i
. Зачем? Потому что если делитель j
больше квадратного корня i
, такой, что j x k = i
, то k
будет меньше квадратного корня i
. Если k
было больше, то j x k
было бы больше, чем sqrt(i) x sqrt(i)
, что означает, что они j x k > i
. Но мы знаем, что они равны i
!
Это означает, что если есть потенциальный делитель больше, чем квадратный корень из i
, мы уже нашли другой делитель, меньший, чем квадратный корень из i
, и протестировали его и промаркированы i
как «не простые».
Итак, это то, что тестирует ваш цикл-кандидат. Это в основном простой способ написания
for (j = 2; j <= Math.sqrt(i); j++)
Без вызова Math
класс и без преобразования целых чисел в парном разряде.
Но, как я сказал с самого начала, важно, чтобы условие было <=
, а не <
. Для чисел, которые являются квадратами простых чисел (4 = 2 x 2, 9 = 3 x 3), единственным правильным делителем является число, равное , равное их квадратному корню.
последнее замечание: эта книга пример еще расточительно, так как он не остановить проверку после того, как он нашел один делитель, который делает число не простое. Найти один делитель достаточно. Один из способов сделать это, чтобы изменить условие цикла, как это:
for (j = 2; isprime && j <= i/j; j++)
Так цикл будет продолжаться только до тех пор, как мы по-прежнему есть основания полагать, что число является простым. После j
, который отмечает isprime
как false
, цикл автоматически остановится.
(И, конечно же, этот алгоритм не самый лучший алгоритм. Есть лучшие алгоритмы. Это только тот, с которого все начинаются).
Ответы на вопросы, заданные в комментариях:
Внутренний цикл всегда выполняется заново. Подумайте об этом так:
Если петля говорит:
for (int i = 0; i < 3; i++) {
doSomething();
}
Это эквивалентно
doSomething();
doSomething();
doSomething();
Так что, если "что-то делать" часть сама по себе петля:
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
runSomething();
}
}
эквивалентен:
for (int j = 0; j < 2; j++) {
runSomething();
}
for (int j = 0; j < 2; j++) {
runSomething();
}
for (int j = 0; j < 2; j++) {
runSomething();
}
Так вы видите, каждый раз это новый j
, который начинается с нуля.
Что касается вопроса о фигурных скобках: официально, то формат for
утверждения:
for (initialization; termination; increment)
statement
Оператор может быть один оператор, как вызов метода, внутренний цикл, в если заявление или что-то еще. В этом случае он не нуждается в фигурных скобках. Или оператор может быть блоком , который представляет собой пару фигурных скобок, которая содержит ноль или более операторов.Вы привыкли видеть блок, и в самом деле рекомендуется всегда использовать блок, а не один оператор, так как легче добавлять утверждения.
вам не нужно ломать? –
'for (j = 2; j khelwood
Возможный дубликат [Поиск простых чисел с ситом эратосфенов] (http://stackoverflow.com/questions/586284/finding-prime-numbers-with-the-sieve-of-eratosthenes-originally-is-there-a -bet) – abarisone