Тест петли на верхней или нижней? (В то время как против делать, пока)

голоса
21

Когда я принимал CS в колледже (в середине 80-х годов), одна из идей, которые постоянно повторяющимися было всегда писать петли, тест на вершине (в то время как ...), а не на дне (сделать ... пока) из петля. Эти понятия часто подкреплены ссылками на исследования, которые показали, что петли, которые испытаны в верхней были статистически гораздо больше шансов быть правильной, чем их донные тестирования коллег.

В результате, я почти всегда пишу петлю, тест на вершине. Я не сделать это, если она вводит дополнительную сложность в коде, но тот случай, кажется, редко. Я заметил, что некоторые программисты, как правило, почти исключительно писать циклы, которые проверяют на дне. Когда я вижу конструкции нравится:

if (condition)
{
    do
    {
       ...
    } while (same condition);
}

или обратное ( ifвнутри while), это заставляет меня задаться вопросом, если они на самом деле написали это таким образом , или если они добавили ifзаявление , когда они поняли , что петля не справиться с нулевым случаем.

Я сделал некоторые погуглите, но не смог найти какую-либо литературу по этому вопросу. Как вы, ребята (и девчата) написать свои петли?

Задан 22/10/2008 в 01:29
источник пользователем
На других языках...                            


31 ответов

голоса
74

Я всегда следовать правилу , что если он должен работать ноль или более раз, тест в начале, если он должен работать один раз или более, тест в конце. Я не вижу никакой логической причины , чтобы использовать код , указанный в вашем примере. Это только добавляет сложности.

Ответил 22/10/2008 в 01:37
источник пользователем

голоса
54

Используйте в то время как петли, когда вы хотите, чтобы проверить состояние перед первой итерации цикла.

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

Например, если вы обнаружили, что делает что-то вроде либо из этих отрывков:

func();
while (condition) {
   func();
}

//or:

while (true){
    func();
    if (!condition) break;
}

Вы должны переписать как:

do{
    func();
} while(condition);
Ответил 22/06/2010 в 17:17
источник пользователем

голоса
20

Разница в том, что делать цикл выполняется «сделать что-то» один раз, а затем проверяет состояние, чтобы увидеть, если он должен повторить «сделать что-то» в то время как цикл в то время как проверяет состояние, прежде чем делать что-либо

Ответил 24/12/2008 в 02:51
источник пользователем

голоса
17

Есть ли избежать do/ whileдействительно поможет сделать мой код более читабельным?

Нет.

Если это имеет смысл , чтобы использовать do/ whileцикл, то сделать это. Если вам необходимо выполнить тело цикла один раз перед проверкой условия, то do/ whileцикл, вероятно, самый простой реализацией.

Ответил 31/07/2010 в 03:30
источник пользователем

голоса
12

Во-первых, можно не выполнять вообще, если условие ложно. Другие один будет выполнять по крайней мере один раз, а затем проверить conidition.

Ответил 24/12/2008 в 02:51
источник пользователем

голоса
7

Ради удобства чтения, кажется разумным, чтобы проверить на самом верху. Дело в том, что петля имеет важное значение; человек, читающий код должен знать об условиях цикла, прежде чем пытаться понять тело цикла.

Ответил 22/10/2008 в 01:50
источник пользователем

голоса
6

Вот хороший реальный пример , который я наткнулся в последнее время . Предположим , у вас есть целый ряд задач обработки (например , обработки элементов в массиве) , и вы хотите , чтобы разделить работу между одним потоком в ядро процессора настоящее время . Там должно быть по крайней мере , один сердечник должен быть запущен текущий код! Таким образом , вы можете использовать do... whileчто - то вроде:

do {
    get_tasks_for_core();
    launch_thread();
} while (cores_remaining());

Это почти negligable, но это может быть стоит рассмотреть преимущества в производительности: это может быть в равной степени записать в виде стандартного whileцикла, но это всегда будет делать ненужную первоначальное сравнение , которое всегда будет оценивать true- и на одноядерных, ветви состояние сделай в то время как более предсказуемо (всегда ложно, по сравнению с чередованием истина / ложь для стандарта while).

Ответил 22/06/2010 в 17:55
источник пользователем

голоса
4

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

Ответил 31/07/2010 в 03:32
источник пользователем

голоса
4

Да, так же, как с использованием, а время, или Еогеасп а не для улучшает читаемость. Тем не менее некоторые обстоятельства, что нужно сделать в то время, и я соглашаюсь, что Вы бы глупо, чтобы заставить тех ситуаций, в цикла.

Ответил 31/07/2010 в 03:32
источник пользователем

голоса
4

Yaa..its правда .. делать в то время как будет работать по крайней мере один раз. То единственное различие. Ничего другого для обсуждения по этому вопросу

Ответил 22/06/2010 в 17:18
источник пользователем

голоса
4

Цикл в то время как будет проверять «состояние» первый; если оно ложно, оно никогда не будет «делать что-то.» Но делать ... в то время как цикл будет «делать что-то», а затем проверить «состояние».

