Re: Interval aggregate regression failure (expected seems - Mailing list pgsql-hackers

From Bruce Momjian
Subject Re: Interval aggregate regression failure (expected seems
Date
Msg-id 200608110448.k7B4m8f01279@momjian.us
Whole thread Raw
In response to Re: Interval aggregate regression failure (expected seems  (Tom Lane <tgl@sss.pgh.pa.us>)
Responses Re: Interval aggregate regression failure (expected seems
List pgsql-hackers
Have we made any progress on this?

---------------------------------------------------------------------------

Tom Lane wrote:
> Michael Glaesemann <grzm@seespotcode.net> writes:
> > ... I think this just confirms that there is some kind of rounding (or  
> > lack of) in interval_div. Kind of frustrating that it's not visible  
> > in the result.
> 
> I think the fundamental problem is that the float8 results of division
> are inaccurate, and yet we're assuming that we can (for instance) coerce
> them to integer and get exactly the right answer.  For instance, in the
> '41 months'/10 example, I get month_remainder_days being computed as
> 
> (gdb) p month_remainder
> $19 = 0.099999999999999645
> (gdb) s
> 2575            result->day += (int32) month_remainder_days;
> (gdb) p month_remainder_days
> $20 = 2.9999999999999893
> 
> The only way we can really fix this is to be willing to round off
> the numbers, and I think the only principled way to do that is to
> settle on a specific target accuracy, probably 1 microsecond.
> Then the thing to do would be to scale up all the intermediate
> float results to microseconds and apply rint().  Something like
> (untested)
> 
>     month_remainder = rint(span->month * USECS_PER_MONTH / factor);
>     day_remainder = rint(span->day * USECS_PER_DAY / factor);
>     result->month = (int32) (month_remainder / USECS_PER_MONTH);
>     result->day = (int32) (day_remainder / USECS_PER_DAY);
>     month_remainder -= result->month * USECS_PER_MONTH;
>     day_remainder -= result->day * USECS_PER_DAY;
> 
>     /*
>      * Handle any fractional parts the same way as in interval_mul.
>      */
> 
>     /* fractional months full days into days */
>     month_remainder_days = month_remainder * DAYS_PER_MONTH;
>     extra_days = (int32) (month_remainder_days / USECS_PER_DAY);
>     result->day += extra_days;
>     /* fractional months partial days into time */
>     day_remainder += month_remainder_days - extra_days * USECS_PER_DAY;
> 
> #ifdef HAVE_INT64_TIMESTAMP
>     result->time = rint(span->time / factor + day_remainder);
> #else
>     result->time = rint(span->time * 1.0e6 / factor + day_remainder) / 1.0e6;
> #endif
> 
> This might need a few more rint() calls --- I'm assuming that float ops
> with exact integral inputs will be OK, which is an assumption used
> pretty widely in the datetime code, but ...
> 
> Per the comment, if we do this here we probably want to make
> interval_mul work similarly.
> 
>             regards, tom lane

--  Bruce Momjian   bruce@momjian.us EnterpriseDB    http://www.enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


pgsql-hackers by date:

Previous
From: Michael Glaesemann
Date:
Subject: Re: [GENERAL] different sort order in windows and linux version
Next
From: Tom Lane
Date:
Subject: Re: [GENERAL] different sort order in windows and linux version