闰年判断必须严格遵循ISO 8601标准:(y % 4 == 0 && y % 100 != 0) || (y % 400 == 0),且y须为正整数,避免负数取余未定义行为及跨世纪误判。

闰年判断的数学规则必须严格按 ISO 8601 执行
不是“能被4整除就是闰年”,这个常见误解会导致 2100、2200 等年份误判。ISO 标准规定:年份 y 是闰年当且仅当满足以下逻辑表达式:(y % 4 == 0 && y % 100 != 0) || (y % 400 == 0)。
注意:该规则适用于公历(格里高利历),且 y 必须是正整数(C++ 中建议用 int 或 unsigned int,避免负年份引发未定义行为)。
用 if 写最清晰的判断函数
直接封装成函数最安全,避免重复写逻辑或括号错位。关键点是运算符优先级——&& 优先级高于 ||,但加括号更易读、防错。
bool is_leap_year(int y) {
return (y % 4 == 0 && y % 100 != 0) || (y % 400 == 0);
}
- 不要写成
y % 4 == 0 && y % 100 != 0 || y % 400 == 0(虽语法正确,但易读性差,团队协作中容易漏括号) - 输入
y应做范围检查(如y >= 1),否则-4、0等值会因取模行为不符合日历语义 - 不推荐用三目运算符一行写完,可读性下降且不利于调试
常见错误:用 switch 或查表法硬编码
有人试图用 switch(y % 400) 枚举 400 种余数来判断,这既无必要又易出错。闰年规则是纯算术逻辑,不是离散状态映射。
-
switch不适合处理带条件组合的布尔逻辑 - 硬编码表无法应对运行时输入(比如用户输入年份),且维护成本高
- 现代 CPU 对几个取模和比较指令的执行效率远高于查 400 元素数组的 cache miss 开销
注意 % 运算符在负数上的 C++ 行为
C++ 中 % 是**取余**而非数学意义的“模”,当 y 为负时(如 -2000),y % 400 可能为负值(例如 -2000 % 400 == 0 是对的,但 -1900 % 100 在某些编译器下可能非 0)。因此:
立即学习“C++免费学习笔记(深入)”;
- 务必限制输入为正整数,可在函数开头加断言:
assert(y > 0); - 若需支持公元前年份(如天文计算),应改用
std::abs(y) % n并单独处理纪元分界逻辑,但这已超出标准闰年判定范畴 - 别依赖
y % 400 == 0对负y成立——它偶然成立不代表语义正确
is_leap_year 当作一个不可拆解的原子逻辑来调用就行。真正容易翻车的,往往不是公式本身,而是忘了年份得是正数,或者在跨世纪年份(如 1900、2000)上靠直觉拍脑袋。











