一个公式,两行代码,实现任意两天天数计算(如该日当年第几天)(可推导蔡勒(Zeller)公式)

一个公式,两行代码,实现任意两天天数计算(如该日当年第几天)(可推导蔡勒(Zeller)公式))

  通过此文章,将介绍一种求任意两天天数计算的极简算法。(1852年10月15日后)通过这个算法我们可以很容易实现下面的功能:
  1.该日当年第几天
  2.距离某个纪念日已经过了多少天
  3.推导蔡勒(Zeller)公式

本文章将以计算“该日当年第几天”为例讲解这个算法并进行分析!
PS:文字不好看就看图片吧

常规解法

/*
程序题目:
输入年,月,日判断该日是该年的第几天!
*/
  常规解法是通过一个数组,保存12个月每个月的天数,(默认2月是28天),输入年份后,将该月之前的所有天数之和加起来,再加上该月日期,即可得到平年下该年月日为该年的第几天,但是如果是闰年,并且月数大于等于3月,那说明该年天数还得继续得加上一天,通过此方法可以求得任意年日是该年的第几天。

常规解法源码贴出:

#include<stdio.h>
#include<math.h>

int main()
{
	int year, month, day, sum = 0, i, j, flag = 0;
	int monthdays[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };

	printf("请输入年份:");
	scanf("%d", &year);
	printf("请输入月数:");
	scanf("%d", &month);
	printf("请输入日期:");
	scanf("%d", &day);

	if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
	{
		flag = 1;
	}
	else
	{
		flag = 0;
	}

	for (i = 0; i < month - 1; i++)
	{
		sum = sum + monthdays[i];
	}

	sum = sum + day;

	if (month >= 3 && flag)
	{
		sum = sum + 1;
	}

	printf("taday is %dth day\n", sum);
	return 0;
}

在这里插入图片描述

特殊解法

/*
算法思路: 子函数计算出该年该天距离0001-1-1的天数!
在同过减去该年的第一天"距离"0001-1-1的天数+1天从而得到是该年的第几天!
*/
  此算法易懂,但是代码量较大,并且定义数组也占用内存资源,下面介绍非常规操作:精简代码:真正的核心代码就几行。

先贴出核心代码:

#include <stdio.h>

int days(int y, int m, int d);

int main()
{
	int year, month, day;
	printf("请输入年份:");
	scanf("%d", &year);
	printf("请输入月数:");
	scanf("%d", &month);
	printf("请输入日期:");
	scanf("%d", &day);
	printf("该日是该年的第%d天\n", days(year, month, day) - days(year, 1, 1) + 1);
}

int days(int y, int m, int d)
{
	if (m < 3)
	{
		y--;
		m += 12;
	}
	return 365 * y + (y >> 2) - y / 100 + y / 400 + (153 * m - 457) / 5 + d - 306;
}

在这里插入图片描述

分析过程:
函数功能 计算出该年该天距离0001-1-1(公元1年1月1日)的天数

算法思路: 1,先找出每个月天数的规律
    把1月和2月当成上一年的13月和14月
    月份:03-04-05-06-07;08-09-10-11-12;13-14;
    天数:31-30-31-30-31;31-30-31-30-31;31-30(28)
    为了凸显规律,5个月,5个月一组
    规律就是:1-0-1-0-1(重复)
    2,找到m个月之前有多少天的公式(以3月为第一个月)
    由此规律就可以知道在m月(以3月为第一个月)之前有多有多少天
    月份:03-04-05-06-07;08-09-10-11-12;13-14;
    天数: 0- 1- 1- 2- 2; 3- 4- 4- 5- 5; 6- 7(28)(7用不到)
    所以有此表达式:(3*m-7)/5
    加上每个月30天后的gl
    月份:03-04-05-06- 07; 08- 09- 10- 11- 12;13-14;
    天数: 0-31-61-92-122;153-184-214-245-275;306-337(28)
    (因为求得是每个月之前的天数,正好2月在最后一天,所以这个数据可以舍弃,直接加上day即可(day<=28))
    所以有此表达式:( 153 * m - 457 ) / 5,求得m月之前有多有多少天
    如:m=3,之前只有0天
    m=4,之前有31天
    
    但是这是以3月为第一个月的每个月之前的天数
    当月数为3月之前,总天数不可能为负数,所以当月数为3月之前时,要将其转化为13,14月
    但是这样子在三月之前的天数都时300多天,相当于向前一年借了有年,所以年数要减少一年
    所以得出天数的规律:365 * y + ( 153 * m - 457 ) / 5 - 306 + d
    3,解决闰年每年多一天的问题
    四年一闰,百年不闰,四百年再闰
    所以每四年天数就要多一天:y >> 2(相当于y / 4(取整))
    但是每100年就不闰,所以百年时的天数不会相加,所以要减回去
    同理四百年再闰,还得加上这些年有多少个400年,补上2月多有的一天

    所以核心结果就是右边的公式:365 * y+(y>>2)-y/100+y/400+(153 * m-457)/5+d-306

  此算法是我大一寒假看到的,在这推广一下QQ群:8086730 我也是从这个群的群主“慢羊羊”那里学到的,为什么要推广一下这个QQ群呢,因为我当初在这个群里面学到了很多,里面有很多大佬,群里面的人也很和善,乐于帮助他人
  仔细一看核心代码,也就只有两行。

  现在有了上面的函数之后,求两任一年1月份天数之长,也就可以通过相减就可以得到,所以在主函数我们只需要调用以下语句,就可以达到目的,求得以上问题:

  days(year,month,day) - days(year,1,1) +1
  (子函数的功能是算距离某一天的天数,计算是该年的某一天需要再加上一天)

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值