Ответил 24/12/2008 в 02:53
источник пользователем

голоса
4

Первых проверяет условие перед выполнением так что возможно, что ваш код никогда не будет вводить код внизу. Второй будет выполнять код внутри перед тестированием состояния.

Ответил 24/12/2008 в 02:52
источник пользователем

голоса
3

Я предпочитаю делать-то время как петли, сам. Если условие будет всегда быть верным в начале цикла, я предпочитаю , чтобы проверить его в конце. На мой взгляд, весь смысл условий тестирования (кроме утверждений) является то , что никто не знает , результат теста. Если я вижу время цикла с тестом состояния в верхней части, мой наклон рассмотреть случай, когда цикл выполняется ноль раза. Если это не может произойти, то почему бы не закодировать таким образом , что ясно показывает , что?

Ответил 31/07/2010 в 05:28
источник пользователем

голоса
3

Вот перевод:

do { y; } while(x); 

Такой же как

{ y; } while(x) { y; }

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

do {
    // do something
} while (condition is true);

Соответствующее время цикла для делать-цикл выглядит следующим образом

{
    // do something
}
while (condition is true) {
    // do something
}

Да, вы видите, соответствующие, а для вашего цикла сделай отличается от вашего времени :)

Ответил 24/12/2008 в 03:37
источник пользователем

голоса
3

В то время как () проверяет состояние перед каждым выполнением тела цикла и делать ... в то время как () проверяет состояние после каждого выполнения тела цикла.

Таким образом, ** сделать ... в то время как () ** s всегда будет выполняться тело цикла по крайней мере один раз.

Функционально, некоторое время () эквивалентно

startOfLoop:
    if (!condition)
        goto endOfLoop;

    //loop body goes here

    goto startOfLoop;
endOfLoop:

и делать ... в то время как () эквивалентно

startOfLoop:

    //loop body

    //goes here
    if (condition)
        goto startOfLoop;

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

  • Вы знаете , что условие всегда будет истинным первый раз, или
  • Вы хотите цикл , чтобы выполнить один раз , даже если условие ложно , чтобы начать с.
Ответил 24/12/2008 в 03:15
источник пользователем

голоса
3

Случаи использования различны для двух. Это не «наилучшей практики» вопрос.

Если вы хотите, чтобы петля для выполнения на основе условия исключительно , чем использовать для или времени

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

Ответил 22/10/2008 в 01:51
источник пользователем

голоса
2

Как отметили Piemasons, разница, выполняет ли цикл один раз перед выполнением теста, или если тест сделан первым, так что тело цикла никогда не может выполнить.

Ключевой вопрос в том, какой имеет смысл для вашего приложения.

Для того, чтобы принять два простых примера:

  1. Допустим, вы циклически элементы массива. Если массив не имеет элементов, вы не хотите, чтобы обработать номер один ноль. Таким образом, вы должны использовать WHILE.

  2. Вы хотите, чтобы отобразить сообщение, принять ответ, и если ответ неверен, переспрашивать, пока вы не получите правильный ответ. Таким образом, вы всегда хотите задать один раз. Вы не можете проверить, если ответ является действительным, пока не получит ответ, так что вы должны пройти через тело цикла один раз, прежде чем вы можете проверить состояние. Вы должны использовать DO / WHILE.

Ответил 22/06/2010 в 18:52
источник пользователем

голоса
2

Обе конвенции являются правильными, если вы знаете, как писать код правильно :)

Обычно использование второй конвенции ( делать {} , а () ) предназначаются , чтобы избежать иметь дублированное заявление вне цикла. Рассмотрим следующий (более упрощенной) , например:

a++;
while (a < n) {
  a++;
}

можно записать в более сжатой форме с использованием

do {
  a++;
} while (a < n)

Конечно, этот конкретный пример можно записать в еще более кратким, как (предполагая, что синтаксис С)

while (++a < n) {}

Но я думаю, что вы можете увидеть точку здесь.

Ответил 24/12/2008 в 03:40
источник пользователем

голоса
2

Для тех, кто не может придумать причину, чтобы иметь один или более раз-цикл:

try {
    someOperation();
} catch (Exception e) {
    do {
        if (e instanceof ExceptionIHandleInAWierdWay) {
            HandleWierdException((ExceptionIHandleInAWierdWay)e);
        }
    } while ((e = e.getInnerException())!= null);
}

То же самое может быть использован для любого вида иерархической структуры.

в классе Node:

public Node findSelfOrParentWithText(string text) {
    Node node = this;
    do {
        if(node.containsText(text)) {
            break;
        }
    } while((node = node.getParent()) != null);
    return node;
}
Ответил 22/10/2008 в 13:03
источник пользователем

голоса
2

Это фактически означало , за разные вещи. В C, вы можете использовать сделать - в то время как конструкция для достижения как сценарий (работает по крайней мере один раз и работает в то время как верно). Но PASCAL имеет повторение - до тех пор , и в то время как для каждого сценария, и если я правильно помню, ADA не имеет другую конструкцию , которая позволяет выйти в середине, но, конечно, не то , что вы просите. Мой ответ на ваш вопрос: мне нравится мой цикл с тестированием на вершине.

