Velocity Reviews > A better algorithm to calculate a leap year?

# A better algorithm to calculate a leap year?

Guest
Posts: n/a

 11-06-2007
Richard Heathfield wrote:

[Q: To leap or not to leap?]

> Here's a better method:
>
> int really_is_leap(int year)
> {
> return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
> }
>
> This one has the merit of actually giving the right results.

The Gregorian Calendar is not used everywhere in the world, even in the
Catholic countries, it was not used before

assert(year > 1582);

The Protestantic countries was far more skeptical, and didn't like to be
dictated by the Pope. Anyway, Germany, Switzerland and Denmark-Norway
finally followed in

assert(year > 1700);

As usual, the Brits was slow (btw they might switch to euro some day!),
so for the British Empire we have

assert(year > 1752);

at least you beat Sweden/Finland to it by a year. However, the
Swedes did this their own way, and instead of loosing many days at once,
they dropped 10+ leap years afterwards.

etc. etc.

> Test your function, and see how it works on years that you know to be leap
> years (eg 1976, 2000, 2004, 200 and years you know not to be leap years
> (2001, 2002, 2003, 2005).
>
> Then switch to a working algorithm.

As an example to us all, in 1983, Stanley Rabinowitz made this
*masterpiece* of a maintainer response to a VAX/VMS leap-year bug report:

http://rudy.ca/lycomplaint.html

--
Tor <(E-Mail Removed) | tr i-za-h a-z>

Jean-Marc Bourguet
Guest
Posts: n/a

 11-06-2007
Rob Kendrick <(E-Mail Removed)> writes:

> On Mon, 05 Nov 2007 21:55:58 +0000, Christopher Benson-Manica wrote:
>
> > [comp.lang.c] Richard Heathfield <(E-Mail Removed)> wrote:
> >
> >> int really_is_leap(int year)
> >> {
> >> return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
> >> }

> >
> >> This one has the merit of actually giving the right results.

> >
> > How about for year 0?

>
> There wasn't a year 0. The year after 1 BC was 1 AD.

There is a year 0 in the Gregorian calendar, but few people use it for
dates before its first adoption. There is no year 0 in the "Julian"
calendar which is more commonly used for giving date at this period even if
it wasn't in use with that origin. I seem to remember that taking into
account leap years as observed in that period is funny, you need to get a
table because the rules where not followed.

See http://emr.cs.iit.edu/home/reingold/...econd-edition/.
This reference could also of use for the OP.

A+

--
Jean-Marc

Dik T. Winter
Guest
Posts: n/a

 11-06-2007
In article <(E-Mail Removed) om> John Bode <(E-Mail Removed)> writes:
> On Nov 5, 12:30 pm, (E-Mail Removed) wrote:
> > Code:
> > int is_leap(int year)
> > {
> > switch (year % 19) {
> > case 0: case 3: case 6: case 8:
> > case 11: case 14: case 17: return 1;
> > default: return 0;
> > }
> >
> > }
> >
> > This is part of a calendar program.

>
> Try this:
>
> return (year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0));
>
> I think that's the correct formula (evenly divisible by 400, or evenly
> divisible by 4 and not evenly divisible by 100).

Depends on the calendar you are using. The %4 rule etc. is valid for the
Gregorian calendar. I think the %19 rule above is valid for the Muslim
calendar.
--
dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/

gw7rib@aol.com
Guest
Posts: n/a

 11-06-2007
On 5 Nov, 21:55, Christopher Benson-Manica
<(E-Mail Removed)> wrote:
> [comp.lang.c] Richard Heathfield <(E-Mail Removed)> wrote:
>
> > int really_is_leap(int year)
> > {
> > return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
> > }
> > This one has the merit of actually giving the right results.

>
> How about for year 0?

Strangely enough, a couple of my programs use 0 as a wildcard, ie
meaning any year, and in those cases I want the number of days in
February to be returned as 29, because some years do have 29 days in
February. So the above formula can be used without a special
modification.

Paul.

Nick Keighley
Guest
Posts: n/a

 11-06-2007
On 6 Nov, 00:58, Tor Rustad <(E-Mail Removed)> wrote:

> The Gregorian Calendar is not used everywhere in the world, even in the
> Catholic countries, it was not used before
>
> assert(year > 1582);
>
> The Protestantic countries was far more skeptical, and didn't like to be
> dictated by the Pope. Anyway, Germany, Switzerland and Denmark-Norway
> finally followed in
>
> assert(year > 1700);
>
> As usual, the Brits was slow (btw they might switch to euro some day!),
> so for the British Empire we have
>
> assert(year > 1752);
>
> at least you beat Sweden/Finland to it by a year. However, the
> Swedes did this their own way, and instead of loosing many days at once,
> they dropped 10+ leap years afterwards.
>
> etc. etc.

