fizzbuzz 中 if 与 if else if 之间的区别
Difference between if vs if else if in fizzbuzz
我尝试在 C++ 中实现 fizzbuzz,但对以下代码示例产生的不同输出感到困惑:
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
,然后是数字本身。
但是,以下代码可以完美运行。我知道 else if 使它正常工作,但我只是看不到 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();
}
代码首先捕获 15 的倍数,这意味着它们是 3 和 5 的倍数。在这种情况下,它会打印 "FizzBuzz"。任何未通过此测试的数字可能是 3 或 5 的倍数,但不是 两者 的倍数。接下来的两个 if 语句分别检查 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;
}
你的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";
}
}
}
}
}
}
在第一个例子中:
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
.
15的倍数是也是5的倍数和3的倍数。else
表示“仅当 previous if wasn't true then 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
序列都可以写成'nested tree'。语义完全相同,但结构可能使路径更容易可视化。在这种情况下,应该清楚每个终端案例 (a "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";
}
}
}
我尝试在 C++ 中实现 fizzbuzz,但对以下代码示例产生的不同输出感到困惑:
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
,然后是数字本身。
但是,以下代码可以完美运行。我知道 else if 使它正常工作,但我只是看不到 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();
}
代码首先捕获 15 的倍数,这意味着它们是 3 和 5 的倍数。在这种情况下,它会打印 "FizzBuzz"。任何未通过此测试的数字可能是 3 或 5 的倍数,但不是 两者 的倍数。接下来的两个 if 语句分别检查 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;
}
你的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";
}
}
}
}
}
}
在第一个例子中:
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
.
15的倍数是也是5的倍数和3的倍数。else
表示“仅当 previous if wasn't true then 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
序列都可以写成'nested tree'。语义完全相同,但结构可能使路径更容易可视化。在这种情况下,应该清楚每个终端案例 (a "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";
}
}
}