LunarCalendar中的二进制移位等问题的理解

写个万年历,学习了下农历的一些算法,其中有个方法研究了半天:

// 传回农历 y年的总天数
	final private static int yearDays(int y) {
    
    
	
		int i, sum = 348;
		
		for (i = 0x8000; i > 0x8; i >>= 1) {
    
    
			
			if ((lunarInfo[y - 1900] & i) != 0)
				
				sum += 1;
		
		}
		
		return (sum + leapDays(y));
	
	}
其中数组lunarinfo的源码,表示从1900年到2050年的十六进制码:
final static long[] lunarInfo = new long[] {
    
     0x04bd8, 0x04ae0, 0x0a570,
			0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2,
			0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0,
			0x0ada2, 0x095b0, 0x14977, 0x04970, 0x0a4b0, 0x0b4b5, 0x06a50,
			0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, 0x06566,
			0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0,
			0x1c8d7, 0x0c950, 0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4,
			0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, 0x06ca0, 0x0b550,
			0x15355, 0x04da0, 0x0a5d0, 0x14573, 0x052d0, 0x0a9a8, 0x0e950,
			0x06aa0, 0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260,
			0x0f263, 0x0d950, 0x05b57, 0x056a0, 0x096d0, 0x04dd5, 0x04ad0,
			0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b5a0, 0x195a6,
			0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40,
			0x0af46, 0x0ab60, 0x09570, 0x04af5, 0x04970, 0x064b0, 0x074a3,
			0x0ea50, 0x06b58, 0x055c0, 0x0ab60, 0x096d5, 0x092e0, 0x0c960,
			0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0,
			0x092d0, 0x0cab5, 0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9,
			0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, 0x07954, 0x06aa0,
			0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65,
			0x0d530, 0x05aa0, 0x076a3, 0x096d0, 0x04bd7, 0x04ad0, 0x0a4d0,
			0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, 0x0b5a0, 0x056d0, 0x055b2,
			0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0 };

一开始对0x8000等十六进制数不是很理解,为什么要设置成0x8000,为什么条件是0x8,为什么右移一位,,,经过思考,下面发表下自己的理解,也是因为CSDN没有这个源码的详细解释,我开个头头嘻嘻:

农历中,一年分12个月,每月30天或29天;每3年有一个闰月,5年两个闰月,19年7个闰月,算法是非常复杂的,所以一般那些牛×的机械手表,其实只能正常用到2100年,往后就不准了,需要自己调,那是,,,以后的事了
  1. 十六进制码代表的含义:
    转换为二进制,会产生20位01码,比如2050年0x0ada0 ,转换为二进制就是
    0000 1010 1101 1010 0000
    注意从低位在右边,我们来看这五组二进制数分别代表什么。
    一、有无闰月: 由低位的0000表示,0表示没有闰月,不为0,换算成十进制后的数字表示闰的月份,2050年没有闰月~
    二、每个月的天数:由中间12位的1010 1101 1010表示,从高位到低位,即从左到右的16到5位,0表示该月有29天,1表示该月有30天,2050年1月到12月的天数分别是30 29 30 29 30 30 29 30 30 29 30 29
    三、闰月天数:由高位的0000表示,0表示小闰月29天,1表示大闰月30天

  2. 再看刚开始的方法,获得某年的总天数
    一、首先我们知道,每年最少有12*29=348天,总天数是在这个基础上,加上闰月天数 leapDays(y),加上30天的月份数 += 1得来的
    二、表示年份的二进制码的中间12位进行与运算((lunarInfo[y - 1900] & i),就可以得出有30天的月份有几个。在这里我们把0x8000转换成二进制,0000 1000 0000 0000 0000,把0x8转换成二进制,0000 0000 0000 0000 1000,我把它们都编为了20位是为了方便跟表示年份的二进制码做运算,每次循环后,i都会右移一位,变成0000 0100 0000 0000 00000000 0010 0000 0000 以此类推~。
    这样就很明朗了,该方法的for循环,是轮流判断,表示每个月份的二进制码等不等于0,不等于0就表示该月为30天,总天数在348的基础上就要加1~

    希望对某些盆友能有所帮助和启发咯~~~~继续研究源码!
    

猜你喜欢

转载自blog.csdn.net/qq_41446977/article/details/112969040