17c478bdstevel@tonic-gate/* 27c478bdstevel@tonic-gate * CDDL HEADER START 37c478bdstevel@tonic-gate * 47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bdstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bdstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bdstevel@tonic-gate * with the License. 87c478bdstevel@tonic-gate * 97c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bdstevel@tonic-gate * See the License for the specific language governing permissions 127c478bdstevel@tonic-gate * and limitations under the License. 137c478bdstevel@tonic-gate * 147c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bdstevel@tonic-gate * 207c478bdstevel@tonic-gate * CDDL HEADER END 217c478bdstevel@tonic-gate */ 227c478bdstevel@tonic-gate/* 237c478bdstevel@tonic-gate * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 247c478bdstevel@tonic-gate * Use is subject to license terms. 257c478bdstevel@tonic-gate */ 267c478bdstevel@tonic-gate 277c478bdstevel@tonic-gate#pragma ident "%Z%%M% %I% %E% SMI" 287c478bdstevel@tonic-gate 297c478bdstevel@tonic-gate/* 307c478bdstevel@tonic-gate * _D_cplx_div_rx(a, w) returns a / w with infinities handled according 317c478bdstevel@tonic-gate * to C99. 327c478bdstevel@tonic-gate * 337c478bdstevel@tonic-gate * If a and w are both finite and w is nonzero, _D_cplx_div_rx(a, w) 347c478bdstevel@tonic-gate * delivers the complex quotient q according to the usual formula: 357c478bdstevel@tonic-gate * let c = Re(w), and d = Im(w); then q = x + I * y where x = (a * c) 367c478bdstevel@tonic-gate * / r and y = (-a * d) / r with r = c * c + d * d. This implementa- 377c478bdstevel@tonic-gate * tion scales to avoid premature underflow or overflow. 387c478bdstevel@tonic-gate * 397c478bdstevel@tonic-gate * If a is neither NaN nor zero and w is zero, or if a is infinite 407c478bdstevel@tonic-gate * and w is finite and nonzero, _D_cplx_div_rx delivers an infinite 417c478bdstevel@tonic-gate * result. If a is finite and w is infinite, _D_cplx_div_rx delivers 427c478bdstevel@tonic-gate * a zero result. 437c478bdstevel@tonic-gate * 447c478bdstevel@tonic-gate * If a and w are both zero or both infinite, or if either a or w is 457c478bdstevel@tonic-gate * NaN, _D_cplx_div_rx delivers NaN + I * NaN. C99 doesn't specify 467c478bdstevel@tonic-gate * these cases. 477c478bdstevel@tonic-gate * 487c478bdstevel@tonic-gate * This implementation can raise spurious underflow, overflow, in- 497c478bdstevel@tonic-gate * valid operation, inexact, and division-by-zero exceptions. C99 507c478bdstevel@tonic-gate * allows this. 517c478bdstevel@tonic-gate * 527c478bdstevel@tonic-gate * Warning: Do not attempt to "optimize" this code by removing multi- 537c478bdstevel@tonic-gate * plications by zero. 547c478bdstevel@tonic-gate */ 557c478bdstevel@tonic-gate 567c478bdstevel@tonic-gate#if !defined(sparc) && !defined(__sparc) 577c478bdstevel@tonic-gate#error This code is for SPARC only 587c478bdstevel@tonic-gate#endif 597c478bdstevel@tonic-gate 607c478bdstevel@tonic-gate/* 617c478bdstevel@tonic-gate * scl[i].d = 2^(250*(4-i)) for i = 0, ..., 9 627c478bdstevel@tonic-gate */ 637c478bdstevel@tonic-gatestatic const union { 647c478bdstevel@tonic-gate int i[2]; 657c478bdstevel@tonic-gate double d; 667c478bdstevel@tonic-gate} scl[9] = { 677c478bdstevel@tonic-gate { 0x7e700000, 0 }, 687c478bdstevel@tonic-gate { 0x6ed00000, 0 }, 697c478bdstevel@tonic-gate { 0x5f300000, 0 }, 707c478bdstevel@tonic-gate { 0x4f900000, 0 }, 717c478bdstevel@tonic-gate { 0x3ff00000, 0 }, 727c478bdstevel@tonic-gate { 0x30500000, 0 }, 737c478bdstevel@tonic-gate { 0x20b00000, 0 }, 747c478bdstevel@tonic-gate { 0x11100000, 0 }, 757c478bdstevel@tonic-gate { 0x01700000, 0 } 767c478bdstevel@tonic-gate}; 777c478bdstevel@tonic-gate 787c478bdstevel@tonic-gate/* 797c478bdstevel@tonic-gate * Return +1 if x is +Inf, -1 if x is -Inf, and 0 otherwise 807c478bdstevel@tonic-gate */ 817c478bdstevel@tonic-gatestatic int 827c478bdstevel@tonic-gatetestinf(double x) 837c478bdstevel@tonic-gate{ 847c478bdstevel@tonic-gate union { 857c478bdstevel@tonic-gate int i[2]; 867c478bdstevel@tonic-gate double d; 877c478bdstevel@tonic-gate } xx; 887c478bdstevel@tonic-gate 897c478bdstevel@tonic-gate xx.d = x; 907c478bdstevel@tonic-gate return (((((xx.i[0] << 1) - 0xffe00000) | xx.i[1]) == 0)? 917c478bdstevel@tonic-gate (1 | (xx.i[0] >> 31)) : 0); 927c478bdstevel@tonic-gate} 937c478bdstevel@tonic-gate 947c478bdstevel@tonic-gatedouble _Complex 957c478bdstevel@tonic-gate_D_cplx_div_rx(double a, double _Complex w) 967c478bdstevel@tonic-gate{ 977c478bdstevel@tonic-gate double _Complex v; 987c478bdstevel@tonic-gate union { 997c478bdstevel@tonic-gate int i[2]; 1007c478bdstevel@tonic-gate double d; 1017c478bdstevel@tonic-gate } aa, cc, dd; 1027c478bdstevel@tonic-gate double c, d, sc, sd, r; 1037c478bdstevel@tonic-gate int ha, hc, hd, hw, i, j; 1047c478bdstevel@tonic-gate 1057c478bdstevel@tonic-gate /* 1067c478bdstevel@tonic-gate * The following is equivalent to 1077c478bdstevel@tonic-gate * 1087c478bdstevel@tonic-gate * c = creal(w); d = cimag(w); 1097c478bdstevel@tonic-gate */ 1107c478bdstevel@tonic-gate c = ((double *)&w)[0]; 1117c478bdstevel@tonic-gate d = ((double *)&w)[1]; 1127c478bdstevel@tonic-gate 1137c478bdstevel@tonic-gate /* extract high-order words to estimate |a| and |w| */ 1147c478bdstevel@tonic-gate aa.d = a; 1157c478bdstevel@tonic-gate ha = aa.i[0] & ~0x80000000; 1167c478bdstevel@tonic-gate 1177c478bdstevel@tonic-gate cc.d = c; 1187c478bdstevel@tonic-gate dd.d = d; 1197c478bdstevel@tonic-gate hc = cc.i[0] & ~0x80000000; 1207c478bdstevel@tonic-gate hd = dd.i[0] & ~0x80000000; 1217c478bdstevel@tonic-gate hw = (hc > hd)? hc : hd; 1227c478bdstevel@tonic-gate 1237c478bdstevel@tonic-gate /* check for special cases */ 1247c478bdstevel@tonic-gate if (hw >= 0x7ff00000) { /* w is inf or nan */ 1257c478bdstevel@tonic-gate i = testinf(c); 1267c478bdstevel@tonic-gate j = testinf(d); 1277c478bdstevel@tonic-gate if (i | j) { /* w is infinite */ 1287c478bdstevel@tonic-gate c = (cc.i[0] < 0)? -0.0 : 0.0; 1297c478bdstevel@tonic-gate d = (dd.i[0] < 0)? -0.0 : 0.0; 1307c478bdstevel@tonic-gate } else /* w is nan */ 1317c478bdstevel@tonic-gate a *= c * d; 1327c478bdstevel@tonic-gate ((double *)&v)[0] = a * c; 1337c478bdstevel@tonic-gate ((double *)&v)[1] = -a * d; 1347c478bdstevel@tonic-gate return (v); 1357c478bdstevel@tonic-gate } 1367c478bdstevel@tonic-gate 1377c478bdstevel@tonic-gate if (hw < 0x00100000) { 1387c478bdstevel@tonic-gate /* 1397c478bdstevel@tonic-gate * This nonsense is needed to work around some SPARC 1407c478bdstevel@tonic-gate * implementations of nonstandard mode; if both parts 1417c478bdstevel@tonic-gate * of w are subnormal, multiply them by one to force 1427c478bdstevel@tonic-gate * them to be flushed to zero when nonstandard mode 1437c478bdstevel@tonic-gate * is enabled. Sheesh. 1447c478bdstevel@tonic-gate */ 1457c478bdstevel@tonic-gate cc.d = c = c * 1.0; 1467c478bdstevel@tonic-gate dd.d = d = d * 1.0; 1477c478bdstevel@tonic-gate hc = cc.i[0] & ~0x80000000; 1487c478bdstevel@tonic-gate hd = dd.i[0] & ~0x80000000; 1497c478bdstevel@tonic-gate hw = (hc > hd)? hc : hd; 1507c478bdstevel@tonic-gate } 1517c478bdstevel@tonic-gate 1527c478bdstevel@tonic-gate if (hw == 0 && (cc.i[1] | dd.i[1]) == 0) { 1537c478bdstevel@tonic-gate /* w is zero; multiply a by 1/Re(w) - I * Im(w) */ 1547c478bdstevel@tonic-gate c = 1.0 / c; 1557c478bdstevel@tonic-gate i = testinf(a); 1567c478bdstevel@tonic-gate if (i) { /* a is infinite */ 1577c478bdstevel@tonic-gate a = i; 1587c478bdstevel@tonic-gate } 1597c478bdstevel@tonic-gate ((double *)&v)[0] = a * c; 1607c478bdstevel@tonic-gate ((double *)&v)[1] = (a == 0.0)? a * c : -a * d; 1617c478bdstevel@tonic-gate return (v); 1627c478bdstevel@tonic-gate } 1637c478bdstevel@tonic-gate 1647c478bdstevel@tonic-gate if (ha >= 0x7ff00000) { /* a is inf or nan */ 1657c478bdstevel@tonic-gate ((double *)&v)[0] = a * c; 1667c478bdstevel@tonic-gate ((double *)&v)[1] = -a * d; 1677c478bdstevel@tonic-gate return (v); 1687c478bdstevel@tonic-gate } 1697c478bdstevel@tonic-gate 1707c478bdstevel@tonic-gate /* 1717c478bdstevel@tonic-gate * Compute the real and imaginary parts of the quotient, 1727c478bdstevel@tonic-gate * scaling to avoid overflow or underflow. 1737c478bdstevel@tonic-gate */ 1747c478bdstevel@tonic-gate hw = (hw - 0x38000000) >> 28; 1757c478bdstevel@tonic-gate sc = c * scl[hw + 4].d; 1767c478bdstevel@tonic-gate sd = d * scl[hw + 4].d; 1777c478bdstevel@tonic-gate r = sc * sc + sd * sd; 1787c478bdstevel@tonic-gate 1797c478bdstevel@tonic-gate ha = (ha - 0x38000000) >> 28; 1807c478bdstevel@tonic-gate a = (a * scl[ha + 4].d) / r; 1817c478bdstevel@tonic-gate ha -= (hw + hw); 1827c478bdstevel@tonic-gate 1837c478bdstevel@tonic-gate hc = (hc - 0x38000000) >> 28; 1847c478bdstevel@tonic-gate c = (c * scl[hc + 4].d) * a; 1857c478bdstevel@tonic-gate hc += ha; 1867c478bdstevel@tonic-gate 1877c478bdstevel@tonic-gate hd = (hd - 0x38000000) >> 28; 1887c478bdstevel@tonic-gate d = -(d * scl[hd + 4].d) * a; 1897c478bdstevel@tonic-gate hd += ha; 1907c478bdstevel@tonic-gate 1917c478bdstevel@tonic-gate /* compensate for scaling */ 1927c478bdstevel@tonic-gate sc = scl[3].d; /* 2^250 */ 1937c478bdstevel@tonic-gate if (hc < 0) { 1947c478bdstevel@tonic-gate hc = -hc; 1957c478bdstevel@tonic-gate sc = scl[5].d; /* 2^-250 */ 1967c478bdstevel@tonic-gate } 1977c478bdstevel@tonic-gate while (hc--) 1987c478bdstevel@tonic-gate c *= sc; 1997c478bdstevel@tonic-gate 2007c478bdstevel@tonic-gate sd = scl[3].d; 2017c478bdstevel@tonic-gate if (hd < 0) { 2027c478bdstevel@tonic-gate hd = -hd; 2037c478bdstevel@tonic-gate sd = scl[5].d; 2047c478bdstevel@tonic-gate } 2057c478bdstevel@tonic-gate while (hd--) 2067c478bdstevel@tonic-gate d *= sd; 2077c478bdstevel@tonic-gate 2087c478bdstevel@tonic-gate ((double *)&v)[0] = c; 2097c478bdstevel@tonic-gate ((double *)&v)[1] = d; 2107c478bdstevel@tonic-gate return (v); 2117c478bdstevel@tonic-gate} 212