--- caldefs.h-orig 2004-10-09 12:32:32.851897696 -0700 +++ caldefs.h 2004-10-09 13:33:18.500674840 -0700 @@ -51,22 +51,77 @@ #define TM_YEAR_BASE 1900 #endif /* !defined TM_YEAR_BASE */ -#ifndef isleap -#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) -#endif /* !defined isleap */ #ifndef isleap_sum /* -** Since everything in isleap is modulo 400 (or a factor of 400), we know that -** isleap(y) == isleap(y % 400) -** and so -** isleap(a + b) == isleap((a + b) % 400) -** or -** isleap(a + b) == isleap(a % 400 + b % 400) -** This is true even if % means modulo rather than Fortran remainder -** (which is allowed by C89 but not C99). -** We use this to avoid addition overflow problems. +** Predicate determining if the year (a+b) is a leap-year on the +** proleptic Gregorian calendar. We pass in seperate arguments a +** and b instead of a single y=a+b value in order to avoid potential +** overflow problems with the addition. +** +** The leap year rule used by the calendar that the C time API +** implements was defined in Pope Gregory XIII's Papal Bull of February +** 24, 1582. The clause most relevant to our task is: +** 9. Deinde, ne in posterum a XII kalendas aprilis aequinoctium +** recedat, statuimus bissextum quarto quoque anno (uti mos est) +** continuari debere, praeterquam in centesimis annis; qui, quamvis +** bissextiles antea semper fuerint, qualem etiam esse volumus +** annum MDC, post eum tamen qui deinceps consequentur centesimi +** non omnes bissextiles sint, sed in quadringentis quibusque annis +** primi quique tres centesimi sine bissexto transigantur, quartus +** vero quisque centesimus bissextilis sit, ita ut annus MDCC, +** MDCCC, MDCCCC bissextiles non sint. Anno vero MM, more consueto +** dies bissextus intercaletur, februario dies XXIX continente, +** idemque ordo intermittendi intercalandique bissextum diem in +** quadringentis quibusque annis perpetuo conservetur. +** +** One reasonable translation into modern-day English is: +** 9. Then, lest the equinox recede from XII calends April +** [March 21st] in the future, we establish that a bissextile +** [intercalation day] shall be inserted every four years (as with +** the present custom), except in centennial years. Those, although +** they were always bissextile until now, will not be from now on, +** although we decree that year 1600 is still bissextile; after +** that, however, those centennial years that follow are not all +** bissextile, but the first year is, and then three centennial +** years have no bissextile [intercallation] performed, and, then, +** the fourth centennial year is indeed bissextile. Thus, the years +** 1700, 1800 and 1900 will not be bissextile, and then, as with +** the habit with which we are now accustomed, the year 2000 will +** have a bissextile intercalation day, as the day February 29, +** and that the same order of intermittent bissextile intercalations +** in each four hundred year period will be preserved in perpetuity. + +** Or, using a more mathematical formulation, and interpolating for +** what qualified as "uti mos est (as with the present custom)": +** A leap day is inserted in years which are divisible by 4 (with +** zero remainder), *except* that years whose value is exactly +** divisible by 100 are only leap years when the year's value is +** also exactly divisible by 400. +** +** +** In order to avoid heavy use of the comparatively expensive % operator, +** the code below makes use of the following observations: +** 1. A year is divisible by 4 if its low-order two bits are both +** zero; +** 2. If the low-order four bits of a year are all zero, then +** it doesn't matter if the year is divisible by 100, +** because lcm(16,100) is 400; +** 3. To make the above two statments formally true in C, we need +** to ensure that the arguments are cast to unsigned values; +** 4. Since we only care the values of (low-order) bits, +** the possibilty that the addition of the two unsigned +** values might "overflow" is not a problem; +** 5. (a+b)%100 == 0 if and only if ((a%100)+(b%100))%100 == 0. +** */ -#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400) +#define isleap_sum(a, b) ( 0 == (3 & (unsigned int)(a)+(unsigned int)(b)) && \ + ( 0 == (0xf & (unsigned int)(a)+(unsigned int)(b)) \ + || 0 != ((a)%100+(b)%100)%100 ) ) + #endif /* !defined isleap_sum */ + +#ifndef isleap +#define isleap(y) isleap_sum(y, 0) +#endif /* !defined isleap */