6 * Compute the complex arcsin corresponding to a complex sine value;
7 * a generic implementation for casin(), casinf(), and casinl().
9 * Written by Keith Marshall <keith@users.osdn.me>
10 * This is an adaptation of an original contribution by Danny Smith
11 * Copyright (C) 2003, 2014, 2022, MinGW.OSDN Project
14 * Permission is hereby granted, free of charge, to any person obtaining a
15 * copy of this software and associated documentation files (the "Software"),
16 * to deal in the Software without restriction, including without limitation
17 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 * and/or sell copies of the Software, and to permit persons to whom the
19 * Software is furnished to do so, subject to the following conditions:
21 * The above copyright notice, this permission notice, and the following
22 * disclaimer shall be included in all copies or substantial portions of
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF OR OTHER
31 * DEALINGS IN THE SOFTWARE.
34 * This is a generic implementation for all of the casin(), casinl(),
35 * and casinf() functions; each is to be compiled separately, i.e.
37 * gcc -D FUNCTION=casin -o casin.o casin_generic.c
38 * gcc -D FUNCTION=casinl -o casinl.o casin_generic.c
39 * gcc -D FUNCTION=casinf -o casinf.o casin_generic.c
46 /* If user neglected to specify it, the default compilation is for
47 * the casin() function.
49 # define FUNCTION casin
52 #define argtype_casin double
53 #define argtype_casinl long double
54 #define argtype_casinf float
56 #define PASTE(PREFIX,SUFFIX) PREFIX##SUFFIX
57 #define mapname(PREFIX,SUFFIX) PASTE(PREFIX,SUFFIX)
59 #define ARGTYPE(FUNCTION) PASTE(argtype_,FUNCTION)
60 #define ARGCAST(VALUE) mapname(argcast_,FUNCTION)(VALUE)
62 #define argcast_casin(VALUE) VALUE
63 #define argcast_casinl(VALUE) PASTE(VALUE,L)
64 #define argcast_casinf(VALUE) PASTE(VALUE,F)
66 #define mapfunc(NAME) mapname(mapfunc_,FUNCTION)(NAME)
68 #define mapfunc_casin(NAME) NAME
69 #define mapfunc_casinl(NAME) PASTE(NAME,l)
70 #define mapfunc_casinf(NAME) PASTE(NAME,f)
72 /* Define the generic function implementation.
74 ARGTYPE(FUNCTION) complex FUNCTION( ARGTYPE(FUNCTION) complex Z )
76 ARGTYPE(FUNCTION) x = __real__ Z; /* real part of Z saved as x */
77 ARGTYPE(FUNCTION) y = __imag__ Z; /* imaginary part of Z saved as iy */
79 /* Having thus saved the original value of Z as separate real and
80 * imaginary parts, we may reuse Z to compute the arcsin value...
82 if( (y == ARGCAST(0.0)) && (ARGCAST(1.0) >= mapfunc(fabs)(x)) )
84 /* ...but when Z is entirely real, and lies within the valid
85 * domain, (-1.0 .. +1.0), for real sine values, we may simply
86 * optimize this call, using the real arcsin function...
88 __real__ Z = mapfunc(asin)(x);
91 { /* Z is complex, (i.e. it has a non-zero imaginary part), or it
92 * is entirely real but lies outside the valid domain for a real
93 * sine value; we must evaluate the complex arcsin expression:
95 * casin(Z) = -i * clog(i * Z + csqrt(1.0 - Z * Z))
97 * Here, we use a local accumulator for the evaluation:
99 ARGTYPE(FUNCTION) complex ZZ;
101 /* First, note that we may express 1.0 - Z * Z as equivalent to
102 * 1.0 - (x + iy) * (x + iy), which expands to:
104 * 1.0 - (x * x + i * y * i * y + 2.0 * i * x * y)
106 * and, noting that i * i is equivalent to -1, this simplifies
109 * 1.0 - (x * x - y * y + 2.0 * i * x * y)
111 * Separating real and imaginary parts yields:
113 * (1.0 - x * x - y * y) - (i * 2.0 * x * y)
115 * and factorization of the real part then yields:
117 * (1.0 - (x - y) * (x + y)) - (i * 2.0 * x * y)
121 __real__ ZZ = ARGCAST(1.0) - (x - y) * (x + y);
122 __imag__ ZZ = ARGCAST(-2.0) * x * y;
124 /* ...and the complex square root term may be computed as...
126 ZZ = mapfunc(csqrt)(ZZ);
128 /* ...to which we then add i * (x + iy), (i.e. i times the
129 * original value of Z); here, we note that i * iy is equal to
130 * -1 * y, and hence adding it is equivalent to subtracting y
131 * from the real part of our recomputed Z, while adding i * x
132 * is equivalent to adding x to the imaginary part...
137 /* ...thus obtaining the intermediate expression value from
138 * which we must compute the complex logarithm...
140 ZZ = mapfunc(clog)(ZZ);
142 /* ...and ultimately, the arcsin value to be returned is the
143 * value of this complex logarithm multiplied by -1 * i; (the
144 * imaginary part of the intermediate result, multiplied by i
145 * becomes the real part of the result, with inverted sign,
146 * which is then inverted again on multiplication by -1...
148 __real__ Z = __imag__ ZZ;
150 /* ...while the real part of the intermediate simply becomes
151 * the imaginary part of the result, with sign preserved, but
152 * then inverted by multiplication by -1).
154 __imag__ Z = ARGCAST(-1.0) * __real__ ZZ;
159 /* $RCSfile$: end of file */