Skip to content

Commit

Permalink
Avoid double-loop and branching for leap years
Browse files Browse the repository at this point in the history
This avoids the variable-length array issue n #429. The previous
implementation uses 'leap' to:

    * Run a full 'nyear' loop to populate whether each year is leap.
    * Run a second loop to count the number of days from the array
      (the branch prediction in each iteration will be wrong about
      half the time).

Count the number of days directly in one loop. This is slightly more
memory-efficient and should be more computationally efficient too.

Closes #430. See #429.
  • Loading branch information
MichaelChirico authored Nov 15, 2024
1 parent ae39d2b commit bfec4d1
Showing 1 changed file with 7 additions and 13 deletions.
20 changes: 7 additions & 13 deletions src/startofyear.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,27 +36,21 @@ SEXP do_startofyear (SEXP _from, SEXP _to, SEXP _origin)
int *fromto = INTEGER(_fromto);

int nyear[1] = { (to - from + 1) };
int leap[nyear[0]];


// generate sequence of dates to work with
fromto[0] = from;
for(i=1; i < nyear[0]; i++) {
fromto[i] = fromto[i-1] + 1;
}

for(i = 0; i < nyear[0]; i++) {
leap[ i ] = ( (fromto[ i ] % 4 == 0 && fromto[ i ] % 100 != 0)
||
fromto[ i ] % 400 == 0) ? 1 : 0;
}

for(i=0; i < nyear[0]; i++) {
if(leap[i] == 1) { // a leapyear (366 days)
fromto[i] = 366;
} else { // a non-leapyear (365 days)
fromto[i] = 365;
}
// A leap year is every year divisible by 4 _except_
// years also divisible by 100. Leap centuries,
// those divisible by 400, also get 366 days.
int leap = ( (fromto[ i ] % 4 == 0 && fromto[ i ] % 100 != 0)
||
fromto[ i ] % 400 == 0) ? 1 : 0;
fromto[i] = 365 + leap;
}

/*
Expand Down

0 comments on commit bfec4d1

Please sign in to comment.