-9

Is there any shorter logic than this to achieve leap year test with fewer conditions?

#include <stdio.h>

int isleap(int year) {
    return (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0));
}

int main() {
    for (int year = 1600; year <= 2020; year++) {
        printf("%d: %s\n", year, isleap(year) ? "Leap Year" : "Not a Leap Year");
    }
    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
roh.it
  • 23
  • 1
  • 7
  • 6
    I guess "asap" is a regional form of "please"? – M Oehm Mar 30 '20 at 06:02
  • Can you clarify what you mean by 'shorter logic'? – rtx13 Mar 30 '20 at 06:09
  • Less condition to achieve rhe result – roh.it Mar 30 '20 at 06:09
  • 1
    The question may seem ridiculous, but is legitimate: a simpler expression would be useful. – chqrlie Mar 30 '20 at 06:31
  • @roh.it: I am sorry your question got such a rough treatment. I shall rephrase it to make it more acceptable. Both answers provide valuable insight IMHO. – chqrlie Mar 30 '20 at 15:52
  • @chqrlieforyellowblockquotes: While legitimate, the question is direct duplicate to https://stackoverflow.com/questions/3220163/how-to-find-leap-year-programmatically-in-c. which is easily googled. Not sure that the question is needed to be re-opened from "too broad" for being immediately closed as a duplicate. – Tsyvarev Mar 30 '20 at 16:16
  • @Tsyvarev: I'm afraid I don't agree: the question is not a duplicate of that one: the OP is not asking how to test for leap years, he provides working code, but if there is a more efficient test than the commonly accepted one. The duplicate you refer to does not fully address this and even *Cassio Neri*'s detailed answer does not benchmark my proposed solutions with lookup tables. There is always something to learn from the most mundane questions. – chqrlie Mar 30 '20 at 16:32
  • @chqrlieforyellowblockquotes: without **exact** definition of "efficient" given question is just a collecting of **possible ways**. "even Cassio Neri's detailed answer does not benchmark my proposed solutions with lookup tables." - You may add your answer with the table to the duplicate question as well. So all possible ways will be in a single bucket. – Tsyvarev Mar 30 '20 at 17:15
  • @Tsyvarev: I wrote *more efficient*, my bad, but the OP was only inquiring about fewer conditions... I am posting my findings as an answer to the question in reference: https://stackoverflow.com/questions/3220163/how-to-find-leap-year-programmatically-in-c – chqrlie Mar 30 '20 at 17:35
  • @roh.it: your question has been closed, but you can still accept one of the answers by clicking on the grey checkmark below its score. – chqrlie Mar 30 '20 at 19:59

2 Answers2

3

There is a way to have just a single expression without a test, using a 400 byte array:

static unsigned char const leaptest[400] = {
    1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,
    0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,
    0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,
    0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,
    0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,
    0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,
    0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,
    0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,
    0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,
    0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,
    0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,
    0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,
    0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,
    0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,
    0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,
    0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,
};
int isleap(unsigned year) {
    return leaptest[year % 400];
}

Here is a more complex expression without tests, using a smaller array:

#include <stdio.h>

static unsigned char const leaptest[50] = {
    0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
    0x11, 0x11, 0x01, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
    0x11, 0x11, 0x11, 0x11, 0x11, 0x10, 0x11, 0x11, 0x11, 0x11,
    0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x01, 0x11, 0x11,
    0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
};
int isleap(unsigned y) {
    return (leaptest[(y >> 3) % 50] >> (y & 7)) & 1;
}

int main() {
    for (int y = 1600; y <= 2000; y++) {
        printf("%d: %s\n", y, isleap(y) ? "leap" : "");
    }
    return 0;
}

Finally, here is a simple solution that compiles to branchless code:

int isleap(unsigned y) {
    return !(y % 100 ? y % 4 : y % 16);
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
1

If we stick to your current algorithm, you can reduce average number of comparisons.

Most years are not divisible by 4, and thus cannot be a leap year. But with your current expression

((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)

there are 2 comparisons: (year % 4 == 0) and (year % 400 == 0).

If you rearrange comparisons

(year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0))

you'll do only one comparison for the most common case.

user694733
  • 15,208
  • 2
  • 42
  • 68