Re: Wrong formulae for complex elementary functions

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello Richard,

On Fri, Aug 5, 2011 at 11:34 PM, Richard B. Kreckel <kreckel@xxxxxxxx> wrote:
> Hi everybody,
>
> On 11/27/2010 08:37 AM, Michael Kerrisk wrote:
>>
>> Hi Andries,
>>
>> Since you are the mathematician, can you comment?
>>
>> Thanks,
>>
>> Michael
>>
>> On Fri, Nov 26, 2010 at 9:57 AM, Richard B. Kreckel<kreckel@xxxxxxxx>
>>  wrote:
>>>
>>> Hi!
>>>
>>> The man pages for cacos, cacosf, cacosl, catan, catanf, catanl, cacosh,
>>> cacoshf, cacoshl, catanh, catanhf, and catanhl contain wrong maths.
>>>
>>> cacos, cacosf, cacosl:
>>>  The formula given in the man page
>>>    cacos(z) = -i clog(z + csqrt(z * z - 1))
>>>  gives wrong results in second and fourth quadrant of complex plain.
>>>  The formula
>>>    cacos(z) = -i clog(z + I*csqrt(1 - z * z))
>>>  gives correct results.
>>>
>>> catan, catanf, catanl:
>>>  The formula given in the man page
>>>    catan(z) = 1 / 2i clog((1 + iz) / (1 - iz))
>>>  gives wrong results on the negative imaginary axis beginning at -I
>>>  (along one of the two branch cuts). Besides, the formula is written
>>>  in an ambiguous way.
>>>  The formula
>>>    catan(z) = (clog(1 + iz) - clog(1 - iz)) / 2i
>>>  gives correct results.
>>>
>>> cacosh, cacoshf, cacoshl:
>>>  The formula given in the man page
>>>    cacosh(z) = (0.5) * clog((1 + z) / (1 - z))
>>>  gives wrong results everywhere in the complex plain. (The formula
>>>  seems to be copied from the one for catanh, where it is sometimes
>>>  correct.)
>>>  The formula
>>>    cacosh(z) = 2 * clog(csqrt((z + 1)/2) + csqrt((z - 1)/2))
>>>  gives correct results.
>>>
>>> catanh, catanhf, catanhl:
>>>  The formula given in the man page
>>>    catanh(z) = 0.5 * clog((1 + z) / (1 - z))
>>>  gives wrong results on the positive real axis beginning at 1 (along
>>>  one of the two branch cuts).
>>>  The formula
>>>    catanh(z) = 0.5 * (clog(1 + z) - clog(1 - z))
>>>  gives correct results.
>>>
>>> I've also checked casin, casinf, casinl, casinh, casinhf, and casinhl and
>>> the formulae given there
>>>    casin(z) = -i clog(iz + csqrt(1 - z * z))
>>>    casinh(z) = clog(z + csqrt(z * z + 1))
>>> are actually correct.
>>>
>>> I suspect that some of these errors are due to somebody trying to
>>> "simplify"
>>> these formulae. Since this can ruin the behavior, I recommend to add a
>>> comment to the upstream sources that warns against attempt of
>>> simplification.
>>>
>>> For the sake of reference, I am looking at manpages-dev 3.25-1 on
>>> Debian/squeeze.
>>>
>>> Bye!
>>>  -richy.
>>> --
>>> Richard B. Kreckel
>>> <http://www.ginac.de/~kreckel/>
>
> This doesn't have seem to have been fixed in the Linux man pages, does it?

Sorry -- no, not yet.

> May I suggest a non-mathematical approach to moving forward?
>
> Just write a little C program and compare the complex results of
> a) the library implementation of catan, cacos, etc.,
> b) the formula written in the man page, and
> c) the formula I proposed above.
> If you include a couple of values from all four quadrants, you'll see that
> my formula always agrees with the implementation while the one from the man
> page doesn't.

Now there's a good idea ;-). It would have been even better if you'd
sent me a program--I don't mess round with complex numbers every day
of the week...

> Is there anything else I can do to convince you that this should be fixed?
> If yes, pretty please, let me know! I would really appreciate getting this
> fixed.

So, I eventually ironed out my complex math problems and came up with the below:

===
/* Link with "-lm" */

#include <complex.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>



int
main(int argc, char *argv[])
{
    double complex z, c, f1, f2;
    double complex i = I;

    if (argc != 3) {
        fprintf(stderr, "Usage: %s <real> <imag>\n");
        exit(EXIT_FAILURE);
    }

    z = atof(argv[1]) + atof(argv[2]) * I;

    c = cacos(z);

    printf("cacos() = %6.3f %6.3f*i\n", creal(c), cimag(c));

    f1 = -i * clog(z + csqrt(z * z - 1));
    f2 = -i * clog(z + i * csqrt(1 - z * z));

    printf("f1      = %6.3f %6.3f*i\n", creal(f1), cimag(f1));
    printf("f2      = %6.3f %6.3f*i\n", creal(f2), cimag(f2));

    exit(EXIT_SUCCESS);
}
===

Some sample runs certainly seem to prove your point for that function at least:

$ ./cacos 1 1
cacos() =  0.905 -1.061*i
f1      =  0.905 -1.061*i
f2      =  0.905 -1.061*i
$ ./cacos -1 -1
cacos() =  2.237  1.061*i
f1      =  2.237  1.061*i
f2      =  2.237  1.061*i
$ ./cacos -1 1
cacos() =  2.237 -1.061*i
f1      = -2.237  1.061*i
f2      =  2.237 -1.061*i
$ ./cacos 1 -1
cacos() =  0.905  1.061*i
f1      = -0.905 -1.061*i
f2      =  0.905  1.061*i

The above is what you meant, right?

Thanks,

Michael

-- 
Michael Kerrisk
Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
Author of "The Linux Programming Interface"; http://man7.org/tlpi/
--
To unsubscribe from this list: send the line "unsubscribe linux-man" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Kernel Documentation]     [Netdev]     [Linux Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux