[tz] [PATCH 4/8] Simplify zic integer arithmetic
Paul Eggert
eggert at cs.ucla.edu
Wed Mar 24 03:58:49 UTC 2021
* private.h (DAYSPERREPEAT): New macro.
(SECSPERREPEAT, AVGSECSPERYEAR): Use it.
Rearrange REPEATish macros in a more-logical order.
* zic.c (rpytime): Avoid some conditional branches and
don’t treat years in the range 0..1969 as a special case.
The code for negative years was dubious anyway.
(LDAYSPERWEEK): Remove. All uses removed.
---
private.h | 18 ++++++------------
zic.c | 46 +++++++++++++++++-----------------------------
2 files changed, 23 insertions(+), 41 deletions(-)
diff --git a/private.h b/private.h
index a919e4f..e38a4f3 100644
--- a/private.h
+++ b/private.h
@@ -710,8 +710,6 @@ char *ctime_r(time_t const *, char *);
/* Handy macros that are independent of tzfile implementation. */
-#define YEARSPERREPEAT 400 /* years before a Gregorian repeat */
-
#define SECSPERMIN 60
#define MINSPERHOUR 60
#define HOURSPERDAY 24
@@ -722,6 +720,12 @@ char *ctime_r(time_t const *, char *);
#define SECSPERDAY ((int_fast32_t) SECSPERHOUR * HOURSPERDAY)
#define MONSPERYEAR 12
+#define YEARSPERREPEAT 400 /* years before a Gregorian repeat */
+#define DAYSPERREPEAT ((int_fast32_t) 400 * 365 + 100 - 4 + 1)
+#define SECSPERREPEAT ((int_fast64_t) DAYSPERREPEAT * SECSPERDAY)
+#define SECSPERREPEAT_BITS 34 /* ceil(log2(SECSPERREPEAT)) */
+#define AVGSECSPERYEAR (SECSPERREPEAT / YEARSPERREPEAT)
+
#define TM_SUNDAY 0
#define TM_MONDAY 1
#define TM_TUESDAY 2
@@ -764,14 +768,4 @@ char *ctime_r(time_t const *, char *);
#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400)
-
-/*
-** The Gregorian year averages 365.2425 days, which is 31556952 seconds.
-*/
-
-#define AVGSECSPERYEAR 31556952L
-#define SECSPERREPEAT \
- ((int_fast64_t) YEARSPERREPEAT * (int_fast64_t) AVGSECSPERYEAR)
-#define SECSPERREPEAT_BITS 34 /* ceil(log2(SECSPERREPEAT)) */
-
#endif /* !defined PRIVATE_H */
diff --git a/zic.c b/zic.c
index f5d813b..6c38bd7 100644
--- a/zic.c
+++ b/zic.c
@@ -3420,6 +3420,7 @@ rpytime(const struct rule *rp, zic_t wantedy)
register int m, i;
register zic_t dayoff; /* with a nod to Margaret O. */
register zic_t t, y;
+ int yrem;
if (wantedy == ZIC_MIN)
return min_time;
@@ -3428,24 +3429,20 @@ rpytime(const struct rule *rp, zic_t wantedy)
dayoff = 0;
m = TM_JANUARY;
y = EPOCH_YEAR;
- if (y < wantedy) {
- wantedy -= y;
- dayoff = (wantedy / YEARSPERREPEAT) * (SECSPERREPEAT / SECSPERDAY);
- wantedy %= YEARSPERREPEAT;
- wantedy += y;
- } else if (wantedy < 0) {
- dayoff = (wantedy / YEARSPERREPEAT) * (SECSPERREPEAT / SECSPERDAY);
- wantedy %= YEARSPERREPEAT;
- }
+
+ /* dayoff = floor((wantedy - y) / YEARSPERREPEAT) * DAYSPERREPEAT,
+ sans overflow. */
+ yrem = wantedy % YEARSPERREPEAT - y % YEARSPERREPEAT;
+ dayoff = ((wantedy / YEARSPERREPEAT - y / YEARSPERREPEAT
+ + yrem / YEARSPERREPEAT - (yrem % YEARSPERREPEAT < 0))
+ * DAYSPERREPEAT);
+ /* wantedy = y + ((wantedy - y) mod YEARSPERREPEAT), sans overflow. */
+ wantedy = y + (yrem + 2 * YEARSPERREPEAT) % YEARSPERREPEAT;
+
while (wantedy != y) {
- if (wantedy > y) {
- i = len_years[isleap(y)];
- ++y;
- } else {
- --y;
- i = -len_years[isleap(y)];
- }
+ i = len_years[isleap(y)];
dayoff = oadd(dayoff, i);
+ y++;
}
while (m != rp->r_month) {
i = len_months[isleap(y)][m];
@@ -3464,30 +3461,21 @@ rpytime(const struct rule *rp, zic_t wantedy)
--i;
dayoff = oadd(dayoff, i);
if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
- register zic_t wday;
-
-#define LDAYSPERWEEK ((zic_t) DAYSPERWEEK)
- wday = EPOCH_WDAY;
/*
** Don't trust mod of negative numbers.
*/
- if (dayoff >= 0)
- wday = (wday + dayoff) % LDAYSPERWEEK;
- else {
- wday -= ((-dayoff) % LDAYSPERWEEK);
- if (wday < 0)
- wday += LDAYSPERWEEK;
- }
+ zic_t wday = ((EPOCH_WDAY + dayoff % DAYSPERWEEK + DAYSPERWEEK)
+ % DAYSPERWEEK);
while (wday != rp->r_wday)
if (rp->r_dycode == DC_DOWGEQ) {
dayoff = oadd(dayoff, 1);
- if (++wday >= LDAYSPERWEEK)
+ if (++wday >= DAYSPERWEEK)
wday = 0;
++i;
} else {
dayoff = oadd(dayoff, -1);
if (--wday < 0)
- wday = LDAYSPERWEEK - 1;
+ wday = DAYSPERWEEK - 1;
--i;
}
if (i < 0 || i >= len_months[isleap(y)][m]) {
--
2.27.0
More information about the tz
mailing list