Thread: Re: [BUGS] BUG #2846: inconsistent and confusing handling of

Re: [BUGS] BUG #2846: inconsistent and confusing handling of

From
Bruce Momjian
Date:
Roman Kononov wrote:
> On 12/27/2006 12:44 PM, Bruce Momjian wrote:
> > The only unsolved issue is the one with underflow checks.  I have added
> > comments explaining the problem in case someone ever figures out how to
> > address it.
>
> This will behave better for float4:
>
>     Datum float4pl(PG_FUNCTION_ARGS)
>     {
> ---    float4  arg1 = PG_GETARG_FLOAT4(0);
> ---    float4  arg2 = PG_GETARG_FLOAT4(1);
> +++    double  arg1 = PG_GETARG_FLOAT4(0);
> +++    double  arg2 = PG_GETARG_FLOAT4(1);
>         double  result;
>
>         result = arg1 + arg2;
>         CheckFloat4Val(result,isinf(arg1) || isinf(arg2));
>         PG_RETURN_FLOAT4((float4) result);
> }

Are you sure?  As I remember, computation automatically upgrades to
'double'.  See this program and output:

    $ cat tst1.c
    #include <stdio.h>
    #include <stdlib.h>

    int
    main(int argc, char *argv[])
    {
            float a = 1e30, b = 1e30;
            double c;

            c = a * b;

            printf("%e\n", c);
            return 0;
    }

    $  tst1
    1.000000e+60

--
  Bruce Momjian   bruce@momjian.us
  EnterpriseDB    http://www.enterprisedb.com

  + If your life is a hard drive, Christ can be your backup. +

Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows,

From
Roman Kononov
Date:
On 12/27/2006 03:23 PM, Bruce Momjian wrote:
> Are you sure?  As I remember, computation automatically upgrades to
> 'double'.  See this program and output:

This is platform- and compiler- dependent:

~>uname -a
Linux rklinux 2.6.15-27-amd64-generic #1 SMP PREEMPT Fri Dec 8 17:50:54 UTC 2006 x86_64 GNU/Linux
~>gcc --version
gcc (GCC) 4.3.0 20061213 (experimental)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

~>cat test.c
#include <stdio.h>
#include <stdlib.h>

int
main(int argc, char *argv[])
{
    float a = 1e30, b = 1e30;
    double c;

    c = a * b;

    printf("%e\n", c);
    return 0;
}
~>gcc test.c
~>./a.out
inf
~>gcc -march=i386 -m32 test.c
~>./a.out
1.000000e+60

Roman

Re: [BUGS] BUG #2846: inconsistent and confusing handling of

From
Bruce Momjian
Date:
Roman Kononov wrote:
> On 12/27/2006 03:23 PM, Bruce Momjian wrote:
> > Are you sure?  As I remember, computation automatically upgrades to
> > 'double'.  See this program and output:
>
> This is platform- and compiler- dependent:
>
> ~>uname -a
> Linux rklinux 2.6.15-27-amd64-generic #1 SMP PREEMPT Fri Dec 8 17:50:54 UTC 2006 x86_64 GNU/Linux
> ~>gcc --version
> gcc (GCC) 4.3.0 20061213 (experimental)
> Copyright (C) 2006 Free Software Foundation, Inc.
> This is free software; see the source for copying conditions.  There is NO
> warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
>
> ~>cat test.c
> #include <stdio.h>
> #include <stdlib.h>
>
> int
> main(int argc, char *argv[])
> {
>     float a = 1e30, b = 1e30;
>     double c;
>
>     c = a * b;
>
>     printf("%e\n", c);
>     return 0;
> }
> ~>gcc test.c
> ~>./a.out
> inf
> ~>gcc -march=i386 -m32 test.c
> ~>./a.out
> 1.000000e+60

Interesting.  I didn't know that, but in the float4pl() function,
because the overflow tests and result is float4, what value is there to
doing things as double --- as soon as the float4 maximum is exceeded, we
throw an error?

--
  Bruce Momjian   bruce@momjian.us
  EnterpriseDB    http://www.enterprisedb.com

  + If your life is a hard drive, Christ can be your backup. +

Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows,

From
Roman Kononov
Date:
On 12/27/2006 04:04 PM, Bruce Momjian wrote:
> Interesting.  I didn't know that, but in the float4pl() function,
> because the overflow tests and result is float4, what value is there to
> doing things as double --- as soon as the float4 maximum is exceeded, we
> throw an error?
>

This is useful for underflows.

    float a=1e-30;
    float b=1e-30;
    double r1=a*b;
    double r2=(double)a*b;

r1 is zero and underflow is lost.
r2 is not zero and underflow is detected.

In float4mul() and float4div(), the computation should be double precision.

In float4pl() and float4mi(), it depends on the ability of the hardware
to generate denormalized numbers. If denormalized numbers are generated,
float vs double makes no difference. If denormalized numbers are not
generated (zero is generated), then double computation is safer.

Another way to detect underflows, overflows and other junk is to use FPU
status flags after each computation. Performance will likely suffer.

#include <fenv.h>

Datum
float4mul(PG_FUNCTION_ARGS)
{
     float4   arg1 = PG_GETARG_FLOAT4(0);
     float4   arg2 = PG_GETARG_FLOAT4(1);
     float4   result;
     int fe_exceptions;
     feclearexcept(FE_ALL_EXCEPT);
     result = arg1 * arg2;
     fe_exceptions=fetestexcept(FE_DIVBYZERO,FE_INVALID,FE_OVERFLOW,FE_UNDERFLOW);
     if (fe_exceptions) handle_exceptions(fe_exceptions); //??
     PG_RETURN_FLOAT4(result);
}

