精华内容
下载资源
问答
  • 中国年历算法

    2009-05-10 18:38:00
    本文摘自“和笔记 - 中国农历二百年算法及年历”中国公历算法中国公历算法不是太难,关键是星期值确定。这里给出了简单算法: public static int dayOfWeek(int y, int m, int d) { int w = 1; // 公历一年一...

     本文摘自“和荣笔记 - 中国农历二百年算法及年历”

    中国公历算法

    中国公历算法不是太难,关键是星期值的确定。这里给出了简单算法: 

       public static int dayOfWeek(int y, int m, int d) {
          int w = 1; // 公历一年一月一日是星期一,所以起始值为星期日
          y = (y-1)%400 + 1; // 公历星期值分部 400 年循环一次
          int ly = (y-1)/4; // 闰年次数
          ly = ly - (y-1)/100;
          ly = ly + (y-1)/400;
          int ry = y - 1 - ly; // 常年次数
          w = w + ry; // 常年星期值增一
          w = w + 2*ly; // 闰年星期值增二
          w = w + dayOfYear(y,m,d); 
          w = (w-1)%7 + 1;
          return w;
       }
    



    中国农历算法

    根公历相比,中国农历的算法相当复杂。我在网上找的算法之中,eleworld.com 的算法是最好的一个。这个算法使用了大量的数据来确定农历月份和节气的分部,它仅实用于公历 1901 年到 2100 年之间的 200 年。 

    中国农历计算程式

    跟据 eleworld.com 提供的算法,我写了下面这个程式: 
    [HTML]<pre>
    /**
     * ChineseCalendarGB.java
     * Copyright (c) 1997-2002 by Dr. Herong Yang. http://www.herongyang.com/
     * 中国农历算法 - 实用于公历 1901 年至 2100 年之间的 200 年 
     */
    import java.text.*;
    import java.util.*;
    class ChineseCalendarGB {
       private int gregorianYear;
       private int gregorianMonth;
       private int gregorianDate;
       private boolean isGregorianLeap;
       private int dayOfYear;
       private int dayOfWeek; // 周日一星期的第一天
       private int chineseYear;
       private int chineseMonth; // 负数表示闰月
       private int chineseDate;
       private int sectionalTerm;
       private int principleTerm;
       private static char[] daysInGregorianMonth = 
          {31,28,31,30,31,30,31,31,30,31,30,31};
       private static String[] stemNames =
          {"甲","乙","丙","丁","戊","己","庚","辛","壬","癸"};
       private static String[] branchNames =
          {"子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"};
       private static String[] animalNames =
          {"鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"};
       public static void main(String[] arg) {
          ChineseCalendarGB c = new ChineseCalendarGB();
          String cmd = "day";
          int y = 1901;
          int m = 1;
          int d = 1;
          if (arg.length>0) cmd = arg[0];
          if (arg.length>1) y = Integer.parseInt(arg[1]);
          if (arg.length>2) m = Integer.parseInt(arg[2]);
          if (arg.length>3) d = Integer.parseInt(arg[3]);
          c.setGregorian(y,m,d);
          c.computeChineseFields();
          c.computeSolarTerms();
          if (cmd.equalsIgnoreCase("year")) {
             String[] t = c.getYearTable();
             for (int i=0; i<t.length; i++) System.out.println(t[i]);
          } else if (cmd.equalsIgnoreCase("month")) {
             String[] t = c.getMonthTable();
             for (int i=0; i<t.length; i++) System.out.println(t[i]);
          } else {
             System.out.println(c.toString());
          }
       }
       public ChineseCalendarGB() {
          setGregorian(1901,1,1);
       }
       public void setGregorian(int y, int m, int d) {
          gregorianYear = y;
          gregorianMonth = m;
          gregorianDate = d;
          isGregorianLeap = isGregorianLeapYear(y);
          dayOfYear = dayOfYear(y,m,d);
          dayOfWeek = dayOfWeek(y,m,d);
          chineseYear = 0;
          chineseMonth = 0;
          chineseDate = 0;
          sectionalTerm = 0;
          principleTerm = 0;
       }
       public static boolean isGregorianLeapYear(int year) {
          boolean isLeap = false;
          if (year%4==0) isLeap = true;
          if (year%100==0) isLeap = false;
          if (year%400==0) isLeap = true;
          return isLeap;
       }
       public static int daysInGregorianMonth(int y, int m) {
          int d = daysInGregorianMonth[m-1];
          if (m==2 && isGregorianLeapYear(y)) d++; // 公历闰年二月多一天
          return d;
       }
       public static int dayOfYear(int y, int m, int d) {
          int c = 0;
          for (int i=1; i<m; i++) {
             c = c + daysInGregorianMonth(y,i);
          }
          c = c + d;
          return c;      
       }
       public static int dayOfWeek(int y, int m, int d) {
          int w = 1; // 公历一年一月一日是星期一,所以起始值为星期日
          y = (y-1)%400 + 1; // 公历星期值分部 400 年循环一次
          int ly = (y-1)/4; // 闰年次数
          ly = ly - (y-1)/100;
          ly = ly + (y-1)/400;
          int ry = y - 1 - ly; // 常年次数
          w = w + ry; // 常年星期值增一
          w = w + 2*ly; // 闰年星期值增二
          w = w + dayOfYear(y,m,d); 
          w = (w-1)%7 + 1;
          return w;
       }
       private static char[] chineseMonths = { 
       // 农历月份大小压缩表,两个字节表示一年。两个字节共十六个二进制位数, 
       // 前四个位数表示闰月月份,后十二个位数表示十二个农历月份的大小。
       0x00,0x04,0xad,0x08,0x5a,0x01,0xd5,0x54,0xb4,0x09,0x64,0x05,0x59,0x45,
       0x95,0x0a,0xa6,0x04,0x55,0x24,0xad,0x08,0x5a,0x62,0xda,0x04,0xb4,0x05,
       0xb4,0x55,0x52,0x0d,0x94,0x0a,0x4a,0x2a,0x56,0x02,0x6d,0x71,0x6d,0x01,
       0xda,0x02,0xd2,0x52,0xa9,0x05,0x49,0x0d,0x2a,0x45,0x2b,0x09,0x56,0x01,
       0xb5,0x20,0x6d,0x01,0x59,0x69,0xd4,0x0a,0xa8,0x05,0xa9,0x56,0xa5,0x04,
       0x2b,0x09,0x9e,0x38,0xb6,0x08,0xec,0x74,0x6c,0x05,0xd4,0x0a,0xe4,0x6a,
       0x52,0x05,0x95,0x0a,0x5a,0x42,0x5b,0x04,0xb6,0x04,0xb4,0x22,0x6a,0x05,
       0x52,0x75,0xc9,0x0a,0x52,0x05,0x35,0x55,0x4d,0x0a,0x5a,0x02,0x5d,0x31,
       0xb5,0x02,0x6a,0x8a,0x68,0x05,0xa9,0x0a,0x8a,0x6a,0x2a,0x05,0x2d,0x09,
       0xaa,0x48,0x5a,0x01,0xb5,0x09,0xb0,0x39,0x64,0x05,0x25,0x75,0x95,0x0a,
       0x96,0x04,0x4d,0x54,0xad,0x04,0xda,0x04,0xd4,0x44,0xb4,0x05,0x54,0x85,
       0x52,0x0d,0x92,0x0a,0x56,0x6a,0x56,0x02,0x6d,0x02,0x6a,0x41,0xda,0x02,
       0xb2,0xa1,0xa9,0x05,0x49,0x0d,0x0a,0x6d,0x2a,0x09,0x56,0x01,0xad,0x50,
       0x6d,0x01,0xd9,0x02,0xd1,0x3a,0xa8,0x05,0x29,0x85,0xa5,0x0c,0x2a,0x09,
       0x96,0x54,0xb6,0x08,0x6c,0x09,0x64,0x45,0xd4,0x0a,0xa4,0x05,0x51,0x25,
       0x95,0x0a,0x2a,0x72,0x5b,0x04,0xb6,0x04,0xac,0x52,0x6a,0x05,0xd2,0x0a,
       0xa2,0x4a,0x4a,0x05,0x55,0x94,0x2d,0x0a,0x5a,0x02,0x75,0x61,0xb5,0x02,
       0x6a,0x03,0x61,0x45,0xa9,0x0a,0x4a,0x05,0x25,0x25,0x2d,0x09,0x9a,0x68,
       0xda,0x08,0xb4,0x09,0xa8,0x59,0x54,0x03,0xa5,0x0a,0x91,0x3a,0x96,0x04,
       0xad,0xb0,0xad,0x04,0xda,0x04,0xf4,0x62,0xb4,0x05,0x54,0x0b,0x44,0x5d,
       0x52,0x0a,0x95,0x04,0x55,0x22,0x6d,0x02,0x5a,0x71,0xda,0x02,0xaa,0x05,
       0xb2,0x55,0x49,0x0b,0x4a,0x0a,0x2d,0x39,0x36,0x01,0x6d,0x80,0x6d,0x01,
       0xd9,0x02,0xe9,0x6a,0xa8,0x05,0x29,0x0b,0x9a,0x4c,0xaa,0x08,0xb6,0x08,
       0xb4,0x38,0x6c,0x09,0x54,0x75,0xd4,0x0a,0xa4,0x05,0x45,0x55,0x95,0x0a,
       0x9a,0x04,0x55,0x44,0xb5,0x04,0x6a,0x82,0x6a,0x05,0xd2,0x0a,0x92,0x6a,
       0x4a,0x05,0x55,0x0a,0x2a,0x4a,0x5a,0x02,0xb5,0x02,0xb2,0x31,0x69,0x03,
       0x31,0x73,0xa9,0x0a,0x4a,0x05,0x2d,0x55,0x2d,0x09,0x5a,0x01,0xd5,0x48,
       0xb4,0x09,0x68,0x89,0x54,0x0b,0xa4,0x0a,0xa5,0x6a,0x95,0x04,0xad,0x08,
       0x6a,0x44,0xda,0x04,0x74,0x05,0xb0,0x25,0x54,0x03
       };
       // 初始日,公历农历对应日期:
       // 公历 1901 年 1 月 1 日,对应农历 4598 年 11 月 11 日
       private static int baseYear = 1901;
       private static int baseMonth = 1;
       private static int baseDate = 1;
       private static int baseIndex = 0;
       private static int baseChineseYear = 4598-1;
       private static int baseChineseMonth = 11;
       private static int baseChineseDate = 11;
       public int computeChineseFields() {
          if (gregorianYear<1901 || gregorianYear>2100) return 1;
          int startYear = baseYear;
          int startMonth = baseMonth;
          int startDate = baseDate;      
          chineseYear = baseChineseYear; 
          chineseMonth = baseChineseMonth;
          chineseDate = baseChineseDate;
          // 第二个对应日,用以提高计算效率
          // 公历 2000 年 1 月 1 日,对应农历 4697 年 11 月 25 日
          if (gregorianYear >= 2000) {
             startYear = baseYear + 99;
             startMonth = 1;
             startDate = 1;
             chineseYear = baseChineseYear + 99;
             chineseMonth = 11;
             chineseDate = 25;
          }
          int daysDiff = 0;
          for (int i=startYear; i<gregorianYear; i++) {
             daysDiff += 365;
             if (isGregorianLeapYear(i)) daysDiff += 1; // leap year
          }
          for (int i=startMonth; i<gregorianMonth; i++) {
             daysDiff += daysInGregorianMonth(gregorianYear,i);
          }
          daysDiff += gregorianDate - startDate;
          
          chineseDate += daysDiff;
          int lastDate = daysInChineseMonth(chineseYear, chineseMonth);
          int nextMonth = nextChineseMonth(chineseYear, chineseMonth);
          while (chineseDate>lastDate) {
             if (Math.abs(nextMonth)<Math.abs(chineseMonth)) chineseYear++;
             chineseMonth = nextMonth;
             chineseDate -= lastDate;
             lastDate = daysInChineseMonth(chineseYear, chineseMonth);
             nextMonth = nextChineseMonth(chineseYear, chineseMonth);
          }
          return 0;
       }
       private static int[] bigLeapMonthYears = {
          // 大闰月的闰年年份
            6, 14, 19, 25, 33, 36, 38, 41, 44, 52, 
           55, 79,117,136,147,150,155,158,185,193
          };
       public static int daysInChineseMonth(int y, int m) {
          // 注意:闰月 m < 0
          int index = y - baseChineseYear + baseIndex;
          int v = 0;
          int l = 0;
          int d = 30;
          if (1<=m && m<=8) {
             v = chineseMonths[2*index];
             l = m - 1;
             if ( ((v>>l)&0x01)==1 ) d = 29;
          } else if (9<=m && m<=12) {
             v = chineseMonths[2*index+1];
             l = m - 9;
             if ( ((v>>l)&0x01)==1 ) d = 29;
          } else {
             v = chineseMonths[2*index+1];
             v = (v>>4)&0x0F;
             if (v!=Math.abs(m)) {
                d = 0;
             } else {
                d = 29; 
                for (int i=0; i<bigLeapMonthYears.length; i++) {
                   if (bigLeapMonthYears[i]==index) {
                      d = 30;
                      break;
                   }
                }
             }
          }
          return d;
       }
       public static int nextChineseMonth(int y, int m) {
          int n = Math.abs(m) + 1;
          if (m>0) {
             int index = y - baseChineseYear + baseIndex;
             int v = chineseMonths[2*index+1];
             v = (v>>4)&0x0F;
             if (v==m) n = -m;
          }
          if (n==13) n = 1;
          return n;
       }
       private static char[][] sectionalTermMap = {
       {7,6,6,6,6,6,6,6,6,5,6,6,6,5,5,6,6,5,5,5,5,5,5,5,5,4,5,5},  
       {5,4,5,5,5,4,4,5,5,4,4,4,4,4,4,4,4,3,4,4,4,3,3,4,4,3,3,3},  
       {6,6,6,7,6,6,6,6,5,6,6,6,5,5,6,6,5,5,5,6,5,5,5,5,4,5,5,5,5},
       {5,5,6,6,5,5,5,6,5,5,5,5,4,5,5,5,4,4,5,5,4,4,4,5,4,4,4,4,5},
       {6,6,6,7,6,6,6,6,5,6,6,6,5,5,6,6,5,5,5,6,5,5,5,5,4,5,5,5,5},
       {6,6,7,7,6,6,6,7,6,6,6,6,5,6,6,6,5,5,6,6,5,5,5,6,5,5,5,5,4,5,5,5,5},
       {7,8,8,8,7,7,8,8,7,7,7,8,7,7,7,7,6,7,7,7,6,6,7,7,6,6,6,7,7},
       {8,8,8,9,8,8,8,8,7,8,8,8,7,7,8,8,7,7,7,8,7,7,7,7,6,7,7,7,6,6,7,7,7},
       {8,8,8,9,8,8,8,8,7,8,8,8,7,7,8,8,7,7,7,8,7,7,7,7,6,7,7,7,7},
       {9,9,9,9,8,9,9,9,8,8,9,9,8,8,8,9,8,8,8,8,7,8,8,8,7,7,8,8,8},
       {8,8,8,8,7,8,8,8,7,7,8,8,7,7,7,8,7,7,7,7,6,7,7,7,6,6,7,7,7},
       {7,8,8,8,7,7,8,8,7,7,7,8,7,7,7,7,6,7,7,7,6,6,7,7,6,6,6,7,7} 
       }; 
       private static char[][] sectionalTermYear = {
       {13,49,85,117,149,185,201,250,250},
       {13,45,81,117,149,185,201,250,250},
       {13,48,84,112,148,184,200,201,250},
       {13,45,76,108,140,172,200,201,250},
       {13,44,72,104,132,168,200,201,250},
       {5 ,33,68,96 ,124,152,188,200,201},
       {29,57,85,120,148,176,200,201,250},
       {13,48,76,104,132,168,196,200,201},
       {25,60,88,120,148,184,200,201,250},
       {16,44,76,108,144,172,200,201,250},
       {28,60,92,124,160,192,200,201,250},
       {17,53,85,124,156,188,200,201,250} 
       };
       private static char[][] principleTermMap = {
       {21,21,21,21,21,20,21,21,21,20,20,21,21,20,20,20,20,20,20,20,20,19,
          20,20,20,19,19,20},
       {20,19,19,20,20,19,19,19,19,19,19,19,19,18,19,19,19,18,18,19,19,18,
          18,18,18,18,18,18},
       {21,21,21,22,21,21,21,21,20,21,21,21,20,20,21,21,20,20,20,21,20,20,
          20,20,19,20,20,20,20},
       {20,21,21,21,20,20,21,21,20,20,20,21,20,20,20,20,19,20,20,20,19,19,
          20,20,19,19,19,20,20},
       {21,22,22,22,21,21,22,22,21,21,21,22,21,21,21,21,20,21,21,21,20,20,
          21,21,20,20,20,21,21},
       {22,22,22,22,21,22,22,22,21,21,22,22,21,21,21,22,21,21,21,21,20,21,
          21,21,20,20,21,21,21},
       {23,23,24,24,23,23,23,24,23,23,23,23,22,23,23,23,22,22,23,23,22,22,
          22,23,22,22,22,22,23},
       {23,24,24,24,23,23,24,24,23,23,23,24,23,23,23,23,22,23,23,23,22,22,
          23,23,22,22,22,23,23},
       {23,24,24,24,23,23,24,24,23,23,23,24,23,23,23,23,22,23,23,23,22,22,
          23,23,22,22,22,23,23},
       {24,24,24,24,23,24,24,24,23,23,24,24,23,23,23,24,23,23,23,23,22,23,
          23,23,22,22,23,23,23},
       {23,23,23,23,22,23,23,23,22,22,23,23,22,22,22,23,22,22,22,22,21,22,
          22,22,21,21,22,22,22},
       {22,22,23,23,22,22,22,23,22,22,22,22,21,22,22,22,21,21,22,22,21,21,
          21,22,21,21,21,21,22}
       };
       private static char[][] principleTermYear = {
       {13,45,81,113,149,185,201},    
       {21,57,93,125,161,193,201},    
       {21,56,88,120,152,188,200,201},
       {21,49,81,116,144,176,200,201},
       {17,49,77,112,140,168,200,201},
       {28,60,88,116,148,180,200,201},
       {25,53,84,112,144,172,200,201},
       {29,57,89,120,148,180,200,201},
       {17,45,73,108,140,168,200,201},
       {28,60,92,124,160,192,200,201},
       {16,44,80,112,148,180,200,201},
       {17,53,88,120,156,188,200,201} 
       };
       public int computeSolarTerms() {
          if (gregorianYear<1901 || gregorianYear>2100) return 1;
          sectionalTerm = sectionalTerm(gregorianYear, gregorianMonth);
          principleTerm = principleTerm(gregorianYear, gregorianMonth);
          return 0;
       }
       public static int sectionalTerm(int y, int m) {
          if (y<1901 || y>2100) return 0;
          int index = 0;
          int ry = y-baseYear+1;
          while (ry>=sectionalTermYear[m-1][index]) index++;
          int term = sectionalTermMap[m-1][4*index+ry%4];
          if ((ry == 121)&&(m == 4)) term = 5;
          if ((ry == 132)&&(m == 4)) term = 5;
          if ((ry == 194)&&(m == 6)) term = 6;
          return term;
       }
       public static int principleTerm(int y, int m) {
          if (y<1901 || y>2100) return 0;
          int index = 0;
          int ry = y-baseYear+1;
          while (ry>=principleTermYear[m-1][index]) index++;
          int term = principleTermMap[m-1][4*index+ry%4];
          if ((ry == 171)&&(m == 3)) term = 21;
          if ((ry == 181)&&(m == 5)) term = 21;
          return term;
       }
       public String toString() {
          StringBuffer buf = new StringBuffer();
          buf.append("Gregorian Year: "+gregorianYear+"/n");
          buf.append("Gregorian Month: "+gregorianMonth+"/n");
          buf.append("Gregorian Date: "+gregorianDate+"/n");
          buf.append("Is Leap Year: "+isGregorianLeap+"/n");
          buf.append("Day of Year: "+dayOfYear+"/n");
          buf.append("Day of Week: "+dayOfWeek+"/n");
          buf.append("Chinese Year: "+chineseYear+"/n");
          buf.append("Heavenly Stem: "+((chineseYear-1)%10)+"/n");
          buf.append("Earthly Branch: "+((chineseYear-1)%12)+"/n");
          buf.append("Chinese Month: "+chineseMonth+"/n");
          buf.append("Chinese Date: "+chineseDate+"/n");
          buf.append("Sectional Term: "+sectionalTerm+"/n");
          buf.append("Principle Term: "+principleTerm+"/n");
          return buf.toString();
       }
       public String[] getYearTable() {
          setGregorian(gregorianYear,1,1);
          computeChineseFields();
          computeSolarTerms();
          String[] table = new String[58]; // 6*9 + 4
          table[0] = getTextLine(27, "公历年历:"+gregorianYear);
          table[1] = getTextLine(27, "农历年历:"+(chineseYear+1)
             + " ("+stemNames[(chineseYear+1-1)%10]
             + branchNames[(chineseYear+1-1)%12]
             + " - "+animalNames[(chineseYear+1-1)%12]+"年)");
          int ln = 2;
          String blank  = "                                         "
                  +"  " + "                                         ";
          String[] mLeft = null;
          String[] mRight = null;
          for (int i=1; i<=6; i++) {
             table[ln] = blank;
             ln++;
             mLeft = getMonthTable();
             mRight = getMonthTable();
             for (int j=0; j<mLeft.length; j++) {
                String line = mLeft[j] + "  " + mRight[j];
                table[ln] = line;
                ln++;
             }
          }
          table[ln] = blank;
          ln++;
          table[ln] = getTextLine(0,
             "##/## - 公历日期/农历日期,(*)#月 - (闰)农历月第一天");
          ln++;
          return table;
       }
       public static String getTextLine(int s, String t) {
          String str  = "                                         "
                  +"  " + "                                         ";
          if (t!=null && s<str.length() && s+t.length()<str.length())
             str = str.substring(0,s) + t + str.substring(s+t.length());
          return str;
       }
       private static String[] monthNames =
          {"一","二","三","四","五","六","七","八","九","十","十一","十二"};
       public String[] getMonthTable() {
          setGregorian(gregorianYear,gregorianMonth,1);
          computeChineseFields();
          computeSolarTerms();
          String[] table = new String[8]; 
          String title  = null;
          if (gregorianMonth<11) title  = "                   ";
          else title  = "                 ";
          title = title + monthNames[gregorianMonth-1] + "月"
                        + "                   ";
          String header = "   日    一    二    三    四    五    六 ";
          String blank  = "                                          ";
          table[0] = title;
          table[1] = header;
          int wk = 2;
          String line = "";
          for (int i=1; i<dayOfWeek; i++) {
             line += "     " + ' ';
          }
          int days = daysInGregorianMonth(gregorianYear,gregorianMonth);
          for (int i=gregorianDate; i<=days; i++) {
             line += getDateString() + ' ';
             rollUpOneDay();
             if (dayOfWeek==1) {
                table[wk] = line;
                line = "";
                wk++;
             }
          }
          for (int i=dayOfWeek; i<=7; i++) {
             line += "     " + ' ';
          }
          table[wk] = line;
          for (int i=wk+1; i<table.length; i++) {
             table[i] = blank;
          }
          for (int i=0; i<table.length; i++) {
             table[i] = table[i].substring(0,table[i].length()-1);
          }
          
          return table;
       }
       private static String[] chineseMonthNames =
          {"正","二","三","四","五","六","七","八","九","十","冬","腊"};
       private static String[] principleTermNames =
          {"雨水","春分","谷雨","夏满","夏至","大暑","处暑","秋分","霜降", 
           "小雪","冬至","大寒"};
       private static String[] sectionalTermNames =
          {"立春","惊蛰","清明","立夏","芒种","小暑","立秋","白露","寒露",
           "立冬","大雪","小寒"};
       public String getDateString() {
          String str = "*  /  ";
          String gm = String.valueOf(gregorianMonth);
          if (gm.length()==1) gm = ' ' + gm;
          String cm = String.valueOf(Math.abs(chineseMonth));
          if (cm.length()==1) cm = ' ' + cm;
          String gd = String.valueOf(gregorianDate);
          if (gd.length()==1) gd = ' ' + gd;
          String cd = String.valueOf(chineseDate);
          if (cd.length()==1) cd = ' ' + cd;
          if (gregorianDate==sectionalTerm) {
             str = " "+sectionalTermNames[gregorianMonth-1];
          } else if (gregorianDate==principleTerm) {
             str = " "+principleTermNames[gregorianMonth-1];
          } else if (chineseDate==1 && chineseMonth>0) {
               str = " "+chineseMonthNames[chineseMonth-1]+"月";
          } else if (chineseDate==1 && chineseMonth<0) {
               str = "*"+chineseMonthNames[-chineseMonth-1]+"月";
          } else {
               str = gd+'/'+cd;
          }
          return str;
       }
       public int rollUpOneDay() {
          dayOfWeek = dayOfWeek%7 + 1;
          dayOfYear++;
          gregorianDate++;
          int days = daysInGregorianMonth(gregorianYear,gregorianMonth); 
          if (gregorianDate>days) {
             gregorianDate = 1;
             gregorianMonth++;
             if (gregorianMonth>12) {
                gregorianMonth = 1;
                gregorianYear++;
                dayOfYear = 1;
                isGregorianLeap = isGregorianLeapYear(gregorianYear);
             }
             sectionalTerm = sectionalTerm(gregorianYear,gregorianMonth);
             principleTerm = principleTerm(gregorianYear,gregorianMonth);
          }
          chineseDate++;
          days = daysInChineseMonth(chineseYear,chineseMonth);
          if (chineseDate>days) {
             chineseDate = 1;
             chineseMonth = nextChineseMonth(chineseYear,chineseMonth);
             if (chineseMonth==1) chineseYear++;
          }
          return 0;
       }
    }
    </pre>[/HTML]

    中国二百年年历 1901 年至 2100 年

    我用上面这个程式制作了二百年年历,1901 年至 2100 年,全部收录在这本书中。 

    年历格式说明: 

    农历日期列在公历日期后面。 
    节气用节气名称标明。 
    农历每月第一天用月份名称标明。 
    例如,2000 年一月的表达格式如下: 
    [HTML]<pre>
                       一月                  
       日    一    二    三    四    五    六
                                         1/25
     2/26  3/27  4/28  5/29  立春  腊月  8/ 2
     9/ 3 10/ 4 11/ 5 12/ 6 13/ 7 14/ 8 15/ 9
    16/10 17/11 18/12 19/13 20/14  雨水 22/16
    23/17 24/18 25/19 26/20 27/21 28/22 29/23
    30/24 31/25                              
    </pre>[/HTML]

    其中: 

    "1/25" - 表示公历 1 号和农历 25 号。 
    "立春" - 表示节气。 
    "腊月" - 表示农历 12 月第一天。 

    ------
    有关中国年历算法和程式的详细注解和二百年年历,请参考
    “和荣笔记 - 中国农历二百年算法及年历”
    http://www.herongyang.com/year_gb/

    展开全文
  • 中国年历算法和程式

    2007-02-11 17:49:00
    中国年历算法和程式 本文摘自“和笔记 - 中国农历二百年算法及年历”中国公历算法中国公历算法不是太难,关键是星期值确定。这里给出了简单算法: public static int dayOfWeek(int y, int m, int d) { int w = ...

    中国年历算法和程式

    本文摘自
    “和荣笔记 - 中国农历二百年算法及年历”

    中国公历算法

    中国公历算法不是太难,关键是星期值的确定。这里给出了简单算法:

    public static int dayOfWeek(int y, int m, int d) 
    { int w = 1;
    // 公历一年一月一日是星期一,所以起始值为星期日 y = (y-1)%400 + 1;
    // 公历星期值分部 400 年循环一次 int ly = (y-1)/4;
    // 闰年次数 ly = ly - (y-1)/100; ly = ly + (y-1)/400; int ry = y - 1 - ly;
    // 常年次数 w = w + ry;
    // 常年星期值增一 w = w + 2*ly;
    // 闰年星期值增二 w = w + dayOfYear(y,m,d); w = (w-1)%7 + 1; return w; }



    中国农历算法

    根公历相比,中国农历的算法相当复杂。我在网上找的算法之中,eleworld.com 的算法是最好的一个。这个算法使用了大量的数据来确定农历月份和节气的分部,它仅实用于公历 1901 年到 2100 年之间的 200 年。

    中国农历计算程式

    跟据 eleworld.com 提供的算法,我写了下面这个程式:
    [HTML]
    中国二百年年历 1901 年至 2100 年

    我用上面这个程式制作了二百年年历,1901 年至 2100 年,全部收录在这本书中。

    年历格式说明:

    农历日期列在公历日期后面。
    节气用节气名称标明。
    农历每月第一天用月份名称标明。
    例如,2000 年一月的表达格式如下:
    [HTML]


    一月
    日 一 二 三 四 五 六
    1/25
    2/26 3/27 4/28 5/29 立春 腊月 8/ 2
    9/ 3 10/ 4 11/ 5 12/ 6 13/ 7 14/ 8 15/ 9
    16/10 17/11 18/12 19/13 20/14 雨水 22/16
    23/17 24/18 25/19 26/20 27/21 28/22 29/23
    30/24 31/25
    [/HTML]

    其中:

    "1/25" - 表示公历 1 号和农历 25 号。
    "立春" - 表示节气。
    "腊月" - 表示农历 12 月第一天。 
     

    /**
    * ChineseCalendarGB.java
    * Copyright (c) 1997-2002 by Dr. Herong Yang. http://www.herongyang.com/
    * 中国农历算法 - 实用于公历 1901 年至 2100 年之间的 200 年
    */
    import java.text.*;
    import java.util.*;
    class ChineseCalendarGB {
    private int gregorianYear;
    private int gregorianMonth;
    private int gregorianDate;
    private boolean isGregorianLeap;
    private int dayOfYear;
    private int dayOfWeek; // 周日一星期的第一天
    private int chineseYear;
    private int chineseMonth; // 负数表示闰月
    private int chineseDate;
    private int sectionalTerm;
    private int principleTerm;
    private static char[] daysInGregorianMonth =
    {31,28,31,30,31,30,31,31,30,31,30,31};
    private static String[] stemNames =
    {"甲","乙","丙","丁","戊","己","庚","辛","壬","癸"};
    private static String[] branchNames =
    {"子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"};
    private static String[] animalNames =
    {"鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"};
    public static void main(String[] arg) {
    ChineseCalendarGB c = new ChineseCalendarGB();
    String cmd = "day";
    int y = 1901;
    int m = 1;
    int d = 1;
    if (arg.length>0) cmd = arg[0];
    if (arg.length>1) y = Integer.parseInt(arg[1]);
    if (arg.length>2) m = Integer.parseInt(arg[2]);
    if (arg.length>3) d = Integer.parseInt(arg[3]);
    c.setGregorian(y,m,d);
    c.computeChineseFields();
    c.computeSolarTerms();
    if (cmd.equalsIgnoreCase("year")) {
    String[] t = c.getYearTable();
    for (int i=0; i } else if (cmd.equalsIgnoreCase("month")) {
    String[] t = c.getMonthTable();
    for (int i=0; i } else {
    System.out.println(c.toString());
    }
    }
    public ChineseCalendarGB() {
    setGregorian(1901,1,1);
    }
    public void setGregorian(int y, int m, int d) {
    gregorianYear = y;
    gregorianMonth = m;
    gregorianDate = d;
    isGregorianLeap = isGregorianLeapYear(y);
    dayOfYear = dayOfYear(y,m,d);
    dayOfWeek = dayOfWeek(y,m,d);
    chineseYear = 0;
    chineseMonth = 0;
    chineseDate = 0;
    sectionalTerm = 0;
    principleTerm = 0;
    }
    public static boolean isGregorianLeapYear(int year) {
    boolean isLeap = false;
    if (year%4==0) isLeap = true;
    if (year%100==0) isLeap = false;
    if (year%400==0) isLeap = true;
    return isLeap;
    }
    public static int daysInGregorianMonth(int y, int m) {
    int d = daysInGregorianMonth[m-1];
    if (m==2 && isGregorianLeapYear(y)) d++; // 公历闰年二月多一天
    return d;
    }
    public static int dayOfYear(int y, int m, int d) {
    int c = 0;
    for (int i=1; i c = c + daysInGregorianMonth(y,i);
    }
    c = c + d;
    return c;
    }
    public static int dayOfWeek(int y, int m, int d) {
    int w = 1; // 公历一年一月一日是星期一,所以起始值为星期日
    y = (y-1)%400 + 1; // 公历星期值分部 400 年循环一次
    int ly = (y-1)/4; // 闰年次数
    ly = ly - (y-1)/100;
    ly = ly + (y-1)/400;
    int ry = y - 1 - ly; // 常年次数
    w = w + ry; // 常年星期值增一
    w = w + 2*ly; // 闰年星期值增二
    w = w + dayOfYear(y,m,d);
    w = (w-1)%7 + 1;
    return w;
    }
    private static char[] chineseMonths = {
    // 农历月份大小压缩表,两个字节表示一年。两个字节共十六个二进制位数,
    // 前四个位数表示闰月月份,后十二个位数表示十二个农历月份的大小。
    0x00,0x04,0xad,0x08,0x5a,0x01,0xd5,0x54,0xb4,0x09,0x64,0x05,0x59,0x45,
    0x95,0x0a,0xa6,0x04,0x55,0x24,0xad,0x08,0x5a,0x62,0xda,0x04,0xb4,0x05,
    0xb4,0x55,0x52,0x0d,0x94,0x0a,0x4a,0x2a,0x56,0x02,0x6d,0x71,0x6d,0x01,
    0xda,0x02,0xd2,0x52,0xa9,0x05,0x49,0x0d,0x2a,0x45,0x2b,0x09,0x56,0x01,
    0xb5,0x20,0x6d,0x01,0x59,0x69,0xd4,0x0a,0xa8,0x05,0xa9,0x56,0xa5,0x04,
    0x2b,0x09,0x9e,0x38,0xb6,0x08,0xec,0x74,0x6c,0x05,0xd4,0x0a,0xe4,0x6a,
    0x52,0x05,0x95,0x0a,0x5a,0x42,0x5b,0x04,0xb6,0x04,0xb4,0x22,0x6a,0x05,
    0x52,0x75,0xc9,0x0a,0x52,0x05,0x35,0x55,0x4d,0x0a,0x5a,0x02,0x5d,0x31,
    0xb5,0x02,0x6a,0x8a,0x68,0x05,0xa9,0x0a,0x8a,0x6a,0x2a,0x05,0x2d,0x09,
    0xaa,0x48,0x5a,0x01,0xb5,0x09,0xb0,0x39,0x64,0x05,0x25,0x75,0x95,0x0a,
    0x96,0x04,0x4d,0x54,0xad,0x04,0xda,0x04,0xd4,0x44,0xb4,0x05,0x54,0x85,
    0x52,0x0d,0x92,0x0a,0x56,0x6a,0x56,0x02,0x6d,0x02,0x6a,0x41,0xda,0x02,
    0xb2,0xa1,0xa9,0x05,0x49,0x0d,0x0a,0x6d,0x2a,0x09,0x56,0x01,0xad,0x50,
    0x6d,0x01,0xd9,0x02,0xd1,0x3a,0xa8,0x05,0x29,0x85,0xa5,0x0c,0x2a,0x09,
    0x96,0x54,0xb6,0x08,0x6c,0x09,0x64,0x45,0xd4,0x0a,0xa4,0x05,0x51,0x25,
    0x95,0x0a,0x2a,0x72,0x5b,0x04,0xb6,0x04,0xac,0x52,0x6a,0x05,0xd2,0x0a,
    0xa2,0x4a,0x4a,0x05,0x55,0x94,0x2d,0x0a,0x5a,0x02,0x75,0x61,0xb5,0x02,
    0x6a,0x03,0x61,0x45,0xa9,0x0a,0x4a,0x05,0x25,0x25,0x2d,0x09,0x9a,0x68,
    0xda,0x08,0xb4,0x09,0xa8,0x59,0x54,0x03,0xa5,0x0a,0x91,0x3a,0x96,0x04,
    0xad,0xb0,0xad,0x04,0xda,0x04,0xf4,0x62,0xb4,0x05,0x54,0x0b,0x44,0x5d,
    0x52,0x0a,0x95,0x04,0x55,0x22,0x6d,0x02,0x5a,0x71,0xda,0x02,0xaa,0x05,
    0xb2,0x55,0x49,0x0b,0x4a,0x0a,0x2d,0x39,0x36,0x01,0x6d,0x80,0x6d,0x01,
    0xd9,0x02,0xe9,0x6a,0xa8,0x05,0x29,0x0b,0x9a,0x4c,0xaa,0x08,0xb6,0x08,
    0xb4,0x38,0x6c,0x09,0x54,0x75,0xd4,0x0a,0xa4,0x05,0x45,0x55,0x95,0x0a,
    0x9a,0x04,0x55,0x44,0xb5,0x04,0x6a,0x82,0x6a,0x05,0xd2,0x0a,0x92,0x6a,
    0x4a,0x05,0x55,0x0a,0x2a,0x4a,0x5a,0x02,0xb5,0x02,0xb2,0x31,0x69,0x03,
    0x31,0x73,0xa9,0x0a,0x4a,0x05,0x2d,0x55,0x2d,0x09,0x5a,0x01,0xd5,0x48,
    0xb4,0x09,0x68,0x89,0x54,0x0b,0xa4,0x0a,0xa5,0x6a,0x95,0x04,0xad,0x08,
    0x6a,0x44,0xda,0x04,0x74,0x05,0xb0,0x25,0x54,0x03
    };
    // 初始日,公历农历对应日期:
    // 公历 1901 年 1 月 1 日,对应农历 4598 年 11 月 11 日
    private static int baseYear = 1901;
    private static int baseMonth = 1;
    private static int baseDate = 1;
    private static int baseIndex = 0;
    private static int baseChineseYear = 4598-1;
    private static int baseChineseMonth = 11;
    private static int baseChineseDate = 11;
    public int computeChineseFields() {
    if (gregorianYear<1901 || gregorianYear>2100) return 1;
    int startYear = baseYear;
    int startMonth = baseMonth;
    int startDate = baseDate;
    chineseYear = baseChineseYear;
    chineseMonth = baseChineseMonth;
    chineseDate = baseChineseDate;
    // 第二个对应日,用以提高计算效率
    // 公历 2000 年 1 月 1 日,对应农历 4697 年 11 月 25 日
    if (gregorianYear >= 2000) {
    startYear = baseYear + 99;
    startMonth = 1;
    startDate = 1;
    chineseYear = baseChineseYear + 99;
    chineseMonth = 11;
    chineseDate = 25;
    }
    int daysDiff = 0;
    for (int i=startYear; i daysDiff += 365;
    if (isGregorianLeapYear(i)) daysDiff += 1; // leap year
    }
    for (int i=startMonth; i daysDiff += daysInGregorianMonth(gregorianYear,i);
    }
    daysDiff += gregorianDate - startDate;

    chineseDate += daysDiff;
    int lastDate = daysInChineseMonth(chineseYear, chineseMonth);
    int nextMonth = nextChineseMonth(chineseYear, chineseMonth);
    while (chineseDate>lastDate) {
    if (Math.abs(nextMonth) chineseMonth = nextMonth;
    chineseDate -= lastDate;
    lastDate = daysInChineseMonth(chineseYear, chineseMonth);
    nextMonth = nextChineseMonth(chineseYear, chineseMonth);
    }
    return 0;
    }
    private static int[] bigLeapMonthYears = {
    // 大闰月的闰年年份
    6, 14, 19, 25, 33, 36, 38, 41, 44, 52,
    55, 79,117,136,147,150,155,158,185,193
    };
    public static int daysInChineseMonth(int y, int m) {
    // 注意:闰月 m < 0
    int index = y - baseChineseYear + baseIndex;
    int v = 0;
    int l = 0;
    int d = 30;
    if (1<=m && m<=8) {
    v = chineseMonths[2*index];
    l = m - 1;
    if ( ((v>>l)&0x01)==1 ) d = 29;
    } else if (9<=m && m<=12) {
    v = chineseMonths[2*index+1];
    l = m - 9;
    if ( ((v>>l)&0x01)==1 ) d = 29;
    } else {
    v = chineseMonths[2*index+1];
    v = (v>>4)&0x0F;
    if (v!=Math.abs(m)) {
    d = 0;
    } else {
    d = 29;
    for (int i=0; i if (bigLeapMonthYears[i]==index) {
    d = 30;
    break;
    }
    }
    }
    }
    return d;
    }
    public static int nextChineseMonth(int y, int m) {
    int n = Math.abs(m) + 1;
    if (m>0) {
    int index = y - baseChineseYear + baseIndex;
    int v = chineseMonths[2*index+1];
    v = (v>>4)&0x0F;
    if (v==m) n = -m;
    }
    if (n==13) n = 1;
    return n;
    }
    private static char[][] sectionalTermMap = {
    {7,6,6,6,6,6,6,6,6,5,6,6,6,5,5,6,6,5,5,5,5,5,5,5,5,4,5,5},
    {5,4,5,5,5,4,4,5,5,4,4,4,4,4,4,4,4,3,4,4,4,3,3,4,4,3,3,3},
    {6,6,6,7,6,6,6,6,5,6,6,6,5,5,6,6,5,5,5,6,5,5,5,5,4,5,5,5,5},
    {5,5,6,6,5,5,5,6,5,5,5,5,4,5,5,5,4,4,5,5,4,4,4,5,4,4,4,4,5},
    {6,6,6,7,6,6,6,6,5,6,6,6,5,5,6,6,5,5,5,6,5,5,5,5,4,5,5,5,5},
    {6,6,7,7,6,6,6,7,6,6,6,6,5,6,6,6,5,5,6,6,5,5,5,6,5,5,5,5,4,5,5,5,5},
    {7,8,8,8,7,7,8,8,7,7,7,8,7,7,7,7,6,7,7,7,6,6,7,7,6,6,6,7,7},
    {8,8,8,9,8,8,8,8,7,8,8,8,7,7,8,8,7,7,7,8,7,7,7,7,6,7,7,7,6,6,7,7,7},
    {8,8,8,9,8,8,8,8,7,8,8,8,7,7,8,8,7,7,7,8,7,7,7,7,6,7,7,7,7},
    {9,9,9,9,8,9,9,9,8,8,9,9,8,8,8,9,8,8,8,8,7,8,8,8,7,7,8,8,8},
    {8,8,8,8,7,8,8,8,7,7,8,8,7,7,7,8,7,7,7,7,6,7,7,7,6,6,7,7,7},
    {7,8,8,8,7,7,8,8,7,7,7,8,7,7,7,7,6,7,7,7,6,6,7,7,6,6,6,7,7}
    };
    private static char[][] sectionalTermYear = {
    {13,49,85,117,149,185,201,250,250},
    {13,45,81,117,149,185,201,250,250},
    {13,48,84,112,148,184,200,201,250},
    {13,45,76,108,140,172,200,201,250},
    {13,44,72,104,132,168,200,201,250},
    {5 ,33,68,96 ,124,152,188,200,201},
    {29,57,85,120,148,176,200,201,250},
    {13,48,76,104,132,168,196,200,201},
    {25,60,88,120,148,184,200,201,250},
    {16,44,76,108,144,172,200,201,250},
    {28,60,92,124,160,192,200,201,250},
    {17,53,85,124,156,188,200,201,250}
    };
    private static char[][] principleTermMap = {
    {21,21,21,21,21,20,21,21,21,20,20,21,21,20,20,20,20,20,20,20,20,19,
    20,20,20,19,19,20},
    {20,19,19,20,20,19,19,19,19,19,19,19,19,18,19,19,19,18,18,19,19,18,
    18,18,18,18,18,18},
    {21,21,21,22,21,21,21,21,20,21,21,21,20,20,21,21,20,20,20,21,20,20,
    20,20,19,20,20,20,20},
    {20,21,21,21,20,20,21,21,20,20,20,21,20,20,20,20,19,20,20,20,19,19,
    20,20,19,19,19,20,20},
    {21,22,22,22,21,21,22,22,21,21,21,22,21,21,21,21,20,21,21,21,20,20,
    21,21,20,20,20,21,21},
    {22,22,22,22,21,22,22,22,21,21,22,22,21,21,21,22,21,21,21,21,20,21,
    21,21,20,20,21,21,21},
    {23,23,24,24,23,23,23,24,23,23,23,23,22,23,23,23,22,22,23,23,22,22,
    22,23,22,22,22,22,23},
    {23,24,24,24,23,23,24,24,23,23,23,24,23,23,23,23,22,23,23,23,22,22,
    23,23,22,22,22,23,23},
    {23,24,24,24,23,23,24,24,23,23,23,24,23,23,23,23,22,23,23,23,22,22,
    23,23,22,22,22,23,23},
    {24,24,24,24,23,24,24,24,23,23,24,24,23,23,23,24,23,23,23,23,22,23,
    23,23,22,22,23,23,23},
    {23,23,23,23,22,23,23,23,22,22,23,23,22,22,22,23,22,22,22,22,21,22,
    22,22,21,21,22,22,22},
    {22,22,23,23,22,22,22,23,22,22,22,22,21,22,22,22,21,21,22,22,21,21,
    21,22,21,21,21,21,22}
    };
    private static char[][] principleTermYear = {
    {13,45,81,113,149,185,201},
    {21,57,93,125,161,193,201},
    {21,56,88,120,152,188,200,201},
    {21,49,81,116,144,176,200,201},
    {17,49,77,112,140,168,200,201},
    {28,60,88,116,148,180,200,201},
    {25,53,84,112,144,172,200,201},
    {29,57,89,120,148,180,200,201},
    {17,45,73,108,140,168,200,201},
    {28,60,92,124,160,192,200,201},
    {16,44,80,112,148,180,200,201},
    {17,53,88,120,156,188,200,201}
    };
    public int computeSolarTerms() {
    if (gregorianYear<1901 || gregorianYear>2100) return 1;
    sectionalTerm = sectionalTerm(gregorianYear, gregorianMonth);
    principleTerm = principleTerm(gregorianYear, gregorianMonth);
    return 0;
    }
    public static int sectionalTerm(int y, int m) {
    if (y<1901 || y>2100) return 0;
    int index = 0;
    int ry = y-baseYear+1;
    while (ry>=sectionalTermYear[m-1][index]) index++;
    int term = sectionalTermMap[m-1][4*index+ry%4];
    if ((ry == 121)&&(m == 4)) term = 5;
    if ((ry == 132)&&(m == 4)) term = 5;
    if ((ry == 194)&&(m == 6)) term = 6;
    return term;
    }
    public static int principleTerm(int y, int m) {
    if (y<1901 || y>2100) return 0;
    int index = 0;
    int ry = y-baseYear+1;
    while (ry>=principleTermYear[m-1][index]) index++;
    int term = principleTermMap[m-1][4*index+ry%4];
    if ((ry == 171)&&(m == 3)) term = 21;
    if ((ry == 181)&&(m == 5)) term = 21;
    return term;
    }
    public String toString() {
    StringBuffer buf = new StringBuffer();
    buf.append("Gregorian Year: "+gregorianYear+"/n");
    buf.append("Gregorian Month: "+gregorianMonth+"/n");
    buf.append("Gregorian Date: "+gregorianDate+"/n");
    buf.append("Is Leap Year: "+isGregorianLeap+"/n");
    buf.append("Day of Year: "+dayOfYear+"/n");
    buf.append("Day of Week: "+dayOfWeek+"/n");
    buf.append("Chinese Year: "+chineseYear+"/n");
    buf.append("Heavenly Stem: "+((chineseYear-1)%10)+"/n");
    buf.append("Earthly Branch: "+((chineseYear-1)%12)+"/n");
    buf.append("Chinese Month: "+chineseMonth+"/n");
    buf.append("Chinese Date: "+chineseDate+"/n");
    buf.append("Sectional Term: "+sectionalTerm+"/n");
    buf.append("Principle Term: "+principleTerm+"/n");
    return buf.toString();
    }
    public String[] getYearTable() {
    setGregorian(gregorianYear,1,1);
    computeChineseFields();
    computeSolarTerms();
    String[] table = new String[58]; // 6*9 + 4
    table[0] = getTextLine(27, "公历年历:"+gregorianYear);
    table[1] = getTextLine(27, "农历年历:"+(chineseYear+1)
    + " ("+stemNames[(chineseYear+1-1)%10]
    + branchNames[(chineseYear+1-1)%12]
    + " - "+animalNames[(chineseYear+1-1)%12]+"年)");
    int ln = 2;
    String blank = " "
    +" " + " ";
    String[] mLeft = null;
    String[] mRight = null;
    for (int i=1; i<=6; i++) {
    table[ln] = blank;
    ln++;
    mLeft = getMonthTable();
    mRight = getMonthTable();
    for (int j=0; j String line = mLeft[j] + " " + mRight[j];
    table[ln] = line;
    ln++;
    }
    }
    table[ln] = blank;
    ln++;
    table[ln] = getTextLine(0,
    "##/## - 公历日期/农历日期,(*)#月 - (闰)农历月第一天");
    ln++;
    return table;
    }
    public static String getTextLine(int s, String t) {
    String str = " "
    +" " + " ";
    if (t!=null && s str = str.substring(0,s) + t + str.substring(s+t.length());
    return str;
    }
    private static String[] monthNames =
    {"一","二","三","四","五","六","七","八","九","十","十一","十二"};
    public String[] getMonthTable() {
    setGregorian(gregorianYear,gregorianMonth,1);
    computeChineseFields();
    computeSolarTerms();
    String[] table = new String[8];
    String title = null;
    if (gregorianMonth<11) title = " ";
    else title = " ";
    title = title + monthNames[gregorianMonth-1] + "月"
    + " ";
    String header = " 日 一 二 三 四 五 六 ";
    String blank = " ";
    table[0] = title;
    table[1] = header;
    int wk = 2;
    String line = "";
    for (int i=1; i line += " " + ' ';
    }
    int days = daysInGregorianMonth(gregorianYear,gregorianMonth);
    for (int i=gregorianDate; i<=days; i++) {
    line += getDateString() + ' ';
    rollUpOneDay();
    if (dayOfWeek==1) {
    table[wk] = line;
    line = "";
    wk++;
    }
    }
    for (int i=dayOfWeek; i<=7; i++) {
    line += " " + ' ';
    }
    table[wk] = line;
    for (int i=wk+1; i table[i] = blank;
    }
    for (int i=0; i table[i] = table[i].substring(0,table[i].length()-1);
    }

    return table;
    }
    private static String[] chineseMonthNames =
    {"正","二","三","四","五","六","七","八","九","十","冬","腊"};
    private static String[] principleTermNames =
    {"大寒","雨水","春分","谷雨","夏满","夏至","大暑","处暑","秋分",
    "霜降","小雪","冬至"};
    private static String[] sectionalTermNames =
    {"小寒","立春","惊蛰","清明","立夏","芒种","小暑","立秋","白露",
    "寒露","立冬","大雪"};
    public String getDateString() {
    String str = "* / ";
    String gm = String.valueOf(gregorianMonth);
    if (gm.length()==1) gm = ' ' + gm;
    String cm = String.valueOf(Math.abs(chineseMonth));
    if (cm.length()==1) cm = ' ' + cm;
    String gd = String.valueOf(gregorianDate);
    if (gd.length()==1) gd = ' ' + gd;
    String cd = String.valueOf(chineseDate);
    if (cd.length()==1) cd = ' ' + cd;
    if (gregorianDate==sectionalTerm) {
    str = " "+sectionalTermNames[gregorianMonth-1];
    } else if (gregorianDate==principleTerm) {
    str = " "+principleTermNames[gregorianMonth-1];
    } else if (chineseDate==1 && chineseMonth>0) {
    str = " "+chineseMonthNames[chineseMonth-1]+"月";
    } else if (chineseDate==1 && chineseMonth<0) {
    str = "*"+chineseMonthNames[-chineseMonth-1]+"月";
    } else {
    str = gd+'/'+cd;
    }
    return str;
    }
    public int rollUpOneDay() {
    dayOfWeek = dayOfWeek%7 + 1;
    dayOfYear++;
    gregorianDate++;
    int days = daysInGregorianMonth(gregorianYear,gregorianMonth);
    if (gregorianDate>days) {
    gregorianDate = 1;
    gregorianMonth++;
    if (gregorianMonth>12) {
    gregorianMonth = 1;
    gregorianYear++;
    dayOfYear = 1;
    isGregorianLeap = isGregorianLeapYear(gregorianYear);
    }
    sectionalTerm = sectionalTerm(gregorianYear,gregorianMonth);
    principleTerm = principleTerm(gregorianYear,gregorianMonth);
    }
    chineseDate++;
    days = daysInChineseMonth(chineseYear,chineseMonth);
    if (chineseDate>days) {
    chineseDate = 1;
    chineseMonth = nextChineseMonth(chineseYear,chineseMonth);
    if (chineseMonth==1) chineseYear++;
    }
    return 0;
    }
    }
    [/HTML]
    展开全文
  • 以检测和识别为核心各项计算机视觉分析任务,例如行人检测,异常检测,属性识别等,在过去中引起了人们极大兴趣,并且应用到各种场景中。 本比赛主要聚集城市发展管理核心领域,由珠海市香洲区人民政府...

    本文首发于极市平台

    团队介绍

    团队来自深圳市威富视界有限公司、中国科学院半导体研究所,队长为宁欣副研究员,成员分别为石园、刘江宽、支金林、王镇、荣倩倩,排名不分先后。
    在这里插入图片描述
    珠港澳人工智能算法赛题介绍

    以检测和识别为核心的各项计算机视觉分析任务,例如行人检测,异常检测,属性识别等,在过去的几年中引起了人们的极大兴趣,并且应用到各种场景中。

    本比赛主要聚集城市发展管理的核心领域,由珠海市香洲区人民政府为指导单位,珠海市香洲区科技创新促进中心主办, 腾讯云启创新中心(珠海)、深圳极视角科技有限公司承办,暨南大学智能科学与工程学院/人工智能产业学院提供学术支持,极市平台、腾讯云提供技术支持。并且提供了海量数据集和免费算力。

    任务介绍

    赛道1——短袖短裤识别

    这项任务是基于现代化工厂的智能化需求,识别工厂安全隐患在工业安防中已成为典型需求之一。系统对通过短袖短裤识别算法的开发,赋能工厂更好的在监控区域及时警示安全隐患,提升工厂管理效率,减少工厂安全事故发生频率。

    挑战赛的参与者首先需要检测出行人,给出可见身体范围框,然后根据行人着衣情况给出对应的类别信息,其类别为l_sleeve(长袖)、trousers(长裤)、s_sleeve(短袖)、shorts(短裤)、unsure(不确定)其中的一种或多种。数据由摄像头采集完成,训练数据集包含10537张,测试数据集有4517张

    赛道2——小摊贩占道识别

    今年地摊经济对拉动经济发展、增加就业起到了积极促进作用,如何避免"一管就死,一放就乱"现象是当前城市管理非常重要的问题,因此如何有序管理小摊贩摆设成为智慧城管一大需求。本赛题系统通过小摊贩占道识别算法的开发,使得城市管理能更加智能高效,降低城市管理成本,减少城市小摊贩占道情况的发生。

    挑战赛的参与者首先需要检测出占道的小摊贩,给出目标框和对应的类别信息,其类别为vendors。数据由摄像头采集完成,训练数据集包含7592张,测试数据集有3255张。

    评价指标

    本比赛最终得分采用准确度、算法性能绝对值的综合得分形式,具体形式如下:
    在这里插入图片描述
    说明:

    (1) 算法精度的赛道标准值是指本赛道参赛者算法精度值的最高分;算法性能指的赛道标准值是 100 FPS, 如果所得性能值FPS≥赛道标准值FPS,则算法性能值得分=1;

    (2) 本题规定predicted bounding box和ground truth bounding box的IoU(交叉比)作为结果目标匹配的依据,其中IoU值>Threshold且目标类别标签相匹配的目标视为正确结果,其它视为错误,赛道一Threshold为0.7,赛道二中Threshold为0.75;

    (3)获奖评审标准:参赛者需要获得算法精度和算法性能值的成绩,且算法精度≥0.7,算法性能值FPS≥5,才能进入获奖评选;

    威富视界&中国科学院半导体研究所两只团队荣获两项第一

    赛道一:
    在这里插入图片描述
    赛道二:
    在这里插入图片描述
    赛题特点

    图像尺寸不一、近景和远景目标尺度差异大。

    无论是赛道一的数据集还是赛道二的数据集,图片尺寸不一,相差较大。一方面,由于计算资源和算法性能的限制,大尺寸的图像不能作为网络的输入,而单纯将原图像缩放到小图会使得目标丢失大量信息,特别是赛道一中行人。另一方面,图像中近景和远景的目标尺度差异大,对于检测器来说,是个巨大的挑战。

    目标在图像中分布密集,并且遮挡严重

    数据集均是利用摄像头从真实场景采集,部分数据的目标密集度较大。无论是赛道一中的行人还是赛道二中的小摊贩都出现了频繁出现遮挡现象,目标的漏检情况相对严重。

    主要工作

    主体框架选择:

    目前,基于深度学习的目标检测技术包括anchor-based和anchor-free两大类。首先我们先是分析两者的优缺点:

    anchor-based:

    1)优点:加入了先验知识,模型训练相对稳定;密集的anchor box可有效提高召回率,对于小目标检测来说提升非常明显。

    2)缺点:对于多类别目标检测,超参数scale和aspect ratio相对难设计;冗余box非常多,可能会造成正负样本失衡;在进行目标类别分类时,超参IOU阈值需根据任务情况调整。

    anchor-free:

    1)优点:计算量减少;可灵活使用。

    2)缺点:存在正负样本严重不平衡;两个目标中心重叠的情况下,造成语义模糊性;检测结果相对不稳定。

    我们又考虑到比赛任务情况:

    1)短袖短裤识别是行人检测,小摊位占道识别是小摊位检测,都属于单类别检测,目标的scale和aspect ratio都在一定范围之内,属可控因素。

    2)比赛数据中存在很多目标遮挡情况,这有可能会造成目标中心重新,如果采用anchor-free,会造成语义模糊性;

    3)scale和aspect ratio可控,那么超参IOU调整相对简单;

    4)大赛对模型部署没有特殊要求,因此,部署方案相对较多,模型性能有很大改进。

    因此,在anchor-based和anchor-free两者中,我们偏向于选择基于anchor-based的算法。

    众所周知,YOLO系列性能在目标检测算法一直引人瞩目,特别是最近的YOLOv5在速度上更是令人惊讶。从下图可以看出,YOLOv5在模型大小方面选择灵活,训练周期相对较短。另外,在保证速度的同时,模型精度也是可观。因此,我们选用YOLOv5作为baseline,然后依据两个赛道的任务情况在此基础上进行改进。
    在这里插入图片描述

    赛道一 短袖短裤识别

    首先根据训练数据集进行分析,在10537张训练图像中,总共有12个组合类别、15个场景、18304个目标框。存在以下三种情况:

    (1)样本不平衡,12个组合中,仅长袖-长裤组合占总数据的76.45%;
    (2)场景样本不均衡,商场、工厂和街拍等五个场景中占比86.18%;
    (3)多种状态行人,例如重叠、残缺、和占比小且遮挡。

    另外,要权衡检测分类的精度和模型运行的速度,因此我们决定选用检测分类精度较好的目标检测框架,同时使用模型压缩和模型加速方法完成加速。其主体思路为:

    (1) 目标检测框架:基于YOLOv5的one-stage检测框架;
    (2) 模型压缩:基于BN放缩因子修剪主干网络;
    (3) 模型加速:TensorRT封装部署。

    根据上述问题,采取以下策略:

    (1) 预训练模型
    本地从WiderPerson和COCO公开数据集中挑选并标注3000张行人数据,约1万个正样本(涵盖了商场、街拍、工厂等场景),以该数据集训练的模型作为预训练模型,一方面可加快平台上模型训练,另一方面可提高精度。

    (2) 数增强策略
    使用albumentations完成数据增强,例如裁剪拼接、翻转等。
    在这里插入图片描述
    (3) 网络框架设计
    起初,我们将分类分为12类,即不确定-短裤、不确定-长裤、长袖-不确定、长袖-长裤、长袖-短裤、短袖-不确定、短袖-短裤、长裤、短裤、长袖、短袖。但是模型效果不佳,召回率较低。我们就思考,若将数据先分为两大类,即上衣和下衣,然后再分别将这两类分为四类,即上衣分为长袖、短袖、不确定、无;下衣分为长裤、短裤、不确定、无。从理论层面分析,上述方法可有效改善数据失衡问题,提高模型的召回率。

    于是,我们就在网络的分类层做了实验,尝试了这两种不同策略的分类情况,通过实验证实8类别分类器确实优于12类别分类器,其原因在于8分类场景下训练样本的类别分布更优。
    在这里插入图片描述
    从表中可以看出12个类别中前3个类别占比太高,如果直接使用12类别分类器训练,模型会被引导至更利于检测长袖-长裤、短袖-长裤、短袖短裤等占比较多地类别上,对于剩余的占比较低的类别检出率会很低,最终导致模型测试的召回率很不理想。但是在8类别的分类器上,将前4个用于分类上衣,后4个值用于分类下衣,这样就会改善样本占比较少的类别的劣势。举例来说,长袖-长裤的样本占比较高,会引导模型更好地检出长裤,短袖-短裤样本同样会引导模型更好地检出短裤,短裤的特征参数和长袖的特征参数已经通过两个样本较多的类别训练完成,对于样本数量较少的长袖-短裤样本依旧会有较好的检出率。

    上述两种方案的网络结构图如下:
    在这里插入图片描述
    在这里插入图片描述
    上述是两种分类方式,最终选用的是基于上衣和下衣的8分类方式,具体好处改善样本不均衡带来的分类偏差,从而提高召回率。

    (4) 模型加速

    由于大赛对模型部署没有特殊要求,按照我们以往的经验,我们优先了一下两种方式:1)剪枝加速策略,模型可提高1.3倍左右;2) TensorRT加速策略,模型可提高约为1.3倍。两者可同时使用。

    剪枝加速:

    在许多现实应用中,深度神经网络的部署由于其高额的计算成本变得很困难。Slimming利用通道稀疏化的方法可以达到1)减少模型大小;2)减少运行时内存占用;3)在不影响精度的同时,降低计算操作数。

    Slimming主要原理:

    1)利用batch_norm中的缩放因子γ作为重要因子,即γ越小,所对应的通道不太重要,就可剪枝;
    2)为约束γ的大小,在目标方程中增加一个关于γ的正则项,这样可以做到在训练中自动剪枝,而以往模型压缩不具备。
    在这里插入图片描述
    在这里插入图片描述
    TensorRT加速:

    相对于python部署模型,c++封装部署模型速度更快。目标检测任务相对人脸识别这种任务特征精度要求相对较低,所以在确保精度相对不变的情况下,采用FP16比FP32速度可提升1.5倍左右。另外,TensorRT是一个高性能的深度学习推理优化器,可以为深度学习应用提供低延迟、高吞吐的部署推理。大赛对于模型部署没有特殊要求,因此我们选用了TensorRT进行部署模型。下图是python与TensorRT的模型部署的对比结果。
    在这里插入图片描述

    测试方案

    通过实验发现街拍和商场数据的H:W=2:1的图像,使用输入大小为480的模型检测率更优,对于H:W=1:2的图像,使用输入大小为640的模型检测率更优。因此在测试时使用双模型检测,分析输入图像的尺寸择优选择模型完成预测。
    在这里插入图片描述
    实验结果
    在这里插入图片描述注:NMS阈值为0.5,正样本阈值为0.5

    赛道二 小摊贩占道识别

    和赛道一短袖短裤识别一样,小摊贩占道识别也属于目标检测任务。这里仅分析不同之处,相同技术参考赛道一。

    起初考虑到算法性能因素,我们首先尝试YOLOv5s进行模型训练。经实验结果显示,模型预测存在大量的误检和漏检。这些漏检和无意义的检测结果大幅降低了模型的性能。我们将上述问题归纳为以下两个方面的原因:

    1、YOLOv5s无论是网络宽度和网络深度都较小,学习能力相对较弱。小摊位占道和其他正常车辆十分相似,容易对分类器造成混淆,从而产生误检;

    2、训练和测试时输入模型的图像尺度不合适。图像经过缩放后,目标的尺度也随之变小,导致远景中人的小摊贩等区域被大量遗漏;

    根据上述问题,我们进行了一些尝试。

    首先,从图像预处理方面,使用随机中心裁剪方式切图进行训练。随机窗口切图是一种常用的大图像处理方式,这样可以有效地保留图像的高分辨率信息,不同大小的目标,另一方面采用多尺度训练,这样使得网络获得的信息更加丰富。如果某个目标处于切图边界,根据目标框的与图片的大小比例来决定是否保留。另外,我们还采用了随机几何变换、颜色扰动、翻转、多尺度、mixup、GridMask、Mosaic等数据增广方式,都可提高模型的泛化能力和小目标检测率。

    其次,从优化器层面来讲,我们尝试了优化器梯度归一化和SAM优化器。优化器梯度归一化有三个好处:
    (1)加速收敛;(2)防止梯度爆炸;(3)防止过拟合;
    在这里插入图片描述
    SAM优化器[4]可使损失值和损失锐度同时最小化,并可以改善各种基准数据集(例如CIFAR-f10、100g,ImageNet,微调任务)和模型的模型泛化能力,从而产生了多种最新性能。另外, SAM优化器具有固有的鲁棒性。
    经实验对比,模型进行优化器梯度归一化和采用SAM优化器,约有0.003点的提升。
    在这里插入图片描述
    最后,在网络大小选择方面,由于我们可采用c++、tensorRT部署,所以我们可选择相对较大的网络,即YOLOv5m。这样可以模型的学习能力会增强。部署时不同方案的性能对比情况如下:
    在这里插入图片描述
    测试方案

    通过测试发现,3255张测试集中10801920尺寸的图像与其他尺寸的图像比例约为7:3。于是我们TensorRT部署时,模型使用输入大小为384640比640640检测率更优。因为10801920直接resize为640*640,一方面会到值目标变形,另一面,目标变得更小。另外,使用TensrRT推理时,构造函数中采用warmup,提高算法性能指标。注:由于时间关系该赛道仅使用了TensorRT,没有采用slimming剪枝加速。

    实验结果:
    在这里插入图片描述注:NMS阈值为0.5,正样本阈值为0.5

    讨论与总结

    本文针对2020首届珠港澳人工智能算法大赛两个赛道任务进行了总结与归纳。相关结论可以归纳为以下几点:

    1、 数据分析对于训练模型至关重要。数据不平衡、图像尺寸和目标大小不一、目标密集和遮挡等问题,应选用对应的baseline和应对策略。例如,数据不平衡可尝试过采样、focal loss、数据增强等策略;图像尺寸和目标大小不一可采用多尺度、数据裁剪等方法。

    2、 针对算法精度和性能两者取舍来说,可先实验网络大小和输入图片大小对模型结果的影响,不同任务和不同数据情况,两者相差较大。所以不能一味为了提高速度,单纯压缩网络大小;

    3、 针对性能要求时,可采用TensorRT等方式部署模型,也可采用模型压缩等方式,这样可在保证速度的前提下,使用较大网络,提升模型精度。

    参考文献

    1. Zhuang L, Li J, Shen Z, et al. Learning Efficient Convolutional Networks through Network Slimming[ 2017]2. https://github.com/ultralytics/yolov5.git3. http://www.cbsr.ia.ac.cn/users/sfzhang/WiderPerson/4. https://cocodataset.org/5. Pierre F, Ariel K, Hossein M, Behnam N; Sharpness-Aware Minimization for Efficiently Improving Generalization[2020]
    展开全文
  • 沈阳工业大学电气工程学院研究人员文帅、蔡志远,在2019第15期《电工技术学报》上撰文指出,断路器同步分断可以有效地提高断路器分断能力和减小触头电弧磨损,是智能电器领域发展方向之一。为实现断路器同步...

    沈阳工业大学电气工程学院的研究人员荣文帅、蔡志远,在2019年第15期《电工技术学报》上撰文指出,断路器同步分断可以有效地提高断路器分断能力和减小触头电弧磨损,是智能电器领域的发展方向之一。为实现断路器同步分断,需要对实测短路电流进行波形分解和重建,以预测短路电流过零点。

    该文对目前应用较广的最小二乘参数辨识和改进快速傅里叶变换两种零点预测算法进行了理论分析,建立了单相短路电流仿真模型,给含有直流衰减分量和谐波分量的短路电流信号添加不同信噪比的高斯白噪声,对含有噪声的信号进行了量化处理,模拟电网频率波动,得到了同步采样和非同步采样下短路电流离散时间序列,分别用两种算法对短路电流过零点进行了预测。此外,搭建了短路电流实测平台,对实测短路电流进行了波形分析和零点预测。

    对理论和实测短路电流进行零点预测的结果表明:理想状态下改进快速傅里叶算法的预测精度优于最小二乘参数辨识,但对数字化测量系统的信噪比、模数转换的有效位数和电网频率的稳定性等要求较高;最小二乘参数辨识算法对噪声和扰动等的耐受能力高于改进快速傅里叶算法。

    9c36b8f93607f1fa6521ca31a49b447c.png

    断路器作为整个供电系统中的重要设备,其可靠性是电力系统安全运行的保证。因此,提高断路器分断操作的智能化水平,对电网安全运行具有重要意义。断路器在开断短路电流的过程中,存在暂态变化过程,短路电流中存在随时间衰减的非周期分量,且非周期衰减分量随机不确定,这给精确预测短路电流过零点增加了难度。如何快速计算短路电流的特征参数以预测其过零点是断路器可控开断短路电流必须解决的首要问题。

    断路器相控分断短路电流的基本原理是:采用数字信号处理算法对短路电流离散采样数据进行分析,估算短路电流的特征参数,预测短路电流过零点,以提前发出控制指令。

    • 针对短路电流零点预测,有学者采用改进半波傅里叶算法,依靠半个周波加两个采样点的数据窗口预测短路电流的过零点,计算精度达到 1ms。
    • 有学者采用一种基于最小二乘法发展出来的WLMS算法,对电流参数进行估计,可以在10ms内实现短路电流过零点的预测,预测误差在 1ms以内。
    • 有学者对安全点算法、自适应算法及改进半波傅里叶算法进行对比,得出自适应算法适用于不含谐波分量情况下,当存在谐波分量,自适应算法并不适用,当谐波分量中存在偶次谐波,改进半波傅里叶算法不适用。
    • 有学者采用改进快速傅里叶算法,通过对短路电流分解计算,数字处理只需要6个采样数据,但未对存在谐波分量情况进行分析。

    综上所述,现有的短路电流零点预测方法都是采用数字算法加以实现。但是,为将实际连续变化的短路电流转换成可供分析的数字信号,需要采用电流互感器和模拟放大电路对短路电流信号进行变换和调理,需要采用模数转换器将调理后的电信号转换成离散时间序列,这样才能运用数字信号处理算法对离散短路电流时间序列进行分析,预测出短路电流过零点,适时发出控制指令,使断路器触头在短路电流过零附近分断。因此,短路电流零点预测的实现不仅与所运用的数字信号分析算法有关,还受诸多因素限制,包括模拟测量环节的信噪比、模数转换的有效位数和被控电力线路的频率稳定性等。

    本文介绍了短路电流同步分断零点预测原理,建立了单相短路电流仿真模型,搭建了短路电流实验平台;运用最小二乘参数辨识和改进快速傅里叶算法对含暂态分量和谐波分量的短路电流进行分解和重建,预测短路电流过零点;并从采样精度、噪声干扰、电网频率偏移、谐波分量等几个方面对两种算法的优缺点和适用性进行了对比和实验验证。

    887804c9e435855a698c3a3a87d7dfee.png

    图7 实际短路电流测试平台

    总结

    为实现短路电流零点预测技术,从测量电路信噪比、模数转换有效位数、电网频率偏移、谐波分量和暂态分量影响等方面对最小二乘参数辨识和改进快速傅里叶算法二种短路电流零点预测算法进行了对比,并对实测数据进行了分析。

    • 1)理想状态下,无论是否含有谐波分量,改进快速傅里叶算法精度均优于最小二乘参数辨识。
    • 2)在添加高斯白噪声情况下,最小二乘参数辨识的耐受能力为20dB,改进快速傅里叶算法的耐受能力为90dB;在电网频率偏移干扰情况下,两种算法的抗扰能力基本相同;改进快速傅里叶算法对短路电流数字化测量系统模数转换精度有较高的要求。
    • 3)最小二乘参数辨识在适用性方面高于改进快速傅里叶算法,但在噪声较低的情况下,可以选择改进快速傅里叶算法。
    展开全文
  • Update:0.12 2011-9-5- 修复一个当使用农历正月日期初始化日历时陷入死循环问题。Update:0.11 2009-12-27- 修复了获取中文农历时未计算农历日期问题...从和笔记找到农历算法,用Calendar封装了一下。从Greg...
  • 图像形态学大部分通过集合思想实现,(特点,处理速度快,算法思路清晰)基本思想:用具有一定形态结构元素去度量和提取图像中对应元素数学形态学是由法国矿业学院博士生赛拉和导师马瑟于1964提出来通过...
  • 数学形态学是由法国矿业学院博士生赛拉和导师马瑟于1964提出来 通过腐蚀处理可以将目标图像收缩,而通过膨胀处理可以将图像扩展, 利用收缩和扩展后图像,借助适当变换,可以比较精确提取原图像内外...
  • 对计算机科学反思

    2015-01-12 22:31:06
    从第1台电子计算机问世到现在已经60了,尽管计算机科学和技术继续保持高速发展态势,但是计算机科学与技术不能再采用以往一样方式发展,需要革命性突破。如果一直顺着过去形成惯性发展,计算机科学路子...
  • 搞IT到底怎么了

    2011-09-08 21:01:00
    前大概,每一个人都以IT为,可是十今天,IT几乎成了一个略带侮辱性词汇。老婆QQ截图给我看: 看了以后,思考良久...高度数眼镜,呆滞,满脸痘痘,卷发(统计意义)...这是IT人; 挤车,一身臭...
  • 搞IT到底怎么了 . .

    2011-09-12 16:18:00
    前大概,每一个人都以IT为,可是十今天,IT几乎成了一个略带侮辱性词汇。朋友QQ截图给我看: 看了以后,思考良久...高度数眼镜,呆滞,满脸痘痘,卷发(统计意义)...这是IT人; 挤车,一身臭汗...
  • 搞IT到底怎么了——笑死我了

    千次阅读 2011-11-24 13:43:23
    前大概,每一个人都以IT为,可是十今天,IT几乎成了一个略带侮辱性词汇。老婆QQ截图给我看: 看了以后,思考良久... 高度数眼镜,呆滞,满脸痘痘,卷发(统计意义)...这是IT人; 挤...
  • 由于双摄技术快速发展,目前已经衍生出了几种不同双摄硬件和算法配置解决方案。...比如,华为2014底推出第一款双摄手机是荣耀6plus,后置两个相同彩色相机平行排列,2016推出年度旗舰产品...
  • 手机双摄像头原理

    千次阅读 2018-08-17 11:45:54
    由于双摄技术快速发展,目前已经衍生出了几种不同双摄硬件和算法配置解决方案。...比如,华为2014底推出第一款双摄手机是荣耀6plus,后置两个相同彩色相机平行排列,2016推出年度旗舰产品...
  • 转载一篇IT日志

    2019-07-26 16:06:22
    前大概,每一个人都以IT为,可是十今天,IT几乎成了一个略带侮辱性词汇。老婆QQ截图给我看: 看了以后,思考良久...高度数眼镜,呆滞,满脸痘痘,卷发(统计意义)...这是IT人;挤车,一身臭...
  • 第一次3-1

    2016-03-10 09:46:59
    c++程序编写和运行 掌握简单c++程序编写 /*  * 文件名称:7893-1  * 作 者: 岑  * 完成日期:2016 3 月 10 日  * 版 本 号:v1.0  ...* 对任务及求解方法描述部分: ...* 算法设计: a-b
  • 第七次上机实验

    2016-06-06 01:52:38
    * 作 者: 岑 * 完成日期: 2016 6 月 6 日 * 版 本 号:v1.0 * 对任务及求解方法描述部分:利用自定义函数实现求最大公约数和最小公倍数。 * 输入描述: 无; * 问题描述: 无; * 程序输出: 无; ...
  • 沈志斌19569月8日生于南京,197412月入伍。...汉语编程基础构想和基础算法及其基本功能验证, 便始于此。 1995沈志斌离开部队后, 曾分别就职于航天工业部和信息产业部, 后到国家汉语编程研究院和北京国之经

空空如也

空空如也

1 2
收藏数 28
精华内容 11
关键字:

荣年的算法