Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
786c3c03
Commit
786c3c03
authored
Sep 05, 2006
by
Bruce Momjian
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix imprecision from interval rounding of multiplication/division.
Bruce, Michael Glaesemann
parent
548e2c0a
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
40 additions
and
26 deletions
+40
-26
src/backend/utils/adt/timestamp.c
src/backend/utils/adt/timestamp.c
+33
-22
src/include/utils/timestamp.h
src/include/utils/timestamp.h
+7
-4
No files found.
src/backend/utils/adt/timestamp.c
View file @
786c3c03
...
...
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.16
6 2006/09/03 03:34:04
momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.16
7 2006/09/05 01:13:39
momjian Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -2514,28 +2514,34 @@ interval_mul(PG_FUNCTION_ARGS)
/*
* Fractional months full days into days.
*
* The remainders suffer from float rounding, so instead of
* doing the computation using just the remainder, we calculate
* the total number of days and subtract. Specifically, we are
* multipling by DAYS_PER_MONTH before dividing by factor.
* This greatly reduces rounding errors.
* Floating point calculation are inherently inprecise, so these
* calculations are crafted to produce the most reliable result
* possible. TSROUND() is needed to more accurately produce whole
* numbers where appropriate.
*/
month_remainder_days
=
(
orig_month
*
(
double
)
DAYS_PER_MONTH
)
*
factor
-
result
->
month
*
(
double
)
DAYS_PER_MONTH
;
sec_remainder
=
(
orig_day
*
(
double
)
SECS_PER_DAY
)
*
factor
-
result
->
day
*
(
double
)
SECS_PER_DAY
+
(
month_remainder_days
-
(
int32
)
month_remainder_days
)
*
SECS_PER_DAY
;
month_remainder_days
=
(
orig_month
*
factor
-
result
->
month
)
*
DAYS_PER_MONTH
;
month_remainder_days
=
TSROUND
(
month_remainder_days
);
sec_remainder
=
(
orig_day
*
factor
-
result
->
day
+
month_remainder_days
-
(
int
)
month_remainder_days
)
*
SECS_PER_DAY
;
sec_remainder
=
TSROUND
(
sec_remainder
);
/*
* Might have 24:00:00 hours due to rounding, or >24 hours because of
* time cascade from months and days. It might still be >24 if the
* combination of cascade and the seconds factor operation itself.
*/
if
(
Abs
(
sec_remainder
)
>=
SECS_PER_DAY
)
{
result
->
day
+=
(
int
)(
sec_remainder
/
SECS_PER_DAY
);
sec_remainder
-=
(
int
)(
sec_remainder
/
SECS_PER_DAY
)
*
SECS_PER_DAY
;
}
/* cascade units down */
result
->
day
+=
(
int32
)
month_remainder_days
;
#ifdef HAVE_INT64_TIMESTAMP
result
->
time
=
rint
(
span
->
time
*
factor
+
sec_remainder
*
USECS_PER_SEC
);
#else
/*
* TSROUND() needed to prevent -146:23:60.00 output on PowerPC for
* SELECT interval '-41 mon -12 days -360:00' * 0.3;
*/
result
->
time
=
span
->
time
*
factor
+
TSROUND
(
sec_remainder
);
result
->
time
=
span
->
time
*
factor
+
sec_remainder
;
#endif
PG_RETURN_INTERVAL_P
(
result
);
...
...
@@ -2574,11 +2580,16 @@ interval_div(PG_FUNCTION_ARGS)
* Fractional months full days into days. See comment in
* interval_mul().
*/
month_remainder_days
=
(
orig_month
*
(
double
)
DAYS_PER_MONTH
)
/
factor
-
result
->
month
*
(
double
)
DAYS_PER_MONTH
;
sec_remainder
=
(
orig_day
*
(
double
)
SECS_PER_DAY
)
/
factor
-
result
->
day
*
(
double
)
SECS_PER_DAY
+
(
month_remainder_days
-
(
int32
)
month_remainder_days
)
*
SECS_PER_DAY
;
month_remainder_days
=
(
orig_month
/
factor
-
result
->
month
)
*
DAYS_PER_MONTH
;
month_remainder_days
=
TSROUND
(
month_remainder_days
);
sec_remainder
=
(
orig_day
/
factor
-
result
->
day
+
month_remainder_days
-
(
int
)
month_remainder_days
)
*
SECS_PER_DAY
;
sec_remainder
=
TSROUND
(
sec_remainder
);
if
(
Abs
(
sec_remainder
)
>=
SECS_PER_DAY
)
{
result
->
day
+=
(
int
)(
sec_remainder
/
SECS_PER_DAY
);
sec_remainder
-=
(
int
)(
sec_remainder
/
SECS_PER_DAY
)
*
SECS_PER_DAY
;
}
/* cascade units down */
result
->
day
+=
(
int32
)
month_remainder_days
;
...
...
@@ -2586,7 +2597,7 @@ interval_div(PG_FUNCTION_ARGS)
result
->
time
=
rint
(
span
->
time
/
factor
+
sec_remainder
*
USECS_PER_SEC
);
#else
/* See TSROUND comment in interval_mul(). */
result
->
time
=
span
->
time
/
factor
+
TSROUND
(
sec_remainder
)
;
result
->
time
=
span
->
time
/
factor
+
sec_remainder
;
#endif
PG_RETURN_INTERVAL_P
(
result
);
...
...
src/include/utils/timestamp.h
View file @
786c3c03
...
...
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/timestamp.h,v 1.6
2 2006/07/13 16:49:2
0 momjian Exp $
* $PostgreSQL: pgsql/src/include/utils/timestamp.h,v 1.6
3 2006/09/05 01:13:4
0 momjian Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -161,11 +161,14 @@ typedef int32 fsec_t;
typedef
double
fsec_t
;
/* round off to MAX_TIMESTAMP_PRECISION decimal places */
/* note: this is also used for rounding off intervals */
#endif
/*
* 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))
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment