Skip to content

Commit bfec4d1

Browse files
Avoid double-loop and branching for leap years
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.
1 parent ae39d2b commit bfec4d1

File tree

1 file changed

+7
-13
lines changed

1 file changed

+7
-13
lines changed

src/startofyear.c

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,27 +36,21 @@ SEXP do_startofyear (SEXP _from, SEXP _to, SEXP _origin)
3636
int *fromto = INTEGER(_fromto);
3737

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

4240
// generate sequence of dates to work with
4341
fromto[0] = from;
4442
for(i=1; i < nyear[0]; i++) {
4543
fromto[i] = fromto[i-1] + 1;
46-
}
47-
48-
for(i = 0; i < nyear[0]; i++) {
49-
leap[ i ] = ( (fromto[ i ] % 4 == 0 && fromto[ i ] % 100 != 0)
50-
||
51-
fromto[ i ] % 400 == 0) ? 1 : 0;
5244
}
5345

5446
for(i=0; i < nyear[0]; i++) {
55-
if(leap[i] == 1) { // a leapyear (366 days)
56-
fromto[i] = 366;
57-
} else { // a non-leapyear (365 days)
58-
fromto[i] = 365;
59-
}
47+
// A leap year is every year divisible by 4 _except_
48+
// years also divisible by 100. Leap centuries,
49+
// those divisible by 400, also get 366 days.
50+
int leap = ( (fromto[ i ] % 4 == 0 && fromto[ i ] % 100 != 0)
51+
||
52+
fromto[ i ] % 400 == 0) ? 1 : 0;
53+
fromto[i] = 365 + leap;
6054
}
6155

6256
/*

0 commit comments

Comments
 (0)