Re: BUG #14663: Unexpected rounding changes for money type divided by bigint

From: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
To: pistole(at)rhp(dot)org
Cc: pgsql-bugs(at)postgresql(dot)org, Bruce Momjian <bruce(at)momjian(dot)us>
Subject: Re: BUG #14663: Unexpected rounding changes for money type divided by bigint
Date: 2017-05-19 17:31:41
Message-ID: 4877.1495215101@sss.pgh.pa.us
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

pistole(at)rhp(dot)org writes:
> Running the following query:
> select 878.08::money/11::bigint;
> Returns this following result in 9.6.3:
> $79.83
> In 10beta1, it returns:
> $79.82

Confirmed here.

> I think this may be related to this commit and doing the running sums as
> negatives, but I'm not sure:

No, I think the relevant commit is

Author: Peter Eisentraut <peter_e(at)gmx(dot)net>
Branch: master [323b96aa3] 2017-01-17 12:36:02 -0500

Register missing money operators in system catalogs

The operators money*int8, int8*money, and money/int8 were implemented in
code but not registered in pg_operator or pg_proc.

Previously, money/int8 would have ended up as money/(int8::float8)
which rounds the conversion, whereas cash_div_int8 truncates.

While this is certainly a behavior change, I think it's more consistent
than before, because cash_div_int4 has always truncated. So in prior
versions you got

regression=# select '878.08'::money/11::bigint;
?column?
----------
$79.83
(1 row)

regression=# select '878.08'::money/11::int;
?column?
----------
$79.82
(1 row)

which hardly seems desirable. Now they both give $79.82. If you
want the old behavior you can cast the divisor to float8 explicitly.

We do have a couple of to-do items here though:

1. The v10 release notes mention this commit but fail to point
out that it might be a behavioral change.

2. I notice that the cash_div_intX functions all use rint() on
the result, which is completely useless because the result is
an integer already. Much worse, forcing the value to double
and back will lose precision if the value exceeds 2^52 or so.
This is visible here for instance:

regression=# select '90000000000000012.00'::money / 10::int;
?column?
---------------------------
$9,000,000,000,000,001.28
(1 row)

That's just wrong. We should remove the rint() calls and acknowledge
that these divisor functions truncate rather than rounding. I think
this is a back-patchable bug fix ... does anyone want to argue that
preserving the precision loss in the back branches is a good thing?

regards, tom lane

In response to

Browse pgsql-bugs by date

  From Date Subject
Next Message Tom Lane 2017-05-19 17:44:28 Re: BUG #14662: 'has_table_privilege()' function fails with error, "invalid name syntax" when using Japanese symbols
Previous Message lx xl 2017-05-19 17:09:44 Unique Constraint Provides Lock in Transaction