Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 17 Sep 2012 17:50:26 -0500
From:      Stephen Montgomery-Smith <stephen@missouri.edu>
To:        Bruce Evans <brde@optusnet.com.au>
Cc:        freebsd-numerics@freebsd.org
Subject:   Re: Complex arg-trig functions
Message-ID:  <5057A932.3000603@missouri.edu>
In-Reply-To: <20120918012459.V5094@besplex.bde.org>
References:  <5017111E.6060003@missouri.edu> <502C0CF8.8040003@missouri.edu> <20120906221028.O1542@besplex.bde.org> <5048D00B.8010401@missouri.edu> <504D3CCD.2050006@missouri.edu> <504FF726.9060001@missouri.edu> <20120912191556.F1078@besplex.bde.org> <20120912225847.J1771@besplex.bde.org> <50511B40.3070009@missouri.edu> <20120913204808.T1964@besplex.bde.org> <5051F59C.6000603@missouri.edu> <20120914014208.I2862@besplex.bde.org> <50526050.2070303@missouri.edu> <20120914212403.H1983@besplex.bde.org> <50538E28.6050400@missouri.edu> <20120915231032.C2669@besplex.bde.org> <50548E15.3010405@missouri.edu> <5054C027.2040008@missouri.edu> <5054C200.7090307@missouri.edu> <20120916041132.D6344@besplex.bde.org> <50553424.2080902@missouri.edu> <20120916134730.Y957@besplex.bde.org> <5055ECA8.2080008@missouri.edu> <20120917022614.R2943@besplex.bde.org> <50562213.9020400@missouri.edu> <20120917060116.G3825@besplex.bde.org> <50563C57.60806@missouri.edu> <20120918012459.V5094@besplex.bde.org>

next in thread | previous in thread | raw e-mail | index | archive | help
OK, I am struggling a bit with the latest suggestions.

First, I have completely removed all the code related to when |z| is 
small.  I have just lost it all.  So I didn't perform any changes 
related to that code.  If you want me to put it back with appropriate 
"#if 0", can you email those code segments back to me?

On 09/17/2012 12:07 PM, Bruce Evans wrote:

> @ @@ -321,30 +334,28 @@
> @      }
> @ @ -    if (isinf(x) || isinf(y))
> @ -        return (cpackf(copysignf(0, x), copysignf(m_pi_2 + tiny, y)));
> @ +    /* Raise inexact unless z == 0; return for z == 0 as a side
> effect. */
> @ +    if ((x == 0 && y == 0) || (int)(1 + tiny) != 1)
> @ +        return (z);

I'm not too sure where this code is meant to be.  It looks like it 
should be part of testing |z| small, but it seems to be placed where |z| 
is large.  When |z| is large, z=0 will never happen.

> cacos*() and casin*() should benefit even more from an up-front raising
> of inexact, since do_hard_work() has 7 magic statements to raise inexact
> where sum_squares has only 1.

Where is the code that raises inexact up-front?

> There are no magic expressions (int)(1+tiny) left except the new up-front
> one.  There are still not-so- magic expressions (m_pi_2 + tiny).  BTW,
> most or all of the recent fixes to use the latter expressions don't
> have a comment about raising inexact in catrig.c, while most or all
> older expressions for setting inexact do have such a comment.

I put the comments in.


> Previous optimization not turned off for debugging.  It is simpler now
> that it can depend on inexact being raised up-front.

Ditto.  Which code turns on inexact up front?

> @      } else
> @          rx = log1pf(4*ax / sum_squares(ax-1, ay)) / 4;
> @ @ -    if (ax == 1) {
> @ -        if (ay==0)
> @ -            ry = 0;
> @ -        else
> @ -            ry = atan2f(2, -ay) / 2;
> @ -    } else if (ay < FOUR_SQRT_MIN) {
> @ -        if ((int)ay==0)
> @ -            ry = atan2f(2*ay, (1-ax)*(1+ax)) / 2;
> @ -    } else
> @ +    if (ax == 1)
> @ +        ry = atan2f(2, ay) / 2;
> @ +    else if (ay < FOUR_SQRT_MIN)
> @ +        ry = atan2f(2*ay, (1-ax)*(1+ax)) / 2;
> @ +    else
> @          ry = atan2f(2*ay, (1-ax)*(1+ax) - ay*ay) / 2;
> @
>
> Remove the special case for (ax == 1, ay == 0).  The general case gives
> the same result.

I don't think your code works.  It should be ry = atan2f(2, -ay) / 2, 
not ry = atan2f(2, ay) / 2.

In your tests, you should include cases where x or y is equal or close 
to 1.  These are important special cases that I think your test code is 
very unlikely to hit.  These are difficult edge cases for all the 
arc-trig functions.

> Remove negation of ay for ax == 1.  The sign will be copied into the result
> later for all cases, so it doesn't matter in the arg.  I didn't check the
> branch cut details for this, but runtime tests passed.

See above.

> ...  I now understand what the threshold should be.  You have
> filtered out ax == 1.  This makes 1 - ax*ax at least ~2*EPSILON, so
> ay*ay can be dropped if ay is less than sqrt(2*EPSILON*EPSILON) *
> 2**-GUARD_DIGITS = EPSILON * 2**-5 say.  SQRT_MIN is way smaller
> than that, so FOUR_SQRT_MIN works too.  We should use a larger
> threshold for efficiency, or avoid the special case for ax == 1.
> Testing shows that this analysis is off by a factor of about
> sqrt(EPSILON), since a threshold of EPSILON * 2**7 is optimal.
> The optimization made no difference to speed; it is just an
> optimization for understanding.  Maybe the special case for ax == 1
> can be avoided, or folded together with the same special case for
> evaluation of the real part.  This special case is similar to the
> one in clog(), but easier.

This was one of the clever ideas in the paper by Hull et al, which I 
only understood recently.  Their code was closer to your approach, I think.

Let me think about what you wrote some more.

>
> Further optimization: in sum_squares(), y is always ay >= 0, so there
> is no need to apply fabs*() to it.  I think the compiler does this
> optimization.  It can see that y == ay via the inline.

Well spotted.




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?5057A932.3000603>