Разница между if и if, если в fizzbuzz

Я попытался реализовать fizzbuzz на C ++, и меня смущают различные результаты, которые выдают следующие примеры кода:

int main()
{
int val1 = 1;
while (val1 < 101) {
if (val1 % 15 == 0)
cout << "FizzBuzz\n";
if (val1 % 3 == 0)
cout << "Fizz\n";
if (val1 % 5 == 0)
cout << "Buzz\n";
else cout << val1 << "\n";
++val1;
}
keep_window_open();
}

Для всех кратных 15 этот код выводит

FizzBuzz
Fizz
Buzz

вместо просто FizzBuzz, Все кратные (только) 5 правильно заменены на Buzz но все кратные 3 распечатать Fizz а потом сам номер.

Следующий код, однако, работает отлично. Я понимаю, что иначе, если заставляет это работать правильно, но я просто не вижу, каков путь к коду, когда val1 = 3, или 5, или 15.

int main()
{
int val1 = 1;
while (val1 < 101) {
if (val1 % 15 == 0)
cout << "FizzBuzz\n";
else if (val1 % 3 == 0)
cout << "Fizz\n";
else if (val1 % 5 == 0)
cout << "Buzz\n";
else cout << val1 << "\n";
++val1;
}
keep_window_open();
}

2

Решение

Ваш else принадлежит только последнему if:

if (val1 % 15 == 0)
cout << "FizzBuzz\n";

if (val1 % 3 == 0)
cout << "Fizz\n";

if (val1 % 5 == 0)
cout << "Buzz\n";
else // any val1 which doesn't divide by 5
cout << val1 << "\n";

Вот почему, если val1 не делится на 5, он выводит это значение.

Кроме того, 15 делится либо на 15, 5 и 3. Это запускает все три ifи выводит все три строки.

Ты можешь использовать else if для того, чтобы получить правильные результаты, но лучший способ — заменить его завершением на завершенном состоянии.
Например, если бы у вас была функция, вы могли бы сделать это следующим образом:

string GetOutput(int val)
{
if (val % 15 == 0) return "FizzBuzz";
if (val % 3 == 0) return "Fizz"; // 2. val % 15 != 0 implied
if (val % 5 == 0) return "Buzz"; // 3. val % 15 != 0 && val % 3 != 0 implied
return to_string(val1); // 4. val % 15 != 0 && val % 5 != 0 && val % 3 != 0 implied
}

int main() {
cout << GetOutput(val) << endl;
}

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

1. If execution is at lines 2 or 3 - val is not divisible by 15
2. If execution is at line 4 - val is not divisible by 3, 5 and 15

При таком подходе вам не нужно описывать эти условия вручную.
Более того, если у вас будет все больше и больше условий, поддерживать и читать такую ​​функцию будет намного проще, чем писать очень длинные логические условия.

Например,

string GetOutput(int val)
{
if (val % 64 == 0) return "FizzBuzz"; // such wow
if (val % 32 == 0) return "Fizz"; // much readable
if (val % 16 == 0) return "Buzz";
if (val % 8 == 0) return "Muzz";
if (val % 4 == 0) return "Guzz";
if (val % 2 == 0) return "Duzz";
return "Hizz";
}

вместо

if (val % 64 == 0) cout << "FizzBuzz";
if (val % 64 != 0 && val % 32 == 0) cout << "Fizz";
if (val % 64 != 0 && val % 32 != 0 && val % 16 == 0) cout << "Buzz";
if (val % 64 != 0 && val % 32 != 0 && val % 16 != 0 && val % 8 == 0) cout << "Muzz";
if (val % 64 != 0 && val % 32 != 0 && val % 16 != 0 && val % 8 != 0 && val % 4 == 0) cout << "Guzz";
if (val % 64 != 0 && val % 32 != 0 && val % 16 != 0 && val % 8 != 0 && val % 4 != 0 && val % 2 == 0) cout << "Duzz";
if (val % 64 != 0 && val % 32 != 0 && val % 16 != 0 && val % 8 != 0 && val % 4 != 0 && val % 2 != 0) cout << "Hizz";

или же

if (val % 64 == 0)
{
cout << "FizzBuzz";
} else {
if (val % 32 == 0)
{
cout << "Fizz";
} else {
if (val % 16 == 0)
{
cout << "Buzz";
} else {
if (val % 8 == 0)
{
cout << "Muzz";
} else {
if (val % 4 == 0)
{
cout << "Guzz";
} else {
if (val % 2 == 0)
{
cout << "Duzz";
} else {
cout << "Hizz";
}
}
}
}
}
}
1

Другие решения

В первом примере:

    if (val1 % 15 == 0)
cout << "FizzBuzz\n";
if (val1 % 3 == 0)
cout << "Fizz\n";
if (val1 % 5 == 0)
cout << "Buzz\n";
else cout << val1 << "\n";

каждый случай будет проверяться на каждой итерации. Поскольку все кратные 15 также кратны 3 а также 5 все три будут напечатаны на экране.

В другом случае:

    if (val1 % 15 == 0)
cout << "FizzBuzz\n";
else if (val1 % 3 == 0)
cout << "Fizz\n";
else if (val1 % 5 == 0)
cout << "Buzz\n";
else cout << val1 << "\n";

первый случай (val1 % 15 == 0) будет проверен, и если он ложный, будет проверен второй, и если он ложный, будет проверен третий. Это означает, что только первый сверху вниз из четырех случаев когда-либо будет проверяться на истинность за итерацию.

Например, если вы должны были изменить порядок 5 а также 15:

    if (val1 % 5 == 0)
cout << "FizzBuzz\n";
else if (val1 % 3 == 0)
cout << "Fizz\n";
else if (val1 % 15 == 0)
cout << "Buzz\n";
else cout << val1 << "\n";

ты бы получил это Buzz никогда не будет напечатан, потому что, если значение делится на 15 ты бы остановил самый первый val1 % 5 == 0 тест, поэтому печать FizzBuzz,

3

Сначала код ловит числа, кратные 15, что означает, что они кратны двум а также 5. В этом случае печатается «FizzBuzz». Любое число, которое не проходит этот тест, может быть кратным 3 или же 5 но не и то и другое. Следующие два если операторы проверяют на кратность 3 или 5 соответственно

while (val1 < 101) {
if (val1 % 15 == 0)           // multiple of 3 AND 5
cout << "FizzBuzz\n";
else if (val1 % 3 == 0)       // multiple of ONLY 3
cout << "Fizz\n";
else if (val1 % 5 == 0)       // multiple of ONLY 5
cout << "Buzz\n";
else cout << val1 << "\n";
++val1;
}
1

Кратный 15 также кратное 5 и кратное 3. else говорит «только когда предыдущий если не было true затем do .. «; таким образом, удаление его из серии не взаимоисключающих условных выражений меняет логику.

Однако учтите, что условия мог быть сделаны взаимоисключающими:

if (val1 % 15 == 0)
cout << "FizzBuzz\n";

if (val1 % 3 == 0 && !(val1 % 15 == 0))
cout << "Fizz\n";

if (val1 % 5 == 0 !(val1 % 15 == 0))
cout << "Buzz\n";

if (!(val1 % 3 == 0) && !(val1 % 5 == 0)) // implies !(val1 % 15 == 0)
cout << val1 << "\n";

В этом случае для любого целочисленного значения только один из if условия будут верными.

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


С другой точки зрения, каждый else if последовательность может быть записана как «вложенное дерево». Семантика точно идентична, но структура может облегчить визуализацию пути. В этом случае должно быть ясно, что каждый случай терминала («cout») является взаимоисключающим от любого другого.

if (val1 % 15 == 0) {
cout << "FizzBuzz\n";
} else {
if (val1 % 3 == 0) {
cout << "Fizz\n";
} else {
if (val1 % 5 == 0) {
cout << "Buzz\n";
} else {
cout << val1 << "\n";
}
}
}
1
По вопросам рекламы [email protected]