Re: BUG #17876: Function width_bucket() for float8 input returns value out of range

From: Mats Kindahl <mats(at)timescale(dot)com>
To: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
Cc: pgsql-bugs(at)lists(dot)postgresql(dot)org
Subject: Re: BUG #17876: Function width_bucket() for float8 input returns value out of range
Date: 2023-04-05 07:58:27
Message-ID: CA+14427tOx9GXw2Va_W0HF7Wp7kiu31BNju_=3SnCuaXOAdJzQ@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

On Fri, Mar 31, 2023 at 3:14 PM Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us> wrote:

> Mats Kindahl <mats(at)timescale(dot)com> writes:
> > On Thu, Mar 30, 2023 at 5:35 PM Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us> wrote:
> >> * It seems at least possible that, for an operand just slightly less
> >> than bound2, the quotient ((operand - bound1) / (bound2 - bound1))
> >> could round to exactly 1, even though it should theoretically always
> >> be in [0, 1). If that did happen, and count is INT_MAX, then the final
> >> addition of 1 would create its own possibility of integer overflow.
> >> We have code to check that but it's only applied in the operand >=
> bound2
> >> case. I fixed that by moving the overflow-aware addition of 1 to the
> >> bottom of the function so it's done in all cases, and adjusting the
> other
> >> code paths to account for that.
>
> I realized that it's actually not too hard to make that happen:
>
> regression=# select width_bucket(0, -1e100::float8, 1, 10);
> width_bucket
> --------------
> 11
> (1 row)
>
> While I'm not bothered too much if rounding affects which internal
> bucket a value lands in, it's a bit more annoying if that causes
> it to be reported as being in the end bucket, when we know positively
> that the value is less than bound2. Is it worth expending more
> cycles to prevent this?

I think it could be. I agree that it does not make sense to select the end
bucket when the value is in range, even if just.

> It'd need to be something like
>
> /* Result of division is surely in [0,1], so this can't
> overflow */
> result = count * ((operand - bound1) / (bound2 - bound1));
> + /* ... but the quotient could round to 1, which would be a lie
> */
> + if (result >= count)
> + result = count - 1;
>

Just doing some quick measurements on the different alternatives, I do not
see a big difference in performance between doing this additional check.
Have a look at the attached files. You can probably add a few other
alternatives to see if it can be improved further. Compiled at -O2.

>
> and we'd need two or four copies of that depending on whether we want
> to refactor some more.
>
> Curiously, width_bucket_numeric has this problem too:
>
> regression=# select width_bucket(0, -1e100::numeric, 1, 10);
> width_bucket
> --------------
> 11
> (1 row)
>
> I suppose it's also rounding somewhere in there.
>

Best wishes,
Mats Kindahl

>
> regards, tom lane
>

Attachment Content-Type Size
float_bucket_measure.txt text/plain 8.1 KB
float_bucket.c text/x-csrc 4.2 KB
float_bucket_plot.pl application/x-perl 374 bytes
image/png 32.4 KB

In response to

Responses

Browse pgsql-bugs by date

  From Date Subject
Next Message Tom Lane 2023-04-05 16:57:29 Re: BUG #17886: Error disabling user triggers on a partitioned table
Previous Message Alvaro Herrera 2023-04-05 07:33:56 Re: BUG #17886: Error disabling user triggers on a partitioned table