I believe the Russians didn't change until 1917

--
Nick Keighley

Dik T. Winter
Guest
Posts: n/a

 11-06-2007
In article <(E-Mail Removed) .com> Nick Keighley <(E-Mail Removed)> writes:
> On 6 Nov, 00:58, Tor Rustad <(E-Mail Removed)> wrote:

....
> > at least you beat Sweden/Finland to it by a year. However, the
> > Swedes did this their own way, and instead of loosing many days at once,
> > they dropped 10+ leap years afterwards.

This is not entirely correct. They wanted to do that but failed to do it
after the first dropping. This was corrected in 1712 by adding a 30rd of
February, when they came back again to the Julian calendar.

> I believe the Russians didn't change until 1917

And in Greece it was only adopted in 1923.
--
dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/

Barry Schwarz
Guest
Posts: n/a

 11-06-2007
On Mon, 05 Nov 2007 11:10:45 -0800, http://www.velocityreviews.com/forums/(E-Mail Removed) wrote:

>On Nov 5, 1:30 pm, (E-Mail Removed) wrote:
>> I'm new here, so excuse me if my style is incorrect. Can anyone come
>> up with a better method for this calculation?

>
>Sorry, should have noted. This is to generate a Jewish calendar (This
>is the year 5768, and therefore a leap year with an extra month thrown
>in mid-March to mid-April, which is why Easter is 3 weeks later this

It may explain why Passover is three weeks later (actually less than
2.5) but it has nothing to do with Easter.

>year than it was last year). The numbers in the code are correct. I
>was wondering if there was any better algorithm. Thanks to all who
>responded, and apologies for the misunderstanding.
>
> -- Marty (a newbie, starting off on the wrong foot)
>

Remove del for email

Barry Schwarz
Guest
Posts: n/a

 11-07-2007
On Mon, 05 Nov 2007 12:17:33 -0800, user923005 <(E-Mail Removed)>
wrote:

>OK, if people want to test this for themselves it looks like the code
>should be more robust in terms of "clever" optimisers. Try the
>following
>which sums and prints the number of leap years found:
>***/
>#include <stdio.h>
>#include <time.h>
>#define START_YEAR 1582
>#define END_YEAR 4000
>#define ITERATIONS 100000
>
>typedef unsigned (*leap_func)(unsigned);
>
>static unsigned is_a_leap_year1(unsigned y)
>{
> return (y % 400u == 0u) ? 1 : (y % 100u == 0u) ? 0u : (y % 4u ==
>0u);

Two of the three possible return values are signed and 1 is unsigned.
Did you have something special in mind when you specified the u after
the second "?" and not for any of the other return values?

>}

Remove del for email

user923005
Guest
Posts: n/a

 11-07-2007
On Nov 6, 4:21 pm, Barry Schwarz <(E-Mail Removed)> wrote:
> On Mon, 05 Nov 2007 12:17:33 -0800, user923005 <(E-Mail Removed)>
> wrote:
>
>
>
>
>
> >OK, if people want to test this for themselves it looks like the code
> >should be more robust in terms of "clever" optimisers. Try the
> >following
> >which sums and prints the number of leap years found:
> >***/
> >#include <stdio.h>
> >#include <time.h>
> >#define START_YEAR 1582
> >#define END_YEAR 4000
> >#define ITERATIONS 100000

>
> >typedef unsigned (*leap_func)(unsigned);

>
> >static unsigned is_a_leap_year1(unsigned y)
> >{
> > return (y % 400u == 0u) ? 1 : (y % 100u == 0u) ? 0u : (y % 4u ==
> >0u);

>
> Two of the three possible return values are signed and 1 is unsigned.
> Did you have something special in mind when you specified the u after
> the second "?" and not for any of the other return values?
>
> >}

Error on my part. I converted some old code that had signed int for
all data types.
Since Gregorian dates never have negative years, I changed to
unsigned.
My intention was to change all elements of the calculations to
unsigned type to avoid any conversion costs.
I forgot a couple in that function.

James Kuyper
Guest
Posts: n/a

 11-07-2007
user923005 wrote:
....
> Since Gregorian dates never have negative years, I changed to
> unsigned.

The traditional proleptic Gregorian calendar uses positive year numbers
and "BC", but the proleptic Gregorian calendar used in ISO 8601 assigns
a year number of 0 to 1BC, and negative year numbers to earlier dates.
It's up to you whether you want to support this, but ISO 8601 is, as
it's name implies, an International Standard. If you want to support the
traditional proleptic calendar, you should provide some way of
indicating BC dates.