Я читал «Учебник по программированию на языке GNU C» , и я думаю, я поймал очень маленькую и незаметную ошибку. Именно на этом глава . В функции delete_multiples_of_prime(...) в цикле for:

delete_multiples_of_prime (int prime)
{
  int index, multiplier = 2;

  for (index = prime * multiplier; index < ARRAY_SIZE; index = prime * multiplier++)
    sieve[index] = DELETED;
}

Я думаю, что проблема в части приращения for. Автор использовал оператор постинкремента вместо оператора предварительного приращения, имея в виду это, я думаю, что цикл будет выполняться с начальным значением индекса дважды.

Я прав?

Примечание: я почти уверен, что прав, и я бы не публиковал это, если бы нашел его где-то еще, но нахождение там ... Это заставляет меня сомневаться. Конечно, я знаю, что даже если я прав, разница в производительности незначительна.

c
3
dv1729 15 Июл 2017 в 02:02
Да, кажется, ты прав.
 – 
Fredrik
15 Июл 2017 в 02:21
Вы правы. Это не влияет на правильность функции, потому что дважды пометить элемент как удаленный - нет ничего плохого.
 – 
Barmar
15 Июл 2017 в 02:26
3
В стороне: это не очень хорошее руководство. Первоначально он был написан в 1987 году и, похоже, не обновлялся в соответствии с современными стандартами C. (В частности, он объявляет функции без возвращаемого типа, что больше не разрешено.) Вам действительно следует найти что-то более свежее…
 – 
user149341
15 Июл 2017 в 02:41
3
Я бы использовал более простой цикл: for (int index = prime * 2; index < ARRAY_SIZE; index += prime). Не нужно столько умножений.
 – 
Jonathan Leffler
15 Июл 2017 в 03:07
1
Обратите внимание, что подход Джонатана Леффлера (1) устраняет ошибку (2) устраняет ненужную переменную И (3) легче понять, поскольку он позволяет избежать зависимости от побочных эффектов и, следовательно, его легче исправить.
 – 
Peter
15 Июл 2017 в 03:45

1 ответ

Лучший ответ

Вы правы, что цикл запускается дважды для первого индекса.

Однако это не ошибка , потому что присвоение - это идемпотентная операция, поэтому множественные назначения для данного индекса не будут иметь никакого дальнейшего эффекта или побочных эффектов. Функция всегда будет работать одинаково, даже если первый индекс повторяется дважды.

С точки зрения производительности разница должна быть незначительной, так как это будет только одно дополнительное назначение для каждого вызова функции. (Из-за идемпотентности он также может быть просто оптимизирован компилятором).


При этом для ясности и в случае, если тело цикла for когда-либо было изменено, чтобы больше не быть независимым (например, путем добавления оператора printf), я бы лично использовал приращение префикса:

for (index = prime * multiplier; index < ARRAY_SIZE; index = prime * ++multiplier)
3
Frxstrem 15 Июл 2017 в 02:29
1
Лично я бы вообще избегал использования выражений (в данном случае) с побочными эффектами. В этом случае ошибка, как вы говорите, несущественна, но подобные уловки (включая выражения с множеством эффектов и побочных эффектов) могут вызвать серьезные ошибки, которые ОЧЕНЬ трудно отследить. И в настройках команды виноватым (тем, кто создает проблему) часто оказывается не тот человек, которому «нравится» находить и исправлять ее.
 – 
Peter
15 Июл 2017 в 03:28