From: | Michael Glaesemann <grzm(at)seespotcode(dot)net> |
---|---|
To: | Michael Glaesemann <grzm(at)seespotcode(dot)net> |
Cc: | Bruce Momjian <bruce(at)momjian(dot)us>, Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>, pgsql-hackers(at)postgresql(dot)org, Michael Paesold <mpaesold(at)gmx(dot)at>, PostgreSQL-patches <pgsql-patches(at)postgresql(dot)org> |
Subject: | Re: [HACKERS] Interval aggregate regression failure |
Date: | 2006-09-01 13:54:39 |
Message-ID: | 8A607FA9-382F-4A5B-BEE5-E9B30FBF3233@seespotcode.net |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Thread: | |
Lists: | pgsql-hackers pgsql-patches |
On Sep 1, 2006, at 20:39 , Michael Glaesemann wrote:
> Here's a patch that appears to work. Gives the same output with and
> without --enable-integer-datetimes. Answers look like they're correct.
>
> I'm basically treating the components as three different intervals
> (with the other two components zero), rounding them each to usecs,
> and adding them together.
>
> While it might be nice to carry a little extra precision around, it
> doesn't seem to be needed in these cases. If errors do arise, they
> should be at most 3 usec, which is pretty much noise for the
> floating point case, I suspect.
Okay. Here's the patch. Bruce, does it work for you?
Michael Glaesemann
grzm seespotcode net
Index: src/backend/utils/adt/timestamp.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v
retrieving revision 1.165
diff -c -r1.165 timestamp.c
*** src/backend/utils/adt/timestamp.c 13 Jul 2006 16:49:16 -0000 1.165
--- src/backend/utils/adt/timestamp.c 1 Sep 2006 12:28:23 -0000
***************
*** 2494,2504 ****
float8 factor = PG_GETARG_FLOAT8(1);
double month_remainder,
day_remainder,
! month_remainder_days;
Interval *result;
result = (Interval *) palloc(sizeof(Interval));
month_remainder = span->month * factor;
day_remainder = span->day * factor;
result->month = (int32) month_remainder;
--- 2494,2507 ----
float8 factor = PG_GETARG_FLOAT8(1);
double month_remainder,
day_remainder,
! month_remainder_days,
! month_remainder_time,
! day_remainder_time;
Interval *result;
result = (Interval *) palloc(sizeof(Interval));
+
month_remainder = span->month * factor;
day_remainder = span->day * factor;
result->month = (int32) month_remainder;
***************
*** 2506,2511 ****
--- 2509,2553 ----
month_remainder -= result->month;
day_remainder -= result->day;
+ month_remainder_days = month_remainder * DAYS_PER_MONTH;
+
+ /*
+ if month_remainder_days is not an integer, check to see if it's an
+ integer when converted to SECS or USECS.
+ If it is, round month_remainder_days to the nearest integer
+
+ */
+
+ if (month_remainder_days != (int32)month_remainder_days &&
+ TSROUND(month_remainder_days * SECS_PER_DAY) ==
+ rint(month_remainder_days * SECS_PER_DAY))
+ month_remainder_days = rint(month_remainder_days);
+
+ result->day += (int32)month_remainder_days;
+
+ #ifdef HAVE_INT64_TIMESTAMP
+ month_remainder_time = rint((month_remainder_days -
+ (int32)month_remainder_days) * USECS_PER_DAY);
+
+ day_remainder_time = rint(day_remainder * USECS_PER_DAY);
+
+
+ result->time = rint(rint(span->time * factor) + day_remainder_time +
+ month_remainder_time);
+ #else
+ month_remainder_time = rint((month_remainder_days -
+ (int32)month_remainder_days) * SECS_PER_DAY);
+ day_remainder_time = rint(day_remainder * SECS_PER_DAY);
+
+ result->time = span->time * factor + day_remainder_time +
+ month_remainder_time;
+ #endif
+
+
+ day_remainder = span->day * factor;
+ result->day = (int32) day_remainder;
+ day_remainder -= result->day;
+
/*
* The above correctly handles the whole-number part of the month
and day
* products, but we have to do something with any fractional part
***************
*** 2518,2531 ****
/* fractional months full days into days */
month_remainder_days = month_remainder * DAYS_PER_MONTH;
! result->day += (int32) month_remainder_days;
! /* fractional months partial days into time */
! day_remainder += month_remainder_days - (int32) month_remainder_days;
#ifdef HAVE_INT64_TIMESTAMP
! result->time = rint(span->time * factor + day_remainder *
USECS_PER_DAY);
#else
! result->time = span->time * factor + day_remainder * SECS_PER_DAY;
#endif
PG_RETURN_INTERVAL_P(result);
--- 2560,2599 ----
/* fractional months full days into days */
month_remainder_days = month_remainder * DAYS_PER_MONTH;
! /*
! * The remainders suffer from float rounding, so if they are
! * within 1us of an integer, we round them to integers.
! * It seems doing two multiplies is causing the imprecision.
! */
#ifdef HAVE_INT64_TIMESTAMP
! if (month_remainder_days != (int32)month_remainder_days &&
! rint(month_remainder_days * USECS_PER_DAY) ==
! (int64)(month_remainder_days * USECS_PER_DAY))
! month_remainder_days = rint(month_remainder_days);
! result->day += (int32) month_remainder_days;
! month_remainder_time = rint((month_remainder_days -
! (int32)month_remainder_days) * USECS_PER_DAY);
!
! day_remainder_time = rint(day_remainder * USECS_PER_DAY);
!
! result->time = rint(span->time * factor + day_remainder_time +
! month_remainder_time);
#else
! if (month_remainder_days != (int32)month_remainder_days &&
! TSROUND(month_remainder_days * SECS_PER_DAY) ==
! rint(month_remainder_days * SECS_PER_DAY))
! month_remainder_days = rint(month_remainder_days);
! result->day += (int32) month_remainder_days;
!
! month_remainder_time = rint((month_remainder_days -
! (int32)month_remainder_days) * SECS_PER_DAY);
!
! day_remainder_time = rint(day_remainder * SECS_PER_DAY);
!
! result->time = span->time * factor + day_remainder_time +
! month_remainder_time;
!
#endif
PG_RETURN_INTERVAL_P(result);
***************
*** 2548,2554 ****
float8 factor = PG_GETARG_FLOAT8(1);
double month_remainder,
day_remainder,
! month_remainder_days;
Interval *result;
result = (Interval *) palloc(sizeof(Interval));
--- 2616,2624 ----
float8 factor = PG_GETARG_FLOAT8(1);
double month_remainder,
day_remainder,
! month_remainder_days,
! month_remainder_time,
! day_remainder_time;
Interval *result;
result = (Interval *) palloc(sizeof(Interval));
***************
*** 2571,2584 ****
/* fractional months full days into days */
month_remainder_days = month_remainder * DAYS_PER_MONTH;
result->day += (int32) month_remainder_days;
- /* fractional months partial days into time */
- day_remainder += month_remainder_days - (int32) month_remainder_days;
! #ifdef HAVE_INT64_TIMESTAMP
! result->time = rint(span->time / factor + day_remainder *
USECS_PER_DAY);
! #else
! result->time = span->time / factor + day_remainder * SECS_PER_DAY;
#endif
PG_RETURN_INTERVAL_P(result);
--- 2641,2680 ----
/* fractional months full days into days */
month_remainder_days = month_remainder * DAYS_PER_MONTH;
+ /*
+ * The remainders suffer from float rounding, so if they are
+ * within 1us of an integer, we round them to integers.
+ * It seems doing a division and multiplies is causing the
+ * imprecision.
+ */
+ if (month_remainder_days != (int32)month_remainder_days &&
+ TSROUND(month_remainder_days * SECS_PER_DAY) ==
+ rint(month_remainder_days * SECS_PER_DAY))
+ month_remainder_days = rint(month_remainder_days);
result->day += (int32) month_remainder_days;
! day_remainder_time = day_remainder * SECS_PER_DAY;
! if (day_remainder_time != (int32)day_remainder_time &&
! TSROUND(day_remainder_time) ==
! rint(day_remainder_time))
! day_remainder_time = rint(day_remainder_time);
!
! #ifdef HAVE_INT64_TIMESTAMP
! day_remainder_time = day_remainder * USECS_PER_DAY;
! if (day_remainder_time != (int32)day_remainder_time &&
! TSROUND(day_remainder_time) == rint(day_remainder_time))
! day_remainder_time = rint(day_remainder_time);
!
! result->time = rint(span->time / factor + day_remainder_time +
! (month_remainder_days - (int32)month_remainder_days) *
USECS_PER_DAY;
! #else
! day_remainder_time = day_remainder * SECS_PER_DAY;
! if (day_remainder_time != (int32)day_remainder_time &&
! TSROUND(day_remainder_time) == rint(day_remainder_time))
! day_remainder_time = rint(day_remainder_time);
!
! result->time = span->time / factor + day_remainder_time +
! (month_remainder_days - (int32)month_remainder_days) *
SECS_PER_DAY;
#endif
PG_RETURN_INTERVAL_P(result);
Index: src/include/utils/timestamp.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/utils/timestamp.h,v
retrieving revision 1.62
diff -c -r1.62 timestamp.h
*** src/include/utils/timestamp.h 13 Jul 2006 16:49:20 -0000 1.62
--- src/include/utils/timestamp.h 1 Sep 2006 12:28:24 -0000
***************
*** 161,171 ****
typedef double fsec_t;
! /* round off to MAX_TIMESTAMP_PRECISION decimal places */
! /* note: this is also used for rounding off intervals */
#define TS_PREC_INV 1000000.0
#define TSROUND(j) (rint(((double) (j)) * TS_PREC_INV) / TS_PREC_INV)
- #endif
#define TIMESTAMP_MASK(b) (1 << (b))
#define INTERVAL_MASK(b) (1 << (b))
--- 161,175 ----
typedef double fsec_t;
! #endif
!
! /*
! * Round off to MAX_TIMESTAMP_PRECISION decimal places.
! * This is also used for rounding off intervals, and
! * for rounding interval multiplication/division calculations.
! */
#define TS_PREC_INV 1000000.0
#define TSROUND(j) (rint(((double) (j)) * TS_PREC_INV) / TS_PREC_INV)
#define TIMESTAMP_MASK(b) (1 << (b))
#define INTERVAL_MASK(b) (1 << (b))
From | Date | Subject | |
---|---|---|---|
Next Message | Stefan Kaltenbrunner | 2006-09-01 13:59:49 | Re: Roadmaps 'n all that |
Previous Message | Tom Lane | 2006-09-01 13:44:04 | Re: [HACKERS] Interval aggregate regression failure |
From | Date | Subject | |
---|---|---|---|
Next Message | Tom Lane | 2006-09-01 14:45:09 | Re: DOC: catalog.sgml |
Previous Message | Tom Lane | 2006-09-01 13:44:04 | Re: [HACKERS] Interval aggregate regression failure |