2
* Implement some C99-compatible complex math functions
4
* Most of the code is taken from the msun library in FreeBSD (HEAD @ 30th June
5
* 2009), under the following license:
7
* Copyright (c) 2007 David Schultz <das@FreeBSD.ORG>
10
* Redistribution and use in source and binary forms, with or without
11
* modification, are permitted provided that the following conditions
13
* 1. Redistributions of source code must retain the above copyright
14
* notice, this list of conditions and the following disclaimer.
15
* 2. Redistributions in binary form must reproduce the above copyright
16
* notice, this list of conditions and the following disclaimer in the
17
* documentation and/or other materials provided with the distribution.
19
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31
#include "npy_math_common.h"
32
#include "npy_math_private.h"
34
/*==========================================================
35
* Custom implementation of missing complex C99 functions
36
*=========================================================*/
39
* #type = float,double,npy_longdouble#
40
* #ctype = npy_cfloat,npy_cdouble,npy_clongdouble#
43
* #TMAX = FLT_MAX, DBL_MAX, LDBL_MAX#
46
@type@ npy_cabs@c@(@ctype@ z)
48
return npy_hypot@c@(npy_creal@c@(z), npy_cimag@c@(z));
53
@type@ npy_carg@c@(@ctype@ z)
55
return npy_atan2@c@(npy_cimag@c@(z), npy_creal@c@(z));
60
@ctype@ npy_cexp@c@(@ctype@ z)
69
if (npy_isfinite(r)) {
75
if (npy_isfinite(i)) {
76
ret = npy_cpack@c@(x * c, x * s);
78
ret = npy_cpack@c@(NPY_NAN, npy_copysign@c@(NPY_NAN, i));
81
} else if (npy_isnan(r)) {
84
ret = npy_cpack@c@(r, 0);
86
ret = npy_cpack@c@(r, npy_copysign@c@(NPY_NAN, i));
92
ret = npy_cpack@c@(r, i);
93
} else if (npy_isfinite(i)) {
97
ret = npy_cpack@c@(r * c, r * s);
99
/* x = +inf, y = +-inf | nan */
100
ret = npy_cpack@c@(r, NPY_NAN);
103
if (npy_isfinite(i)) {
108
ret = npy_cpack@c@(x * c, x * s);
110
/* x = -inf, y = nan | +i inf */
111
ret = npy_cpack@c@(0, 0);
121
@ctype@ npy_clog@c@(@ctype@ z)
123
return npy_cpack@c@(npy_log@c@ (npy_cabs@c@ (z)), npy_carg@c@ (z));
127
#ifndef HAVE_CSQRT@C@
129
/* We risk spurious overflow for components >= DBL_MAX / (1 + sqrt(2)). */
130
#define THRESH (@TMAX@ / (1 + NPY_SQRT2@c@))
132
@ctype@ npy_csqrt@c@(@ctype@ z)
142
/* Handle special cases. */
143
if (a == 0 && b == 0)
144
return (npy_cpack@c@(0, b));
146
return (npy_cpack@c@(NPY_INFINITY, b));
148
t = (b - b) / (b - b); /* raise invalid if b is not a NaN */
149
return (npy_cpack@c@(a, t)); /* return NaN + NaN i */
153
* csqrt(inf + NaN i) = inf + NaN i
154
* csqrt(inf + y i) = inf + 0 i
155
* csqrt(-inf + NaN i) = NaN +- inf i
156
* csqrt(-inf + y i) = 0 + inf i
159
return (npy_cpack@c@(npy_fabs@c@(b - b), npy_copysign@c@(a, b)));
161
return (npy_cpack@c@(a, npy_copysign@c@(b - b, b)));
164
* The remaining special case (b is NaN) is handled just fine by
165
* the normal code path below.
168
/* Scale to avoid overflow. */
169
if (npy_fabs@c@(a) >= THRESH || npy_fabs@c@(b) >= THRESH) {
177
/* Algorithm 312, CACM vol 10, Oct 1967. */
179
t = npy_sqrt@c@((a + npy_hypot@c@(a, b)) * 0.5);
180
result = npy_cpack@c@(t, b / (2 * t));
182
t = npy_sqrt@c@((-a + npy_hypot@c@(a, b)) * 0.5);
183
result = npy_cpack@c@(npy_fabs@c@(b) / (2 * t), npy_copysign@c@(t, b));
188
return (npy_cpack@c@(npy_creal@c@(result) * 2, npy_cimag@c@(result)));
196
@ctype@ npy_cpow@c@ (@ctype@ x, @ctype@ y)
199
@type@ br, bi, yr, yi;
201
yr = npy_creal@c@(y);
202
yi = npy_cimag@c@(y);
204
br = npy_creal@c@(b);
205
bi = npy_cimag@c@(b);
207
return npy_cexp@c@(npy_cpack@c@(br * yr - bi * yi, br * yi + bi * yr));
212
@ctype@ npy_ccos@c@(@ctype@ z)
217
return npy_cpack@c@(npy_cos@c@(x) * npy_cosh@c@(y), -(npy_sin@c@(x) * npy_sinh@c@(y)));
222
@ctype@ npy_csin@c@(@ctype@ z)
227
return npy_cpack@c@(npy_sin@c@(x) * npy_cosh@c@(y), npy_cos@c@(x) * npy_sinh@c@(y));
232
/*==========================================================
233
* Decorate all the functions which are available natively
234
*=========================================================*/
237
* #type = float, double, npy_longdouble#
238
* #ctype = npy_cfloat, npy_cdouble, npy_clongdouble#
247
#ifdef HAVE_@KIND@@C@
248
@type@ npy_@kind@@c@(@ctype@ z)
250
__@ctype@_to_c99_cast z1 = {z};
251
return @kind@@c@(z1.c99_z);
257
* #kind = cexp,clog,csqrt,ccos,csin#
258
* #KIND = CEXP,CLOG,CSQRT,CCOS,CSIN#
260
#ifdef HAVE_@KIND@@C@
261
@ctype@ npy_@kind@@c@(@ctype@ z)
263
__@ctype@_to_c99_cast z1 = {z};
264
__@ctype@_to_c99_cast ret;
265
ret.c99_z = @kind@@c@(z1.c99_z);
275
#ifdef HAVE_@KIND@@C@
276
@ctype@ npy_@kind@@c@(@ctype@ x, @ctype@ y)
278
__@ctype@_to_c99_cast x1 = {x};
279
__@ctype@_to_c99_cast y1 = {y};
280
__@ctype@_to_c99_cast ret;
281
ret.c99_z = @kind@@c@(x1.c99_z, y1.c99_z);