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>
index | next in thread | previous in thread | raw e-mail
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.
help
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?5057A932.3000603>
