4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * _X_cplx_div(z, w) returns z / w with infinities handled according
33 * If z and w are both finite and w is nonzero, _X_cplx_div delivers
34 * the complex quotient q according to the usual formula: let a =
35 * Re(z), b = Im(z), c = Re(w), and d = Im(w); then q = x + I * y
36 * where x = (a * c + b * d) / r and y = (b * c - a * d) / r with
37 * r = c * c + d * d. This implementation scales to avoid premature
38 * underflow or overflow.
40 * If z is neither NaN nor zero and w is zero, or if z is infinite
41 * and w is finite and nonzero, _X_cplx_div delivers an infinite
42 * result. If z is finite and w is infinite, _X_cplx_div delivers
45 * If z and w are both zero or both infinite, or if either z or w is
46 * a complex NaN, _X_cplx_div delivers NaN + I * NaN. C99 doesn't
47 * specify these cases.
49 * This implementation can raise spurious underflow, overflow, in-
50 * valid operation, inexact, and division-by-zero exceptions. C99
54 #if !defined(i386) && !defined(__i386) && !defined(__amd64)
55 #error This code is for x86 only
66 * Return +1 if x is +Inf, -1 if x is -Inf, and 0 otherwise
69 testinfl(long double x
)
77 if ((xx
.i
[2] & 0x7fff) != 0x7fff || ((xx
.i
[1] << 1) | xx
.i
[0]) != 0)
79 return (1 | ((xx
.i
[2] << 16) >> 31));
83 _X_cplx_div(long double _Complex z
, long double _Complex w
)
85 long double _Complex v
;
90 long double a
, b
, c
, d
, r
;
91 int ea
, eb
, ec
, ed
, ez
, ew
, es
, i
, j
;
94 * The following is equivalent to
96 * a = creall(*z); b = cimagl(*z);
97 * c = creall(*w); d = cimagl(*w);
99 a
= ((long double *)&z
)[0];
100 b
= ((long double *)&z
)[1];
101 c
= ((long double *)&w
)[0];
102 d
= ((long double *)&w
)[1];
104 /* extract exponents to estimate |z| and |w| */
107 ea
= aa
.i
[2] & 0x7fff;
108 eb
= bb
.i
[2] & 0x7fff;
109 ez
= (ea
> eb
)? ea
: eb
;
113 ec
= cc
.i
[2] & 0x7fff;
114 ed
= dd
.i
[2] & 0x7fff;
115 ew
= (ec
> ed
)? ec
: ed
;
117 /* check for special cases */
118 if (ew
>= 0x7fff) { /* w is inf or nan */
122 if (i
| j
) { /* w is infinite */
124 * "factor out" infinity, being careful to preserve
125 * signs of finite values
127 c
= i
? i
: (((cc
.i
[2] << 16) < 0)? -0.0f
: 0.0f
);
128 d
= j
? j
: (((dd
.i
[2] << 16) < 0)? -0.0f
: 0.0f
);
130 /* scale to avoid overflow below */
135 ((long double *)&v
)[0] = (a
* c
+ b
* d
) * r
;
136 ((long double *)&v
)[1] = (b
* c
- a
* d
) * r
;
140 if (ew
== 0 && (cc
.i
[1] | cc
.i
[0] | dd
.i
[1] | dd
.i
[0]) == 0) {
141 /* w is zero; multiply z by 1/Re(w) - I * Im(w) */
145 if (i
| j
) { /* z is infinite */
149 ((long double *)&v
)[0] = a
* c
+ b
* d
;
150 ((long double *)&v
)[1] = b
* c
- a
* d
;
154 if (ez
>= 0x7fff) { /* z is inf or nan */
157 if (i
| j
) { /* z is infinite */
162 ((long double *)&v
)[0] = a
* c
+ b
* d
;
163 ((long double *)&v
)[1] = b
* c
- a
* d
;
168 * Scale c and d to compute 1/|w|^2 and the real and imaginary
169 * parts of the quotient.
171 es
= ((ew
>> 2) - ew
) + 0x6ffd;
172 if (ez
< 0x0086) { /* |z| < 2^-16249 */
173 if (((ew
- 0x3efe) | (0x4083 - ew
)) >= 0)
174 es
= ((0x4083 - ew
) >> 1) + 0x3fff;
177 ss
.i
[1] = 0x80000000;
182 r
= 1.0f
/ (c
* c
+ d
* d
);
187 ((long double *)&v
)[0] = (a
* c
+ b
* d
) * r
;
188 ((long double *)&v
)[1] = (b
* c
- a
* d
) * r
;