Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 12 Aug 2012 23:06:37 -0000
From:      Stephen Montgomery-Smith <stephen@missouri.edu>
To:        Bruce Evans <brde@optusnet.com.au>
Cc:        Diane Bruce <db@db.net>, John Baldwin <jhb@freebsd.org>, David Chisnall <theraven@freebsd.org>, Bruce Evans <bde@freebsd.org>, Steve Kargl <sgk@troutmask.apl.washington.edu>, David Schultz <das@freebsd.org>, Peter Jeremy <peter@rulingia.com>, Warner Losh <imp@bsdimp.com>
Subject:   Re: Use of C99 extra long double math functions after r236148
Message-ID:  <5006D13D.2080702@missouri.edu>
Resent-Message-ID: <20120812230630.GZ20453@server.rulingia.com>
In-Reply-To: <20120717200931.U6624@besplex.bde.org>
References:  <20120529045612.GB4445@server.rulingia.com> <20120711223247.GA9964@troutmask.apl.washington.edu> <20120713114100.GB83006@server.rulingia.com> <201207130818.38535.jhb@freebsd.org> <9EB2DA4F-19D7-4BA5-8811-D9451CB1D907@theravensnest.org> <C527B388-3537-406F-BA6D-2FA45B9EAA3B@FreeBSD.org> <20120713155805.GC81965@zim.MIT.EDU> <20120714120432.GA70706@server.rulingia.com> <20120717084457.U3890@besplex.bde.org> <5004A5C7.1040405@missouri.edu> <5004DEA9.1050001@missouri.edu> <20120717200931.U6624@besplex.bde.org>

next in thread | previous in thread | raw e-mail | index | archive | help
I went on a long road trip yesterday, so I didn't get any code written, 
but I did have a lot of thoughts about clog and casinh.

First, the naive formula (here z=x+I*y)
clog(z) = cpack(log(hypot(x,y)),atan2(x,y))
is going to work in a lot more edge cases then one might expect.  This 
is because hypot and atan2, especially atan2, already do a rather good 
job getting the edge cases right.  I am thinking in particular of when x 
or y are 0 or -0, or one of them is infinity or -infinity.

So writing this code will be quite a bit easier than I was expecting. 
It looks like I will just have to worry about when both x and y are 
infinite, or when one or both of them are nan.


Next, concerning casinh:

On 07/17/2012 06:13 AM, Bruce Evans wrote:

> I translated this to pari.  There was a sign error for the log() term
> (assuming that pari asinh() has the same branch cuts as C99):

I couldn't spot which sign error Bruce had changed.  However I expect it 
has something to do with what happens when x=0 and fabs(y)>1.  This is 
the reasonable choice of the branch cut.  What I think the value should 
be is

casinh(z) = cpack(
signum(x)*sqrt(fabs(y)+sqrt(y^2-1)),
signum(y)*PI)

where the value of signum(x) depends on whether x is 0 or -0.

(I might add that I checked against the Mathematica ArcSinh function, 
and this does NOT follow the above rule.  But the document Steve pointed 
me to says that
casinh(conj(z)) = conj(casinh(z))
which means that we cannot follow the Mathematica conventions.)

> The most obvious immediate difficulty in translating the above into C is
> that y*y and z*z may overflow when the result shouldn't.

This will be a lot easier than I originally expected.  When we are in 
conditions when overflow might occur, we can simply make the approximations
sqrt(y*y-1) = y
csqrt(z*z+1) = signum(x)*z
because in floating point arithmetic, these will not be approximations, 
but true exactly.  And I am thinking that the test I will use for when 
to use these approximations will be (y==y+1) and (z==z+1) respectively. 
  (I would use (z*z==z*z+1) but that test has the overflow problem.)

Finally, I want to tell you guys that the reason I used the code:

if (x>0)
    return clog(z+csqrt(z*z+1));
  else
    return -clog(-z+csqrt(z*z+1));

is this.  Both formulas are mathematically exactly the same.  This is 
true even if one takes into account the branch cuts for csqrt and clog. 
  The difference between the two formulas is numerical errors.  For 
example, if x<0 and z has very large magnitude, then csqrt(z*z+1) will 
be very close to -z.  In fact in floating point arithmetic, if the 
magnitude of z is sufficiently large, they will be the same.

However, as I am typing this, I realize that the code should really be

if (w!=z+1) {
   w = z*z+1;
   if (signum(creal(w))==1)
     return clog(z+csqrt(w));
   else
     return -clog(-z+csqrt(w));
} else /* if (z==z+1) */ {
   if (x>0)
     return clog(2*z);
   else
     return -clog(-2*z);
}

where the signum function is defined so that signum(0)==1 and signum(-0)=-1.


Next: cacosh and cacos.  I had presumed the formula
cacosh(z) = I*cacos(z)
which can be true depending on how one defines the branch cuts.  But 
this formula won't satisfy the C99 standard which mandates
cacosh(conj(z)) = conj(cacosh(z))
That is why in earlier posts I thought there was a mistake in the online 
documentation, and the range of outputs of cacosh should satisfy 
imaginary part in [0,pi] rather than [-pi,pi].


Anyway, I am just posting this update so that you see I am thinking 
about it.  I might get the project done in days, but it might also be 
months.  It depends upon how much other stuff I have going on.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?5006D13D.2080702>