Thread: extra_float_digits and casting from real to numeric

extra_float_digits and casting from real to numeric

From
Christoph Berg
Date:
A customer recently upgraded their jdbc driver from 8.4 to 9.2. This
enabled the binary wire protocol (effectively between 9.1 and 9.2).
They reported that single precision values inserted into a
numeric(10,2) column were suddenly rounded wrongly, i.e. 10000.18 was
inserted as 10000.20, while that worked before. Of course we told them
that single is the wrong data type for this, but still, this is a
regression.

The behavior is easily reproducible with SELECT 10000.18::real which
returns 10000.2. Now, the jdbc driver sets extra_float_digits = 3,
which makes the this ::real cast return 10000.1797 in psql. This is
consistent with the documentation which suggests that
extra_float_digits = 0 will return the same representation on all
platforms, so it must be rounded a bit to account for different
implementations.

But if extra_float_digits > 0 is set, I'd expect not only the float4
output to be affected by it, but also casts to other datatypes, which
is not the case now:

set extra_float_digits = 0;
select 10000.18::real, 10000.18::real::numeric(10,2), 10000.18::real::text, to_char(10000.18::real, '99999D999');float4
| numeric  |  text   | to_char  
 
---------+----------+---------+----------10000.2 | 10000.20 | 10000.2 |  10000.2

set extra_float_digits = 1;
select 10000.18::real, 10000.18::real::numeric(10,2), 10000.18::real::text, to_char(10000.18::real, '99999D999');
float4 | numeric  |   text   | to_char  
 
----------+----------+----------+----------10000.18 | 10000.20 | 10000.18 |  10000.2

set extra_float_digits = 3;
select 10000.18::real, 10000.18::real::numeric(10,2), 10000.18::real::text, to_char(10000.18::real, '99999D999');
float4  | numeric  |    text    | to_char  
 
------------+----------+------------+----------10000.1797 | 10000.20 | 10000.1797 |  10000.2

Is that sane? Shouldn't FLT_DIG in float4_numeric() be replaced with
"FLT_DIG + extra_float_digits" like float4out() does, so the extra
precision is not lost when inserting float4 data into numeric columns?
Likewise, float4_to_char() should be adjusted for to_char output, and
correspondingly float8_numeric() and float8_to_char()?

Christoph
-- 
cb@df7cb.de | http://www.df7cb.de/



Re: extra_float_digits and casting from real to numeric

From
Tom Lane
Date:
Christoph Berg <christoph.berg@credativ.de> writes:
> A customer recently upgraded their jdbc driver from 8.4 to 9.2. This
> enabled the binary wire protocol (effectively between 9.1 and 9.2).
> They reported that single precision values inserted into a
> numeric(10,2) column were suddenly rounded wrongly, i.e. 10000.18 was
> inserted as 10000.20, while that worked before. Of course we told them
> that single is the wrong data type for this, but still, this is a
> regression.

I'm not sure that it's fair to characterize that as a regression.
If anything, it's more sensible than what happened before.

> But if extra_float_digits > 0 is set, I'd expect not only the float4
> output to be affected by it, but also casts to other datatypes,

This proposal scares me.  extra_float_digits is strictly a matter of
I/O representation, it does not affect any internal calculations.
Moreover, since one of the fundamental attributes of type numeric
is that it's supposed to give platform-independent results, I don't
like the idea that you're likely to get platform-dependent results
of conversions from float4/float8.

I think your customer got bit by his own bad coding practice, and
that should be the end of it.
        regards, tom lane



Re: extra_float_digits and casting from real to numeric

From
Christoph Berg
Date:
Re: Tom Lane 2014-01-07 <14979.1389112998@sss.pgh.pa.us>
> > But if extra_float_digits > 0 is set, I'd expect not only the float4
> > output to be affected by it, but also casts to other datatypes,
>
> This proposal scares me.  extra_float_digits is strictly a matter of
> I/O representation, it does not affect any internal calculations.
> Moreover, since one of the fundamental attributes of type numeric
> is that it's supposed to give platform-independent results, I don't
> like the idea that you're likely to get platform-dependent results
> of conversions from float4/float8.

I forgot to mention one bit here, and that's actually what made me
think "wtf" and post here. The server log is of course also affected
by this, so you even get different parameters depending on
extra_float_digits, yet the numeric result is the same "bad" one:

2014-01-08 10:13:53 CET LOG:  execute <unnamed>: INSERT INTO s VALUES($1)
2014-01-08 10:13:53 CET DETAIL:  parameters: $1 = '10000.2'
2014-01-08 10:14:18 CET LOG:  execute <unnamed>: INSERT INTO s VALUES($1)
2014-01-08 10:14:18 CET DETAIL:  parameters: $1 = '10000.1797'

Of course this is all consistent and in practice sums up to "don't use
real/single"...

> I think your customer got bit by his own bad coding practice, and
> that should be the end of it.

What about this patch to mention this gotcha more explicitely in the
documentation?

diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
new file mode 100644
index 0386330..968f4a7
*** a/doc/src/sgml/datatype.sgml
--- b/doc/src/sgml/datatype.sgml
*************** NUMERIC
*** 689,694 ****
--- 689,697 ----       <literal>0</literal>, the output is the same on every platform       supported by PostgreSQL.
Increasingit will produce output that       more accurately represents the stored value, but may be unportable. 
+       Casts to other numeric datatypes and the <literal>to_char</literal>
+       function are not affected by this setting, it affects only the text
+       representation.      </para>     </note>

Christoph
--
cb@df7cb.de | http://www.df7cb.de/

Re: [doc patch] extra_float_digits and casting from real to numeric

From
Christoph Berg
Date:
Re: To Tom Lane 2014-01-08 <20140108094017.GA20317@msgid.df7cb.de>
> What about this patch to mention this gotcha more explicitely in the
> documentation?
> 
> diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
> new file mode 100644
> index 0386330..968f4a7
> *** a/doc/src/sgml/datatype.sgml
> --- b/doc/src/sgml/datatype.sgml
> *************** NUMERIC
> *** 689,694 ****
> --- 689,697 ----
>         <literal>0</literal>, the output is the same on every platform
>         supported by PostgreSQL.  Increasing it will produce output that
>         more accurately represents the stored value, but may be unportable.
> +       Casts to other numeric datatypes and the <literal>to_char</literal>
> +       function are not affected by this setting, it affects only the text
> +       representation.
>        </para>
>       </note>
>   

Anyone for that patch?

Christoph
-- 
cb@df7cb.de | http://www.df7cb.de/



Re: [doc patch] extra_float_digits and casting from real to numeric

From
Robert Haas
Date:
On Tue, Feb 4, 2014 at 11:25 AM, Christoph Berg
<christoph.berg@credativ.de> wrote:
> Re: To Tom Lane 2014-01-08 <20140108094017.GA20317@msgid.df7cb.de>
>> What about this patch to mention this gotcha more explicitely in the
>> documentation?
>>
>> diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
>> new file mode 100644
>> index 0386330..968f4a7
>> *** a/doc/src/sgml/datatype.sgml
>> --- b/doc/src/sgml/datatype.sgml
>> *************** NUMERIC
>> *** 689,694 ****
>> --- 689,697 ----
>>         <literal>0</literal>, the output is the same on every platform
>>         supported by PostgreSQL.  Increasing it will produce output that
>>         more accurately represents the stored value, but may be unportable.
>> +       Casts to other numeric datatypes and the <literal>to_char</literal>
>> +       function are not affected by this setting, it affects only the text
>> +       representation.
>>        </para>
>>       </note>
>>
>
> Anyone for that patch?

Well, the new text kinda recapitulates what the existing text already
says.  If we're going to clarify, I'd do it like this:
    The <xref linkend="guc-extra-float-digits"> setting controls the     number of extra significant digits included
whena floating point     value is converted to text for output.  It does not affect the results     when a floating
pointnumber is converted to some other data type     or formatted using <literal>to_char</literal>.
 

But frankly I'm inclined to just leave it alone.  It says that it
affects what happens when the value "is converted to text for output".That's specific and accurate.  Granted, someone
couldmisunderstand,
 
but that's true of almost anything we might write, and being too
long-winded has costs of its own.

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company



Re: [doc patch] extra_float_digits and casting from real to numeric

From
Christoph Berg
Date:
Re: Robert Haas 2014-02-05 <CA+TgmoZY4KKapTkf2PXCoQnT-jb0YSP8w2PhP_qge62NiLv5oA@mail.gmail.com>
> >>         <literal>0</literal>, the output is the same on every platform
> >>         supported by PostgreSQL.  Increasing it will produce output that
> >>         more accurately represents the stored value, but may be unportable.
> >> +       Casts to other numeric datatypes and the <literal>to_char</literal>
> >> +       function are not affected by this setting, it affects only the text
> >> +       representation.
> >>        </para>
> >>       </note>
> >>
> >
> > Anyone for that patch?
>
> Well, the new text kinda recapitulates what the existing text already
> says.  If we're going to clarify, I'd do it like this:
>
>      The <xref linkend="guc-extra-float-digits"> setting controls the
>       number of extra significant digits included when a floating point
>       value is converted to text for output.  It does not affect the results
>       when a floating point number is converted to some other data type
>       or formatted using <literal>to_char</literal>.
>
> But frankly I'm inclined to just leave it alone.  It says that it
> affects what happens when the value "is converted to text for output".
>  That's specific and accurate.  Granted, someone could misunderstand,
> but that's true of almost anything we might write, and being too
> long-winded has costs of its own.

Yes, the original text is correct. The point is that the original text
doesn't really make the reader (who might think the numbers he's
seeing on the screen will also be used for computation/inserts) aware
that he's looking at something very different from what will actually
be used internally. I'm sure we were not the only one to stumble over
that problem, and I even knew what extra_float_digits is for, yet I
didn't connect the dots in the beginning.

Including some explicit heads-up sentence in there solves that
problem, either your version, or mine.

Mit freundlichen Grüßen,
Christoph Berg
--
Tel.: +49 (0)21 61 / 46 43-187
credativ GmbH, HRB Mönchengladbach 12080, USt-ID-Nummer: DE204566209
Hohenzollernstr. 133, 41061 Mönchengladbach
Geschäftsführung: Dr. Michael Meskes, Jörg Folz, Sascha Heuer