Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitfb715e0

Browse files
committed
Repair inconsistent rounding behavior for timestamp, time, interval,
per gripe from Csaba Nagy. There is still potential for platform-specificbehavior for values that are exactly halfway between integers, but atleast we now get the expected answer for all other cases.
1 parent2cd00f0 commitfb715e0

File tree

2 files changed

+56
-105
lines changed

2 files changed

+56
-105
lines changed

‎src/backend/utils/adt/date.c

Lines changed: 19 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.74 2002/11/21 23:31:20 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.75 2003/01/09 01:06:57 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -630,12 +630,12 @@ AdjustTimeForTypmod(TimeADT *time, int32 typmod)
630630
};
631631

632632
staticconstint64TimeOffsets[MAX_TIMESTAMP_PRECISION+1]= {
633-
INT64CONST(-500000),
634-
INT64CONST(-50000),
635-
INT64CONST(-5000),
636-
INT64CONST(-500),
637-
INT64CONST(-50),
638-
INT64CONST(-5),
633+
INT64CONST(500000),
634+
INT64CONST(50000),
635+
INT64CONST(5000),
636+
INT64CONST(500),
637+
INT64CONST(50),
638+
INT64CONST(5),
639639
INT64CONST(0)
640640
};
641641

@@ -649,52 +649,33 @@ AdjustTimeForTypmod(TimeADT *time, int32 typmod)
649649
100000,
650650
1000000
651651
};
652-
653-
staticconstdoubleTimeOffsets[MAX_TIMESTAMP_PRECISION+1]= {
654-
0.5,
655-
0.05,
656-
0.005,
657-
0.0005,
658-
0.00005,
659-
0.000005,
660-
0.0000005
661-
};
662652
#endif
663653

664654
if ((typmod >=0)&& (typmod <=MAX_TIME_PRECISION))
665655
{
656+
/*
657+
* Note: this round-to-nearest code is not completely consistent
658+
* about rounding values that are exactly halfway between integral
659+
* values. On most platforms, rint() will implement round-to-nearest,
660+
* but the integer code always rounds up (away from zero). Is it
661+
* worth trying to be consistent?
662+
*/
666663
#ifdefHAVE_INT64_TIMESTAMP
667-
/* we have different truncation behavior depending on sign */
668664
if (*time >=INT64CONST(0))
669-
{
670-
*time= ((*time /TimeScales[typmod])
671-
*TimeScales[typmod]);
672-
}
673-
else
674665
{
675666
*time= (((*time+TimeOffsets[typmod]) /TimeScales[typmod])
676667
*TimeScales[typmod]);
677668
}
678-
#else
679-
/* we have different truncation behavior depending on sign */
680-
if (*time >=0)
681-
{
682-
*time= (rint(((double)*time)*TimeScales[typmod])
683-
/TimeScales[typmod]);
684-
}
685669
else
686670
{
687-
/*
688-
* Scale and truncate first, then add to help the rounding
689-
* behavior
690-
*/
691-
*time= (rint((((double)*time)*TimeScales[typmod])+TimeOffsets[typmod])
692-
/TimeScales[typmod]);
671+
*time=- ((((-*time)+TimeOffsets[typmod]) /TimeScales[typmod])
672+
*TimeScales[typmod]);
693673
}
674+
#else
675+
*time= (rint(((double)*time)*TimeScales[typmod])
676+
/TimeScales[typmod]);
694677
#endif
695678
}
696-
697-
return;
698679
}
699680

700681

‎src/backend/utils/adt/timestamp.c

Lines changed: 37 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.75 2002/11/12 00:39:08 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.76 2003/01/09 01:06:57 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -175,12 +175,12 @@ AdjustTimestampForTypmod(Timestamp *time, int32 typmod)
175175
};
176176

177177
staticconstint64TimestampOffsets[MAX_TIMESTAMP_PRECISION+1]= {
178-
INT64CONST(-500000),
179-
INT64CONST(-50000),
180-
INT64CONST(-5000),
181-
INT64CONST(-500),
182-
INT64CONST(-50),
183-
INT64CONST(-5),
178+
INT64CONST(500000),
179+
INT64CONST(50000),
180+
INT64CONST(5000),
181+
INT64CONST(500),
182+
INT64CONST(50),
183+
INT64CONST(5),
184184
INT64CONST(0)
185185
};
186186

@@ -194,16 +194,6 @@ AdjustTimestampForTypmod(Timestamp *time, int32 typmod)
194194
100000,
195195
1000000
196196
};
197-
198-
staticconstdoubleTimestampOffsets[MAX_TIMESTAMP_PRECISION+1]= {
199-
0.5,
200-
0.05,
201-
0.005,
202-
0.0005,
203-
0.00005,
204-
0.000005,
205-
0.0000005
206-
};
207197
#endif
208198

209199
if (!TIMESTAMP_NOT_FINITE(*time)
@@ -213,34 +203,27 @@ AdjustTimestampForTypmod(Timestamp *time, int32 typmod)
213203
elog(ERROR,"TIMESTAMP(%d) precision must be between %d and %d",
214204
typmod,0,MAX_TIMESTAMP_PRECISION);
215205

206+
/*
207+
* Note: this round-to-nearest code is not completely consistent
208+
* about rounding values that are exactly halfway between integral
209+
* values. On most platforms, rint() will implement round-to-nearest,
210+
* but the integer code always rounds up (away from zero). Is it
211+
* worth trying to be consistent?
212+
*/
216213
#ifdefHAVE_INT64_TIMESTAMP
217-
/* we have different truncation behavior depending on sign */
218214
if (*time >=INT64CONST(0))
219-
{
220-
*time= ((*time /TimestampScales[typmod])
221-
*TimestampScales[typmod]);
222-
}
223-
else
224215
{
225216
*time= (((*time+TimestampOffsets[typmod]) /TimestampScales[typmod])
226217
*TimestampScales[typmod]);
227218
}
228-
#else
229-
/* we have different truncation behavior depending on sign */
230-
if (*time >=0)
231-
{
232-
*time= (rint(((double)*time)*TimestampScales[typmod])
233-
/TimestampScales[typmod]);
234-
}
235219
else
236220
{
237-
/*
238-
* Scale and truncate first, then add to help the rounding
239-
* behavior
240-
*/
241-
*time= (rint((((double)*time)*TimestampScales[typmod])+TimestampOffsets[typmod])
242-
/TimestampScales[typmod]);
221+
*time=- ((((-*time)+TimestampOffsets[typmod]) /TimestampScales[typmod])
222+
*TimestampScales[typmod]);
243223
}
224+
#else
225+
*time= (rint(((double)*time)*TimestampScales[typmod])
226+
/TimestampScales[typmod]);
244227
#endif
245228
}
246229
}
@@ -474,12 +457,12 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod)
474457
};
475458

476459
staticconstint64IntervalOffsets[MAX_INTERVAL_PRECISION+1]= {
477-
INT64CONST(-500000),
478-
INT64CONST(-50000),
479-
INT64CONST(-5000),
480-
INT64CONST(-500),
481-
INT64CONST(-50),
482-
INT64CONST(-5),
460+
INT64CONST(500000),
461+
INT64CONST(50000),
462+
INT64CONST(5000),
463+
INT64CONST(500),
464+
INT64CONST(50),
465+
INT64CONST(5),
483466
INT64CONST(0)
484467
};
485468

@@ -493,16 +476,6 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod)
493476
100000,
494477
1000000
495478
};
496-
497-
staticconstdoubleIntervalOffsets[MAX_INTERVAL_PRECISION+1]= {
498-
0.5,
499-
0.05,
500-
0.005,
501-
0.0005,
502-
0.00005,
503-
0.000005,
504-
0.0000005
505-
};
506479
#endif
507480

508481
/*
@@ -701,30 +674,27 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod)
701674
elog(ERROR,"INTERVAL(%d) precision must be between %d and %d",
702675
precision,0,MAX_INTERVAL_PRECISION);
703676

677+
/*
678+
* Note: this round-to-nearest code is not completely consistent
679+
* about rounding values that are exactly halfway between integral
680+
* values. On most platforms, rint() will implement round-to-nearest,
681+
* but the integer code always rounds up (away from zero). Is it
682+
* worth trying to be consistent?
683+
*/
704684
#ifdefHAVE_INT64_TIMESTAMP
705-
/* we have different truncation behavior depending on sign */
706685
if (interval->time >=INT64CONST(0))
707-
{
708-
interval->time= ((interval->time /IntervalScales[precision])
709-
*IntervalScales[precision]);
710-
}
711-
else
712686
{
713687
interval->time= (((interval->time+IntervalOffsets[precision]) /IntervalScales[precision])
714688
*IntervalScales[precision]);
715689
}
716-
#else
717-
/* we have different truncation behavior depending on sign */
718-
if (interval->time >=0)
719-
{
720-
interval->time= (rint(((double)interval->time)*IntervalScales[precision])
721-
/IntervalScales[precision]);
722-
}
723690
else
724691
{
725-
interval->time=(rint((((double)interval->time)+IntervalOffsets[precision])
726-
*IntervalScales[precision]) /IntervalScales[precision]);
692+
interval->time=- (((-interval->time+IntervalOffsets[precision]) /IntervalScales[precision])
693+
*IntervalScales[precision]);
727694
}
695+
#else
696+
interval->time= (rint(((double)interval->time)*IntervalScales[precision])
697+
/IntervalScales[precision]);
728698
#endif
729699
}
730700
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp