序言

信息竞赛选修上老师给我们讲基础的条件判断语句中给我们讲了一道例题:平闰年计算器。

具体题目内容如下:

"输入一个年份,并判断这个年份是否为闰年"

其实平年闰年判断方式并不难:

总结下来便是:

"四年一闰,百年不闰,四百年又闰"

这便给我们提供了思路。

实现过程

我写代码的速度是很快的,遇到这种问题一般先把程序主体写好后再去精简这个程序。

按照这个方法,我们先把这个思路理一下:

不难看出,我们可以通过取模看他们的余数有没有0就可以了。

那么我们只需要再用if判断下条件即可:

// The First Code
#include <bits/stdc++.h>
using namespace std;

int main() {
    int year = 0;                   // 定义一个名为year的整型变量,初始值赋为0
    scanf("%d", &year);             // 输入一个整数并将输入的值保存在year变量中
    if (year % 100 == 0) {          // 判断是否为整百年
        if (year % 400 == 0) {      // 判断这个整百年是否满足“四百年又闰”的规律
            printf("闰年");
        } else {
            printf("平年");
        }
    } else if (year % 4 == 0) {     // 判断是否满足“四年一闰”的规律
        printf("闰年");
    } else {
        printf("平年");
    }
    return 0;
}

不难发现这个代码实在是太长了,虽然逻辑清晰,十分简单,修bug起来其实也十分的方便,但是嵌套这么多if这代码看着就是不舒服。

最终程序

我们注意到,判断整百年为闰年需要能与400整除,不是整百数就可以直接判断是否与4整除即可。

于是这串程序我们可以直接用一条if-else就能判断了:

// The Final Code
#include <bits/stdc++.h>
using namespace std;

int main() {
    int year = 0;                   // 定义一个名为year的整型变量,初始值赋为0
    scanf("%d", &year);             // 输入一个整数并将输入的值保存在year变量中
    // 以下代码是直接将我们第一次写的if全部用一条if-else判断
    if ((year % 100 == 0 && year % 400 == 0) || (year % 100 != 0 && year % 4 == 0)) {
        printf("闰年");
    } else {
        printf("平年");
    }
    return 0;
}

最后的话

我在我们信息竞赛选修中注意到有人为了省事,想写简单一点,于是跳过了与我类似的"先做后优化"这个过程(事实上,如果足够熟悉的确可以跳过,但要注意的是,新手尽量先做一遍再优化),于是程序上就出现了一些小的bug。

注意到第8行:

if ((year % 100 == 0 && year % 400 == 0) || (year % 100 != 0 && year % 4 == 0)) {

那位比较图省事的同学和我的"The Final Code"里的判断条件相比,他少了一句"year % 100 != 0":

// The Wrong Answer
#include <bits/stdc++.h>
using namespace std;

int main() {
    int year = 0;                   // 定义一个名为year的整型变量,初始值赋为0
    scanf("%d", &year);             // 输入一个整数并将输入的值保存在year变量中
    // 以下代码是直接将我们第一次写的if全部用一条if-else判断,但没有写"year % 100 != 0"
    if ((year % 100 == 0 && year % 400 == 0) || (year % 4 == 0)) {
        printf("闰年");
    } else {
        printf("平年");
    }
    return 0;
}

于是在运行这个程序的时候遇到了以下问题(第二行是输出的结果):

1900
闰年
--------------------------------
Process exited after 5.45 seconds with return value 0
请按任意键继续. . .

注意到:1900是一个整百年,1900除以4的值为475,也就是说1900模4等于0(余数为0,可以整除),但1900除以400就是4.75,也就是余数不为0。也就是说:

事实上,1900年是平年。

那问题到底是出在哪了?事实上,如果我们仔细观察这段错误的代码的话其实会发现有个细节:

(year % 100 == 0 && year % 400 == 0) || (year % 4 == 0)

这个判断条件如何读呢?其实他的意思很简单:

这个数如果是个整百数,且用它模400的值为0,那么结果为真,这个还没问题。

亦或者是:这个数与4的模为0,那么也为真,问题就出在这里。

我1900虽然是个整百数,我不能和400整除,但是!我可以和4整除啊,或后面的判断语句中又没说我不能是个整百数。

所以这个问题就来自于这,改的方法很简单,把或后面的那段语句改成"(year % 100 != 0 && year % 4 == 0)"就解决了。

其实这个问题并不复杂,修理起来也并不难,只不过在修这个问题的时候你可能需要重新看下这个程序到底是如何运行的才能发现这里的一个小问题。

(由于本人是初学者,可能会存在一些小问题,如果有问题或者有其他的思路也可以提出来,谢谢!)