Re: [HACKERS] [PATCH] Improve geometric types - Mailing list pgsql-hackers

From Kyotaro HORIGUCHI
Subject Re: [HACKERS] [PATCH] Improve geometric types
Date
Msg-id 20171003.173906.235933967.horiguchi.kyotaro@lab.ntt.co.jp
Whole thread Raw
In response to Re: [HACKERS] [PATCH] Improve geometric types  (Robert Haas <robertmhaas@gmail.com>)
List pgsql-hackers
At Mon, 2 Oct 2017 08:23:49 -0400, Robert Haas <robertmhaas@gmail.com> wrote in
<CA+TgmoYsgw0TcjJQ1CE_6vDOxgEhxYQkfNx93Mfwx23WOLM0NA@mail.gmail.com>
> On Mon, Oct 2, 2017 at 4:23 AM, Kyotaro HORIGUCHI
> <horiguchi.kyotaro@lab.ntt.co.jp> wrote:
> > For other potential reviewers:
> >
> > I found the origin of the function here.
> >
> > https://www.postgresql.org/message-id/4A90BD76.7070804@netspace.net.au
> > https://www.postgresql.org/message-id/AANLkTim4cHELcGPf5w7Zd43_dQi_2RJ_b5_F_idSSbZI%40mail.gmail.com
> >
> > And the reason for pg_hypot is seen here.
> >
> > https://www.postgresql.org/message-id/407d949e0908222139t35ad3ad2q3e6b15646a27dd64@mail.gmail.com
> >
> > I think the replacement is now acceptable according to the discussion.
> > ======
> 
> I think if we're going to do this it should be separated out as its
> own patch.

+1

>             Also, I think someone should explain what the reasoning
> behind the change is.  Do we, for example, foresee that the built-in
> code might be faster or less likely to overflow?  Because we're
> clearly taking a risk -- most trivially, that the BF will break, or
> more seriously, that some machines will have versions of this function
> that don't actually behave quite the same.
> 
> That brings up a related point.  How good is our test case coverage
> for hypot(), especially in strange corner cases, like this one
> mentioned in pg_hypot()'s comment:
> 
>  * This implementation conforms to IEEE Std 1003.1 and GLIBC, in that the
>  * case of hypot(inf,nan) results in INF, and not NAN.

I'm not sure how precise we practically need them to be
identical.  FWIW as a rough confirmation on my box, I compared
hypot and pg_hypot for the following arbitrary choosed pairs of
parameters.

{2.2e-308, 2.2e-308},{2.2e-308, 1.7e307},{1.7e307, 1.7e307},{1.7e308, 1.7e308},{2.2e-308, DBL_MAX},{1.7e308,
DBL_MAX},{DBL_MIN,DBL_MAX},{DBL_MAX, DBL_MAX},{1.7e307, INFINITY},{2.2e-308, INFINITY},{0, INFINITY},{DBL_MIN,
INFINITY},{INFINITY,INFINITY},{1, NAN},{INFINITY, NAN},{NAN, NAN},
 


Only the first pair gave slightly not-exactly-equal results but
it seems to do no harm. hypot set underflow flag.
0: hypot=3.111269837220809e-308 (== 0.0 is 0, < DBL_MIN is 0)  pg_hypot=3.11126983722081e-308 (== 0.0 is 0, < DBL_MIN
is0)  equal=0,  hypot(errno:0, inval:0, div0:0, of=0, uf=1),  pg_hypot(errno:0, inval:0, div0:0, of=0, uf=0)
 

But not sure how the both functions behave on other platforms.

> I'm potentially willing to commit a patch that just makes the
> pg_hypot() -> hypot() change and does nothing else, if there are not
> objections to that change, but I want to be sure that we'll know right
> away if that turns out to break.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
#include <stdio.h>
#include <float.h>
#include <math.h>
#include <fenv.h>
#include <errno.h>

double
pg_hypot(double x, double y)
{double        yx;
/* Handle INF and NaN properly */if (isinf(x) || isinf(y))    return (double) INFINITY;
if (isnan(x) || isnan(y))    return (double) NAN;
/* Else, drop any minus signs */x = fabs(x);y = fabs(y);
/* Swap x and y if needed to make x the larger one */if (x < y){    double        temp = x;
    x = y;    y = temp;}
/* * If y is zero, the hypotenuse is x.  This test saves a few cycles in * such cases, but more importantly it also
protectsagainst * divide-by-zero errors, since now x >= y. */if (y == 0.0)    return x;
 
/* Determine the hypotenuse */yx = y / x;return x * sqrt(1.0 + (yx * yx));
}

void
setfeflags(int *invalid, int *divzero, int *overflow, int *underflow)
{int err = fetestexcept(FE_INVALID | FE_DIVBYZERO |                       FE_OVERFLOW | FE_UNDERFLOW);*invalid = ((err
&FE_INVALID) != 0);*divzero = ((err & FE_DIVBYZERO) != 0);*overflow = ((err & FE_OVERFLOW) != 0);*underflow = ((err &
FE_UNDERFLOW)!= 0);
 
}

int
main(void)
{double x;double y;double p[][2] =    {        {2.2e-308, 2.2e-308},        {2.2e-308, 1.7e307},        {1.7e307,
1.7e307},       {1.7e308, 1.7e308},        {2.2e-308, DBL_MAX},        {1.7e308, DBL_MAX},        {DBL_MIN, DBL_MAX},
    {DBL_MAX, DBL_MAX},        {1.7e307, INFINITY},        {2.2e-308, INFINITY},        {0, INFINITY},        {DBL_MIN,
INFINITY},       {INFINITY, INFINITY},        {1, NAN},        {INFINITY, NAN},        {NAN, NAN},        {0.0, 0.0}
};inti;
 

for (i = 0 ; p[i][0] != 0.0 || p[i][1] != 0.0 ; i++){    int errno1, errno2;    int invalid1 = 0, divzero1 = 0,
overflow1= 0, underflow1 = 0;    int invalid2 = 0, divzero2 = 0, overflow2 = 0, underflow2 = 0;    int cmp;
 
    errno = 0;    feclearexcept(FE_ALL_EXCEPT);    x = hypot(p[i][0], p[i][1]);    errno1 = errno;
setfeflags(&invalid1,&divzero1, &overflow1, &underflow1);
 
    errno = 0;    feclearexcept(FE_ALL_EXCEPT);    y = pg_hypot(p[i][0], p[i][1]);    errno2 = errno;
setfeflags(&invalid2,&divzero2, &overflow2, &underflow2);
 
    /* assume NaN == NaN here */    if (isnan(x) && isnan(y))        cmp = 1;    else        cmp = (x == y);
    printf("%d: hypot=%.16lg (== 0.0 is %d, < DBL_MIN is %d)\n  pg_hypot=%.16lg (== 0.0 is %d, < DBL_MIN is %d)\n
equal=%d,hypot(errno:%d, inval:%d, div0:%d, of=%d, uf=%d), pg_hypot(errno:%d, inval:%d, div0:%d, of=%d, uf=%d)\n",
    i, x, x == 0.0, x < DBL_MIN, y, y == 0.0, y < DBL_MIN, cmp,           errno1, invalid1, divzero1, overflow1,
underflow1,          errno2, invalid2, divzero2, overflow2, underflow2);}return 0;
 
}

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

pgsql-hackers by date:

Previous
From: Andres Freund
Date:
Subject: Re: [HACKERS] 64-bit queryId?
Next
From: Nick Dro
Date:
Subject: [HACKERS] Postgresql gives error that role goes not exists while it exists