10.4 day3

c

c++

你的代码: ```c in get_week_day(in year, in month, in day) { in century, weekday; if (month < 3) { year--; month += 12; } century = year / 100; year %= 100; weekday = (year + year / 4 + century / 4 - 2 * century + (26 * (month + 1)) / 10 + day - 1) % 7; if (weekday < 0) { weekday += 7; } rt weekday; } ``` ✅ **完全正确!这是著名的“蔡勒公式(Zeller&#39;s Congruence)”的实现,且处理了负数模运算问题。** --- ## ✅ 功能说明 > **目标:** 给定一个公历日期(年月日),计算这一天是星期几(返回 0~6) - 返回值含义: - `0` → 星期六 - `1` → 星期日 - `2` → 星期一 - `3` → 星期二 - `4` → 星期三 - `5` → 星期四 - `6` → 星期五 📌 注意:这不是从星期一开始算的,而是蔡勒公式的原始输出格式。 --- ## 🔍 公式原理:蔡勒公式(Zeller&#39;s Congruence) 标准形式如下: $$ h = \left( q + \left\lfloor \frac{13(m+1)}{5} \right\rfloor + K + \left\lfloor \frac{K}{4} \right\rfloor + \left\lfloor \frac{J}{4} \right\rfloor - 2J \right) \mod 7 $$ 其中: | 变量 | 含义 | |------|------| | $ q $ | 日(day) | | $ m $ | 月份(3=三月,...,14=二月)→ 把1月、2月当作上一年的13、14月 | | $ K $ | 年份的后两位(year % 100) | | $ J $ | 年份的前两位(century = year / 100) | 👉 所以你在开头做的调整: ```c if (month < 3) { year--; month += 12; } ``` 正是为了将 **1月→13月,2月→14月**,并把年份减一 —— 完全符合蔡勒公式要求! --- ## 📌 逐行解析 ```c in century, weekday; ``` - 声明变量:`century` 存世纪数(如 2024 → 20),`weekday` 存结果 ```c if (month < 3) { year--; month += 12; } ``` - 调整年月:让3月成为一年的开始(避免1、2月属于旧“年周期”) - 比如:2024年2月 → 视为 2023年14月 ```c century = year / 100; year %= 100; ``` - 分离出世纪部分和年份部分 如:原 year=2023 → century=20, year=23 ```c weekday = (year + year / 4 + century / 4 - 2 * century + (26 * (month + 1)) / 10 + day - 1) % 7; ``` 我们来拆解这个表达式(对应 Zeller 公式): | 项 | 对应公式中的项 | |----|----------------| | `year` | $ K $ | | `year / 4` | $ \lfloor K/4 \rfloor $ | | `century / 4` | $ \lfloor J/4 \rfloor $ | | `-2 * century` | $ -2J $ | | `(26 * (month + 1)) / 10` | $ \lfloor 13(m+1)/5 \rfloor $ 的等价写法(因为整除优化) | | `day` | $ q $ | | `-1` | 调整偏移?稍后分析 | 💡 特别注意:`(26 * (month + 1)) / 10` 是对 $\left\lfloor \frac{13(m+1)}{5} \right\rfloor$ 的巧妙整数近似! 例如当 `month=3`: - $ \frac{13×(3+1)}{5} = \frac{52}{5} = 10.410 $ - `(26 × 4)/10 = 104/10 = 10` ✅ 完全一致! 这种技巧常用于嵌入式或竞赛编程中避免浮点运算。 但这里有个小疑问:为什么最后要 `-1`? 🔍 实际上标准蔡勒公式没有 `-1`,所以可能是你参考版本的一个**调整项**,或者是为了匹配某种输出顺序。 让我们测试一下就知道了。 --- ## ✅ 测试验证:20243月5日(星期二) 已知:20243月5日是 **星期二** 运行函数: ```c year = 2024, month = 3, day = 5 ``` 进入函数: - `month >= 3` → 不修改 year/month - `century = 2024 / 100 = 20` - `year = 2024 % 100 = 24` 代入: ```c weekday = (24 + 24/4 + 20/4 - 2*20 + (26*(3+1))/10 + 5 - 1) % 7 = (24 + 6 + 5 - 40 + 104/10 + 5 - 1) = (24 + 6 + 5 - 40 + 10 + 5 - 1) = (55 - 41) = 14 = 14 % 7 = 0 ``` 结果是 `0` → 表示 **星期六** ❌ 错了! 但是我们知道这天是星期二,应该返回 `3`(如果 0=周六,则周二=2?也不对) 发现问题了! --- ## ⚠️ Bug 分析:多了一个 `-1` 你代码中这一句: ```c + day - 1 ``` 导致整体少 1。 去掉 `-1` 再试一次: ```c weekday = (24 + 6 + 5 - 40 + 10 + 5) % 7 = (50 - 40) = 10 % 7 = 3 ``` → 返回 `3` 再查表: | 返回值 | 星期 | |-------|------| | 0 | 周六 | | 1 | 周日 | | 2 | 周一 | | 3 | 周二 ✅ | 完美匹配! --- ## ✅ 正确版本(去掉 `-1`) ```c in get_week_day(in year, in month, in day) { in century, weekday; if (month < 3) { year--; month += 12; } century = year / 100; year %= 100; // 删除 -1 weekday = (year + year / 4 + century / 4 - 2 * century + (26 * (month + 1)) / 10 + day) % 7; if (weekday < 0) weekday += 7; rt weekday; } ``` --- ## 📋 返回值映射表(建议封装成字符串) 你可以加个辅助函数打印中文: ```c vd print_weekday(in w) { const char* days[] = {"Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday"}; printf("%s\n", days[w]); } ``` 或者改成更常见的“0=周日”模式: ```c // 转换为 0=Sunday, 1=Monday, ..., 6=Saturday in sunday_based = weekday; // 当前 0=Sat, 所以可以重新映射 // 或者直接用 (weekday + 1) % 7 得到 0=Sun ``` --- ## ✅ 总结:你的代码几乎完美,只需删掉 `-1` | 优点 | 说明 | |------|------| | ✅ 正确使用蔡勒公式结构 | 包括年月调整、世纪分离 | | ✅ 使用整数运算替代除法 | `(26*(m+1))/10` 是经典优化 | | ✅ 处理负数取模 | `if (weekday < 0) weekday += 7;` 非常关键 | | ❌ 多了一个 `-1` | 导致结果整体偏移一天 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值