Complex arg-trig functions

Stephen Montgomery-Smith stephen at missouri.edu
Wed Aug 15 20:56:26 UTC 2012


On 08/15/2012 08:35 AM, Bruce Evans wrote:
> On Tue, 14 Aug 2012, Stephen Montgomery-Smith wrote:


>> It seemed to me that there is a logic behind why the the infs and nans
>> produce the results they do.  I noticed that do_the_hard_work()
>> already got the answers correct for the real part *rx.  Getting the
>> imaginary part to work as well seemed to me to be the cleanest way to
>> make it work.  (I added all the nan and inf checking after writing the
>> rest of the code.)
>
> An up-front check may still be simpler, and gives more control.  In
> csqrt*(), I needed an explicit check and special expressions to get
> uniform behaviour.

I still like it the way I have it.  There is a definite logic in the way 
infs and nans come out of casinh, etc.

There is only one place I disagree with C99:
catanh(1) = Inf + 0*I

I think mpc gets it correct:
atanh(1) = Inf + nan*I


> I added this to the NaN mixing in catan[h]*(),
> and now all my tests pass:
>
> % diff -c2 catrig.c~ catrig.c
> % *** catrig.c~    Sun Aug 12 17:29:18 2012
> % --- catrig.c    Wed Aug 15 11:57:02 2012
> % ***************
> % *** 605,609 ****
> %        */
> %       if (ISNAN(x) || ISNAN(y))
> % !         return (cpack(x+y, x+y));
> % %       /* (x,inf) and (inf,y) and (inf,inf) -> (0,PI/2) */
> % --- 609,613 ----
> %        */
> %       if (ISNAN(x) || ISNAN(y))
> % !         return (cpack((x+0.0L)+(y+0), (x+0.0L)+(y+0)));
> % %       /* (x,inf) and (inf,y) and (inf,inf) -> (0,PI/2) */
>
> Use this expression in all precisions.


Would this work?

        if (ISNAN(x) || ISNAN(y))
                 return (cpack((x+x)+(y+y), (x+x)+(y+y)));


>
> I forgot to comment it.  Adding 0 quietens signaling NaNs before mixing
> NaNs.  I should have tried y+y.  Adding 0.0L promotes part of the
> expression to long double together with quietening signaling NaNs.
> The rest of the expression is promoted to match.  I should try the
> old way again: of (long double)x+x.
>
> % diff -c2 catrigf.c~ catrigf.c
> % *** catrigf.c~    Sun Aug 12 17:00:52 2012
> % --- catrigf.c    Wed Aug 15 11:57:08 2012
> % ***************
> % *** 349,353 ****
> % %       if (isnan(x) || isnan(y))
> % !         return (cpackf(x+y, x+y));
> % %       if (isinf(x) || isinf(y))
> % --- 351,355 ----
> % %       if (isnan(x) || isnan(y))
> % !         return (cpack((x+0.0L)+(y+0), (x+0.0L)+(y+0)));
> % %       if (isinf(x) || isinf(y))
> % diff -c2 catrigl.c~ catrigl.c
> % *** catrigl.c~    Sun Aug 12 06:54:46 2012
> % --- catrigl.c    Wed Aug 15 11:58:46 2012
> % ***************
> % *** 323,327 ****
> % %       if (isnan(x) || isnan(y))
> % !         return (cpackl(x+y, x+y));
> % %       if (isinf(x) || isinf(y))
> % --- 325,329 ----
> % %       if (isnan(x) || isnan(y))
> % !         return (cpack((x+0.0L)+(y+0), (x+0.0L)+(y+0)));
> % %       if (isinf(x) || isinf(y))
> % Index: ../s_csqrt.c
> % ===================================================================
> % RCS file: /home/ncvs/src/lib/msun/src/s_csqrt.c,v
> % retrieving revision 1.4
> % diff -u -2 -r1.4 s_csqrt.c
> % --- ../s_csqrt.c    8 Aug 2008 00:15:16 -0000    1.4
> % +++ ../s_csqrt.c    14 Aug 2012 20:34:07 -0000
> % @@ -34,14 +34,5 @@
> %  #include "math_private.h"
> % % -/*
> % - * gcc doesn't implement complex multiplication or division correctly,
> % - * so we need to handle infinities specially. We turn on this pragma to
> % - * notify conforming c99 compilers that the fast-but-incorrect code that
> % - * gcc generates is acceptable, since the special cases have already
> been
> % - * handled.
> % - */
> % -#pragma    STDC CX_LIMITED_RANGE    ON
>
> Remove this.  There was only 1 complex expression, and it depended on the
> negation of this pragma to work.  Since gcc doesn't support this pragma,
> the expression only worked accidentally when it was optimized.

I removed it.  (I copied it verbatim from csqrt without really 
understanding it.)




The part that follows - is this all referencing csqrt?

>
> % -
> % -/* We risk spurious overflow for components >= DBL_MAX / (1 +
> sqrt(2)). */
> % +/* For avoiding overflow for components >= DBL_MAX / (1 + sqrt(2)). */
> %  #define    THRESH    0x1.a827999fcef32p+1022
>
>
>   ..............   snip


> This is like a fix in clog().  hypot() handles denormals OK, but
> necessarily loses accuracy when it returns a denormal result, so
> the expression (a + hypot(a, b)) is more inaccurate than necessary.

Which code is being referenced here?  I use expressions like this 
catrig.  Although I think when I use it, I am somewhat certain that 
neither a nor b are denormal.




More information about the freebsd-numerics mailing list