Yet another way to detect exceptions is to remove all CheckFloat4Val(),
CheckFloat8Val(), isnan(), unmask FPU exceptions and install an exception handler.
Might have portability difficulties. Comparisons of NaNs must be done in
non-IEEE way (FPU does not compare NaNs, it generates exceptions).

Roman


Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows,

From
Tom Lane
Date:
Roman Kononov <kononov195-pgsql@yahoo.com> writes:
> On 12/27/2006 03:23 PM, Bruce Momjian wrote:
>> Are you sure?  As I remember, computation automatically upgrades to
>> 'double'.  See this program and output:

> This is platform- and compiler- dependent:

... and probably irrelevant, too.  We should store the result into a
float4 variable and then test for isinf() on that; that eliminates the
question of whether the compiler did the multiply in a wider format or
not.

            regards, tom lane

Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows,

From
Tom Lane
Date:
Roman Kononov <kononov195-pgsql@yahoo.com> writes:
> In float4mul() and float4div(), the computation should be double precision.

Why?  It's going to have to fit in a float4 eventually anyway.

            regards, tom lane

Re: [BUGS] BUG #2846: inconsistent and confusing handling

From
Roman Kononov
Date:
On 12/27/2006 05:19 PM, Tom Lane wrote:
> Roman Kononov <kononov195-pgsql@yahoo.com> writes:
>> On 12/27/2006 03:23 PM, Bruce Momjian wrote:
>>> Are you sure?  As I remember, computation automatically upgrades to
>>> 'double'.  See this program and output:
>
>> This is platform- and compiler- dependent:
>
> ... and probably irrelevant, too.  We should store the result into a
> float4 variable and then test for isinf() on that; that eliminates the
> question of whether the compiler did the multiply in a wider format or
> not.

You are right provided that you want to ignore underflows and silently
produce zeros instead.

If you go this way, I recommend to ignore overflows as well, and silently
produce infinities and NaNs.

Roman

Re: [BUGS] BUG #2846: inconsistent and confusing

From
Bruce Momjian
Date:
Tom Lane wrote:
> Roman Kononov <kononov195-pgsql@yahoo.com> writes:
> > In float4mul() and float4div(), the computation should be double precision.
>
> Why?  It's going to have to fit in a float4 eventually anyway.

One issue is in the patch comment:

    !    *  Computations that slightly exceed FLOAT8_MAX are non-Infinity,
    !    *  but those that greatly exceed FLOAT8_MAX become Infinity.  Therefore
    !    *  it is difficult to tell if a value is really infinity or the result
    !    *  of an overflow.  The solution is to use a boolean indicating if
    !    *  the input arguments were infiity, meaning an infinite result is
    !    *  probably not the result of an overflow.  This allows various
    !    *  computations like SELECT 'Inf'::float8 + 5.

    +    *  Underflow has similar issues to overflow, i.e. if a computation is
    +    *  slighly smaller than FLOAT8_MIN, the result is non-zero, but if it is
    +    *  much smaller than FLOAT8_MIN, the value becomes zero.  However,
    +    *  unlike overflow, zero is not a special value and can be the result
    +    *  of a computation, so there is no easy way to pass a boolean
    +    *  indicating whether a zero result is reasonable or not.  It might
    +    *  be possible for multiplication and division, but because of rounding,
    +    *  such tests would probably not be reliable.

For overflow, it doesn't matter, but by using float8, you have a much
larger range until you underflow to zero.  I will make adjustments to
the patch to use this, and add comments explaining its purpose.

--
  Bruce Momjian   bruce@momjian.us
  EnterpriseDB    http://www.enterprisedb.com

  + If your life is a hard drive, Christ can be your backup. +

Re: [BUGS] BUG #2846: inconsistent and confusing

From
Bruce Momjian
Date:
Tom Lane wrote:
> Roman Kononov <kononov195-pgsql@yahoo.com> writes:
> > On 12/27/2006 03:23 PM, Bruce Momjian wrote:
> >> Are you sure?  As I remember, computation automatically upgrades to
> >> 'double'.  See this program and output:
>
> > This is platform- and compiler- dependent:
>
> ... and probably irrelevant, too.  We should store the result into a
> float4 variable and then test for isinf() on that; that eliminates the
> question of whether the compiler did the multiply in a wider format or
> not.

True for overflow to Infinity, but underflow checking is better for
float4 using float8.  See previous email for details.

--
  Bruce Momjian   bruce@momjian.us
  EnterpriseDB    http://www.enterprisedb.com

  + If your life is a hard drive, Christ can be your backup. +

Re: [BUGS] BUG #2846: inconsistent and confusing

From
Bruce Momjian
Date:
Roman Kononov wrote:
> On 12/27/2006 05:19 PM, Tom Lane wrote:
> > Roman Kononov <kononov195-pgsql@yahoo.com> writes:
> >> On 12/27/2006 03:23 PM, Bruce Momjian wrote:
> >>> Are you sure?  As I remember, computation automatically upgrades to
> >>> 'double'.  See this program and output:
> >
> >> This is platform- and compiler- dependent:
> >
> > ... and probably irrelevant, too.  We should store the result into a
> > float4 variable and then test for isinf() on that; that eliminates the
> > question of whether the compiler did the multiply in a wider format or
> > not.
>
> You are right provided that you want to ignore underflows and silently
> produce zeros instead.
>
> If you go this way, I recommend to ignore overflows as well, and silently
> produce infinities and NaNs.

While IEEE seems fine with that, I don't think this is good for SQL.  It
is best to produce a meaningful error.  The major issue is that our
current code is buggy because it doesn't have consistent behavior, as
Roman outlined.

--
  Bruce Momjian   bruce@momjian.us
  EnterpriseDB    http://www.enterprisedb.com

  + If your life is a hard drive, Christ can be your backup. +