Ответил 22/10/2008 в 01:50
источник пользователем

голоса
1
while( someConditionMayBeFalse ){

// this will never run...

}


// then the alternative

do{

// this will run once even if the condition is false

while( someConditionMayBeFalse );

Разница очевидна и позволяет иметь код запуска, а затем оценить результат, чтобы увидеть, если вы должны «делать это снова», а другой метод время позволяет иметь блок скрипта игнорируется, если условная не выполняется.

Ответил 10/02/2012 в 01:34
источник пользователем

голоса
1

Это не совсем ответ, но повторение чего-то один из моих преподавателей сказал, и это заинтересовало меня в то время.

Два типа while..do петли и do..while фактически экземпляры трети более общий контур, который имеет тест где-то в середине.

begin loop
  <Code block A>
  loop condition
  <Code block B>
end loop

Код блок А выполняется по крайней мере один раз и B выполняется ноль или более раз, но не работает на самом последнем (неисправного) итерации. петля в то время, когда блок коды а ​​является пустой и do..while, когда кодовый блок б пуст. Но если вы пишете компилятор, вы можете быть заинтересованы в обобщении оба случая к петле, как это.

Ответил 15/06/2009 в 13:39
источник пользователем

голоса
1

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

Чтобы доказать цикл правильно, стандартный способ выбрать инвариант цикла и индукция доказательство. Но пропустить сложные слова: то, что вы делаете, неформально, это выяснить, то, что это верно для каждой итерации цикла, и что, когда цикл выполняется, что вы хотели осуществить теперь верно. Инвариант цикла является ложным в конце концов, за цикл прекратить.

Если условия цикла карта достаточно легко инвариант и инвариант в верхней части петли, и один делает вывод, что инвариант верно на следующей итерации цикла, работая по коду цикла, то легко чтобы выяснить, что петля является правильной.

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

Ответил 15/06/2009 в 13:34
источник пользователем

голоса
1

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

Ответил 15/06/2009 в 13:34
источник пользователем

голоса
1

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

Вы должны сделать что-то фантазии, если тест логически принадлежит в них среднего. :-)

Ответил 22/10/2008 в 02:50
источник пользователем

голоса
1

Это действительно зависит от того бывают ситуации, когда вы хотите проверить в верхней части, другие, когда вы хотите проверить на дне, и еще другие, когда вы хотите проверить в середине.

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

Ответил 22/10/2008 в 01:56
источник пользователем

голоса
1

Я пишу мое довольно много исключительно тестирование на самом верху. Это меньше кода, так что для меня, по крайней мере, это меньший потенциал, чтобы ввернуть что-нибудь (например, копирование вставки условие делает два места, которые вы всегда должны обновить)

Ответил 22/10/2008 в 01:36
источник пользователем

голоса
0

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

Ответил 31/07/2010 в 06:58
источник пользователем

голоса
0

Из моего ограниченного знания генерации кода я думаю, что это может быть хорошей идеей, чтобы написать нижние петли тестирования, так как они дают возможность компилятору выполнить оптимизацию цикла лучше. Для нижней петли теста гарантируется, что цикл выполняется по крайней мере один раз. Это означает, что инвариант цикла код «доминирует» узел выхода. И, таким образом, может быть безопасно перемещены только перед началом цикла.

Ответил 27/05/2010 в 21:25
источник пользователем

голоса
0

Я бы сказал, что это плохая практика, чтобы писать if..do..while петель, по той простой причине, что это увеличивает размер кода и вызывает код дупликации. Код повторы являются ошибкам и их следует избегать, так как любое изменение в одной части должны быть выполнены на двух экземплярах, а также, что не всегда так. Кроме того, больше кода означает более трудное время на кэш процессора. Наконец, он обрабатывает пустые дела и решает головные боли.

Только тогда, когда первый цикл принципиально отличается должен использовать один do..while, скажем, если код, который заставляет вас пройти условие цикла (например, инициализация) выполняется в цикле. В противном случае, если он уверен, что петля никогда не будет падать на первой итерации, то да, do..while уместно.

Ответил 15/06/2009 в 14:01
источник пользователем

голоса
0

В обычном классе дискретных структур в информатике, это легко доказательство того, что существует отображение эквивалентности между ними.

Стилистический, я предпочитаю в то время как (простое выражение) {}, когда простое выражение известно фронт и готовы к работе, и цикл не имеет много повторных накладные / инициализации. Я предпочитаю делать {} в то время (несколько-менее простой выраж); когда есть более повторен над головой, и условие может быть не совсем так просто, чтобы установить загодя. Если я пишу бесконечный цикл, я всегда использую в то время как (истинно) {}. Я не могу объяснить почему, но я просто не люблю писать для (;;) {}.

Ответил 24/12/2008 в 03:32
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more