New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
math/cmplx: unpredictable sign of 0 calling Sin and Cos for real arguments #51034
Comments
This C program: #include <stdio.h>
#include <complex.h>
int main() {
int i;
for (i = 0; i <= 8; i++) {
complex x = (complex)((double)(i - 4));
complex r = csin(x);
printf("sin %g+%gi %g+%gi\n", creal(x), cimag(x), creal(r), cimag(r));
r = ccos(x);
printf("cos %g+%gi %g+%gi\n", creal(x), cimag(x), creal(r), cimag(r));
}
} prints this:
|
The Go cmplx library gives the same unpredictable signs for the imaginary part. That says we're doing the same as the C environment you are using, but it doesn't exactly say what the right result is. This is mostly a curiosity for me. Are the negative zeroes considered acceptable for a result like cos(0) that is resolutely positive? I don't know. I'm hoping a numerical expert will weigh in. |
What I expected is either always +0i or that the imaginary part has the same sign as the real part. But that is based on surmise, not on what an expert might know and expect. |
https://twitter.com/rob_pike/status/1490529340907417601 to see if anyone knows what's right here. |
Not an expert but as far as I remember from school, when computing an inverse elementary function for complex numbers, we need distinguish between -0i and +0i, and A better question might be: what would experts expect for the result of I would expect the output sign of zero in imaginary part stay consistent with the input, for instance: Let x be real,
|
They appear to behave as if numerically evaluating the expansions
https://godbolt.org/z/Y535n4fbj Edit: musl does this explicitly (using csin in terms of csinh). |
I have not closely studied the Go library yet, but the origin of IEEE Floating Point choices in this regard can be found in Kahan's memo "Branch Cuts for Elementary Functions or Much Ado about Nothing's Sign Bit", which circulated in various versions, for example at https://people.freebsd.org/~das/kahan86branch.pdf. |
@n2vi Thanks for that link. It's very helpful - if remarkably long and roundabout - and it helped me work out what's going on. The sign of the zero is determined by the sheet of the function approaching the "slit" (as Kahan calls it) in the plane where the function has trouble from a all-is-real-and-simple standpoint. In the case of cosine, for example, where we see 1-0i, it's because the sign of the imaginary part is negative for complex numbers with small imaginary components and positive real ones. For instance,
prints
Note the large negative exponent on the negative imaginary part. So the answer is simple and makes sense. Not sure it needed 20+ pages to get there, but I'm happy it's sorted. |
See https://go.dev/play/p/sSDqGhsdp5a
This program prints
cmplx.Cos
andcmplx.Sin
for a number of real arguments (imaginary part zero). The result is of course real, but the returned result often has negative zero as the imaginary part. I can't see a pattern, and I'm not sure if it matters or, if so, what the right thing to do is, but I wanted to record it.In particular, check out this gem:
The text was updated successfully, but these errors were encountered: