Thread
Commits
-
Fix loss of fractional digits for large values in cash_numeric().
- fa854112fc3d 10.10 landed
- ca918f99aaa5 11.5 landed
- b9d2c5c7ac80 13.0 landed
- 81b29c87114c 9.4.24 landed
- 30bed9f63823 9.6.15 landed
- 13e493cf68a4 9.5.19 landed
- 01e0538e8b12 12.0 landed
-
BUG #15925: Loss of precision converting money to numeric
The Post Office <noreply@postgresql.org> — 2019-07-26T07:39:17Z
The following bug has been logged on the website: Bug reference: 15925 Logged by: Slawomir Chodnicki Email address: slawomir.chodnicki@gmail.com PostgreSQL version: 11.4 Operating system: Linux Description: As per documentation converting a money value to numeric does not lose precision. In general that is the case: select '8547758.07'::money, '8547758.07'::money::numeric(30,2); money |numeric | -------------|----------| $8,547,758.07|8547758.07| During my testing I found unexpected results for the min and max value of the money type. select '-92233720368547758.08'::money, '-92233720368547758.08'::money::numeric(30,2); money |numeric | ---------------------------|---------------------| -$92,233,720,368,547,758.08|-92233720368547758.00| Note that the cent value is gone after converting to numeric. Same issue for the max value: money |numeric | --------------------------|--------------------| $92,233,720,368,547,758.07|92233720368547758.00| Best Wishes Slawo
-
Re: BUG #15925: Loss of precision converting money to numeric
Tom Lane <tgl@sss.pgh.pa.us> — 2019-07-26T15:17:34Z
PG Bug reporting form <noreply@postgresql.org> writes: > During my testing I found unexpected results for the min and max value of > the money type. > select '-92233720368547758.08'::money, > '-92233720368547758.08'::money::numeric(30,2); > money |numeric | > ---------------------------|---------------------| > -$92,233,720,368,547,758.08|-92233720368547758.00| > Note that the cent value is gone after converting to numeric. > Same issue for the max value: > money |numeric | > --------------------------|--------------------| > $92,233,720,368,547,758.07|92233720368547758.00| Hmm, yeah, anything approaching INT64_MAX has a problem. The issue is that cash_numeric() does the equivalent of SELECT 9223372036854775807::numeric / 100::numeric; and if you try that by hand you indeed get 92233720368547758 because select_div_scale() has decided that it need not produce any fractional digits. We can force its hand by making the input have the required number of fractional digits *before* dividing, which is a bit weird on its face but gets the job done, per the comment therein: * The result scale of a division isn't specified in any SQL standard. For * PostgreSQL we select a result scale that will give at least * NUMERIC_MIN_SIG_DIGITS significant digits, so that numeric gives a * result no less accurate than float8; but use a scale not less than * either input's display scale. (NUMERIC_MIN_SIG_DIGITS is 16, whence the problem for a 17-digit result. Maybe we should consider raising that, but I'm hesitant to consider such a far-reaching change just to make cash_numeric happy.) I intend to apply the attached patch. regards, tom lane -
Re: BUG #15925: Loss of precision converting money to numeric
Slawomir Chodnicki <slawomir.chodnicki@gmail.com> — 2019-07-26T16:15:00Z
> Hmm, yeah, anything approaching INT64_MAX has a problem. > The issue is that cash_numeric() does the equivalent of > > SELECT 9223372036854775807::numeric / 100::numeric; > > and if you try that by hand you indeed get > > 92233720368547758 > > because select_div_scale() has decided that it need not produce > any fractional digits. We can force its hand by making the input > have the required number of fractional digits *before* dividing, > which is a bit weird on its face but gets the job done, per the > comment therein: > > * The result scale of a division isn't specified in any SQL standard. For > * PostgreSQL we select a result scale that will give at least > * NUMERIC_MIN_SIG_DIGITS significant digits, so that numeric gives a > * result no less accurate than float8; but use a scale not less than > * either input's display scale. > > (NUMERIC_MIN_SIG_DIGITS is 16, whence the problem for a 17-digit result. > Maybe we should consider raising that, but I'm hesitant to consider such > a far-reaching change just to make cash_numeric happy.) > > I intend to apply the attached patch. Thanks Tom, the response is illuminating. And a same-day patch is legendary. Thank you for your work. Slawo