Re: Wrong formulae for complex elementary functions

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

 



Hello Richard,

On Thu, Sep 15, 2011 at 6:31 AM, Michael Kerrisk <mtk.manpages@xxxxxxxxx> wrote:
> 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

For man-pages-3.33, I have applied the changes below. They should be
consistent with what you proposed (and Andries confirmed). Could you
please carefully check...

I think it's not so necessary to add a warning to the page source.
Nowadays we have version control and logs, so the reasoning should be
easy to find.

Thanks,

Michael


diff --git a/man3/cacos.3 b/man3/cacos.3
index b483a0c..1ae6ff5 100644
--- a/man3/cacos.3
+++ b/man3/cacos.3
@@ -27,7 +27,7 @@ is chosen in the interval [0,pi].
 One has:
 .nf

-    cacos(z) = \-i clog(z + csqrt(z * z \- 1))
+    cacos(z) = \-i * clog(z + i * csqrt(1 \- z * z))
 .fi
 .SH VERSIONS
 These functions first appeared in glibc in version 2.1.
diff --git a/man3/cacosh.3 b/man3/cacosh.3
index 7bf60c9..bf3d99b 100644
--- a/man3/cacosh.3
+++ b/man3/cacosh.3
@@ -30,7 +30,7 @@ is chosen nonnegative.
 One has:
 .nf

-    cacosh(z) = (0.5) * clog((1 + z) / (1 \- z))
+    cacosh(z) = 2 * clog(csqrt((z + 1) / 2) + csqrt((z \- 1) / 2))
 .fi
 .SH VERSIONS
 These functions first appeared in glibc in version 2.1.
diff --git a/man3/catan.3 b/man3/catan.3
index 30692bb..fe8c39e 100644
--- a/man3/catan.3
+++ b/man3/catan.3
@@ -25,7 +25,7 @@ The real part of y is chosen in the interval [\-pi/2,pi/2].
 One has:
 .nf

-    catan(z) = 1 / 2i clog((1 + iz) / (1 \- iz))
+    catan(z) = (clog(1 + i * z) \- clog(1 \- i * z)) / (2 * i)
 .fi
 .SH VERSIONS
 These functions first appeared in glibc in version 2.1.
diff --git a/man3/catanh.3 b/man3/catanh.3
index e396021..4f2f230 100644
--- a/man3/catanh.3
+++ b/man3/catanh.3
@@ -27,7 +27,7 @@ is chosen in the interval [\-pi/2,pi/2].
 One has:
 .nf

-    catanh(z) = 0.5 * clog((1 + z) / (1 \- z))
+    catanh(z) = 0.5 * (clog(1 + z) \- clog(1 \- z))
 .fi
 .SH VERSIONS
 These functions first appeared in glibc in version 2.1.



-- 
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