
On Sat, Jul 19, 2008 at 7:13 AM, Pauli Virtanen <pav@iki.fi> wrote:
Hi all,
Re: Ticket 854.
I wrote tests for the branch cuts for all complex arc* functions in umathmodule. It turns out that all except arccosh were OK. The formula for arcsinh was written in a non-standard form with an unnecessary nc_neg, but this didn't affect the results. I also wrote tests for checking values of the functions at infs and nans.
A patch for all of this is attached, with all currently non-passing tests marked as skipped. I'd like to commit this if there are no objections.
Another thing I noticed is that the present implementations of the complex functions are naive, so they over- and underflow earlier than necessary:
np.arcsinh(1e8) 19.113827924512311 np.arcsinh(1e8 + 0j) (inf-0j) np.arcsinh(-1e8 + 0j) (-19.113827924512311-0j)
This particular thing in arcsinh occurs because of loss of precision in intermediate stages. (In the version in my patch this loss of precision is still present.)
It would be nice to polish these up. BTW, are there obstacles to using the C99 complex functions when they are available? This would avoid quite a bit of drudgework... As an alternative, we can probably steal better implementations from Python's recently polished cmathmodule.c
The main problem is determining when they are available and if they cover all the needed precisions. Since we will need standalone implementations on some platforms anyway, I am inclined towards stealing from cmathmodule.c if it offers improved code for some of the functions.
***
Then comes a descent into pedantry: Numpy complex functions are not C99 compliant in handling of the signed zero, inf, and nan. I don't know whether we should comply with C99, but it would be nicer to have these handled in a controlled way rather than as a byproduct of the implementation chosen.
Agreed.
1)
The branch cuts for sqrt and arc* don't respect the negative zero:
a = 1 + 0j np.sqrt(-a) 1j np.sqrt(-1 + 0j) 1j
The branch cut of the logarithm however does:
np.log(-a) -3.1415926535897931j np.log(-1 + 0j) 3.1415926535897931j
All complex functions in the C99 standard respect the negative zero in their branch cuts. Do we want to follow?
Hmm. I think so, to the extent we can. This might lead to some unexpected results, but that is what happens for arguments near the branch cuts. Do it and document it.
I don't know how to check what Octave and Matlab do regarding this, since I haven't figured out how to place a negative zero in complex numbers in these languages. But at least in practice these languages appear not to respect the sign of zero.
a = 1 + 0j log(-a) ans = 0.000000000000000 + 3.141592653589793i log(-1) ans = 0.000000000000000 + 3.141592653589793i
2)
The numpy functions in general don't return C99 compliant results at inf or nan. I wrote up some tests for checking these.
Do we want to fix these?
I'd say yes. That way we can refer to the C99 standard to document numpy behavior. Chuck