diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c index 3b921258890d14fdef817f2d306e18be2162d661..b952480f2fe303991b397203fcc2e89be6b145a3 100644 --- a/src/backend/utils/adt/date.c +++ b/src/backend/utils/adt/date.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.74 2002/11/21 23:31:20 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.75 2003/01/09 01:06:57 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -630,12 +630,12 @@ AdjustTimeForTypmod(TimeADT *time, int32 typmod) }; static const int64 TimeOffsets[MAX_TIMESTAMP_PRECISION + 1] = { - INT64CONST(-500000), - INT64CONST(-50000), - INT64CONST(-5000), - INT64CONST(-500), - INT64CONST(-50), - INT64CONST(-5), + INT64CONST(500000), + INT64CONST(50000), + INT64CONST(5000), + INT64CONST(500), + INT64CONST(50), + INT64CONST(5), INT64CONST(0) }; @@ -649,52 +649,33 @@ AdjustTimeForTypmod(TimeADT *time, int32 typmod) 100000, 1000000 }; - - static const double TimeOffsets[MAX_TIMESTAMP_PRECISION + 1] = { - 0.5, - 0.05, - 0.005, - 0.0005, - 0.00005, - 0.000005, - 0.0000005 - }; #endif if ((typmod >= 0) && (typmod <= MAX_TIME_PRECISION)) { + /* + * Note: this round-to-nearest code is not completely consistent + * about rounding values that are exactly halfway between integral + * values. On most platforms, rint() will implement round-to-nearest, + * but the integer code always rounds up (away from zero). Is it + * worth trying to be consistent? + */ #ifdef HAVE_INT64_TIMESTAMP - /* we have different truncation behavior depending on sign */ if (*time >= INT64CONST(0)) - { - *time = ((*time / TimeScales[typmod]) - * TimeScales[typmod]); - } - else { *time = (((*time + TimeOffsets[typmod]) / TimeScales[typmod]) * TimeScales[typmod]); } -#else - /* we have different truncation behavior depending on sign */ - if (*time >= 0) - { - *time = (rint(((double) *time) * TimeScales[typmod]) - / TimeScales[typmod]); - } else { - /* - * Scale and truncate first, then add to help the rounding - * behavior - */ - *time = (rint((((double) *time) * TimeScales[typmod]) + TimeOffsets[typmod]) - / TimeScales[typmod]); + *time = - ((((- *time) + TimeOffsets[typmod]) / TimeScales[typmod]) + * TimeScales[typmod]); } +#else + *time = (rint(((double) *time) * TimeScales[typmod]) + / TimeScales[typmod]); #endif } - - return; } diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index 885d3992fd44ab5304e7845ab23a89e9507b1a14..19fb9c118438135748919e75ba281b9f7d644ab8 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.75 2002/11/12 00:39:08 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.76 2003/01/09 01:06:57 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -175,12 +175,12 @@ AdjustTimestampForTypmod(Timestamp *time, int32 typmod) }; static const int64 TimestampOffsets[MAX_TIMESTAMP_PRECISION + 1] = { - INT64CONST(-500000), - INT64CONST(-50000), - INT64CONST(-5000), - INT64CONST(-500), - INT64CONST(-50), - INT64CONST(-5), + INT64CONST(500000), + INT64CONST(50000), + INT64CONST(5000), + INT64CONST(500), + INT64CONST(50), + INT64CONST(5), INT64CONST(0) }; @@ -194,16 +194,6 @@ AdjustTimestampForTypmod(Timestamp *time, int32 typmod) 100000, 1000000 }; - - static const double TimestampOffsets[MAX_TIMESTAMP_PRECISION + 1] = { - 0.5, - 0.05, - 0.005, - 0.0005, - 0.00005, - 0.000005, - 0.0000005 - }; #endif if (!TIMESTAMP_NOT_FINITE(*time) @@ -213,34 +203,27 @@ AdjustTimestampForTypmod(Timestamp *time, int32 typmod) elog(ERROR, "TIMESTAMP(%d) precision must be between %d and %d", typmod, 0, MAX_TIMESTAMP_PRECISION); + /* + * Note: this round-to-nearest code is not completely consistent + * about rounding values that are exactly halfway between integral + * values. On most platforms, rint() will implement round-to-nearest, + * but the integer code always rounds up (away from zero). Is it + * worth trying to be consistent? + */ #ifdef HAVE_INT64_TIMESTAMP - /* we have different truncation behavior depending on sign */ if (*time >= INT64CONST(0)) - { - *time = ((*time / TimestampScales[typmod]) - * TimestampScales[typmod]); - } - else { *time = (((*time + TimestampOffsets[typmod]) / TimestampScales[typmod]) * TimestampScales[typmod]); } -#else - /* we have different truncation behavior depending on sign */ - if (*time >= 0) - { - *time = (rint(((double) *time) * TimestampScales[typmod]) - / TimestampScales[typmod]); - } else { - /* - * Scale and truncate first, then add to help the rounding - * behavior - */ - *time = (rint((((double) *time) * TimestampScales[typmod]) + TimestampOffsets[typmod]) - / TimestampScales[typmod]); + *time = - ((((- *time) + TimestampOffsets[typmod]) / TimestampScales[typmod]) + * TimestampScales[typmod]); } +#else + *time = (rint(((double) *time) * TimestampScales[typmod]) + / TimestampScales[typmod]); #endif } } @@ -474,12 +457,12 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod) }; static const int64 IntervalOffsets[MAX_INTERVAL_PRECISION + 1] = { - INT64CONST(-500000), - INT64CONST(-50000), - INT64CONST(-5000), - INT64CONST(-500), - INT64CONST(-50), - INT64CONST(-5), + INT64CONST(500000), + INT64CONST(50000), + INT64CONST(5000), + INT64CONST(500), + INT64CONST(50), + INT64CONST(5), INT64CONST(0) }; @@ -493,16 +476,6 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod) 100000, 1000000 }; - - static const double IntervalOffsets[MAX_INTERVAL_PRECISION + 1] = { - 0.5, - 0.05, - 0.005, - 0.0005, - 0.00005, - 0.000005, - 0.0000005 - }; #endif /* @@ -701,30 +674,27 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod) elog(ERROR, "INTERVAL(%d) precision must be between %d and %d", precision, 0, MAX_INTERVAL_PRECISION); + /* + * Note: this round-to-nearest code is not completely consistent + * about rounding values that are exactly halfway between integral + * values. On most platforms, rint() will implement round-to-nearest, + * but the integer code always rounds up (away from zero). Is it + * worth trying to be consistent? + */ #ifdef HAVE_INT64_TIMESTAMP - /* we have different truncation behavior depending on sign */ if (interval->time >= INT64CONST(0)) - { - interval->time = ((interval->time / IntervalScales[precision]) - * IntervalScales[precision]); - } - else { interval->time = (((interval->time + IntervalOffsets[precision]) / IntervalScales[precision]) * IntervalScales[precision]); } -#else - /* we have different truncation behavior depending on sign */ - if (interval->time >= 0) - { - interval->time = (rint(((double) interval->time) * IntervalScales[precision]) - / IntervalScales[precision]); - } else { - interval->time = (rint((((double) interval->time) + IntervalOffsets[precision]) - * IntervalScales[precision]) / IntervalScales[precision]); + interval->time = - (((-interval->time + IntervalOffsets[precision]) / IntervalScales[precision]) + * IntervalScales[precision]); } +#else + interval->time = (rint(((double) interval->time) * IntervalScales[precision]) + / IntervalScales[precision]); #endif } }