xref: /titanic_41/usr/src/lib/libm/common/m9x/nexttoward.c (revision ef26a926e54f934431066685d069cbf73bba1534)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
24  */
25 /*
26  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
27  * Use is subject to license terms.
28  */
29 
30 #if defined(ELFOBJ)
31 #pragma weak nexttoward = __nexttoward
32 #endif
33 
34 /*
35  * nexttoward(x, y) delivers the next representable number after x
36  * in the direction of y.  If x and y are both zero, the result is
37  * zero with the same sign as y.  If either x or y is NaN, the result
38  * is NaN.
39  *
40  * If x != y and the result is infinite, overflow is raised; if
41  * x != y and the result is subnormal or zero, underflow is raised.
42  * (This is wrong, but it's what C99 apparently wants.)
43  */
44 
45 #include "libm.h"
46 
47 #if defined(__sparc)
48 
49 static union {
50 	unsigned i[2];
51 	double d;
52 } C[] = {
53 	0x00100000, 0,
54 	0x7fe00000, 0,
55 	0x7fffffff, 0xffffffff
56 };
57 
58 #define	tiny	C[0].d
59 #define	huge	C[1].d
60 #define	qnan	C[2].d
61 
62 enum fcc_type {
63 	fcc_equal = 0,
64 	fcc_less = 1,
65 	fcc_greater = 2,
66 	fcc_unordered = 3
67 };
68 
69 #ifdef __sparcv9
70 #define	_Q_cmp	_Qp_cmp
71 #endif
72 
73 extern enum fcc_type _Q_cmp(const long double *, const long double *);
74 
75 double
76 __nexttoward(double x, long double y) {
77 	union {
78 		unsigned i[2];
79 		double d;
80 	} xx;
81 	union {
82 		unsigned i[4];
83 		long double q;
84 	} yy;
85 	long double lx;
86 	unsigned hx;
87 	volatile double	dummy;
88 	enum fcc_type rel;
89 
90 	/*
91 	 * It would be somewhat more efficient to check for NaN and
92 	 * zero operands before converting x to long double and then
93 	 * to code the comparison in line rather than calling _Q_cmp.
94 	 * However, since this code probably won't get used much,
95 	 * I'm opting in favor of simplicity instead.
96 	 */
97 	lx = xx.d = x;
98 	hx = (xx.i[0] & ~0x80000000) | xx.i[1];
99 
100 	/* check for each of four possible orderings */
101 	rel = _Q_cmp(&lx, &y);
102 	if (rel == fcc_unordered)
103 		return (qnan);
104 
105 	if (rel == fcc_equal) {
106 		if (hx == 0) {	/* x is zero; return zero with y's sign */
107 			yy.q = y;
108 			xx.i[0] = yy.i[0];
109 			return (xx.d);
110 		}
111 		return (x);
112 	}
113 
114 	if (rel == fcc_less) {
115 		if (hx == 0) {	/* x is zero */
116 			xx.i[0] = 0;
117 			xx.i[1] = 0x00000001;
118 		} else if ((int)xx.i[0] >= 0) {	/* x is positive */
119 			if (++xx.i[1] == 0)
120 				xx.i[0]++;
121 		} else {
122 			if (xx.i[1]-- == 0)
123 				xx.i[0]--;
124 		}
125 	} else {
126 		if (hx == 0) {	/* x is zero */
127 			xx.i[0] = 0x80000000;
128 			xx.i[1] = 0x00000001;
129 		} else if ((int)xx.i[0] >= 0) {	/* x is positive */
130 			if (xx.i[1]-- == 0)
131 				xx.i[0]--;
132 		} else {
133 			if (++xx.i[1] == 0)
134 				xx.i[0]++;
135 		}
136 	}
137 
138 	/* raise exceptions as needed */
139 	hx = xx.i[0] & ~0x80000000;
140 	if (hx == 0x7ff00000) {
141 		dummy = huge;
142 		dummy *= huge;
143 	} else if (hx < 0x00100000) {
144 		dummy = tiny;
145 		dummy *= tiny;
146 	}
147 
148 	return (xx.d);
149 }
150 
151 #elif defined(__x86)
152 
153 static union {
154 	unsigned i[2];
155 	double d;
156 } C[] = {
157 	0, 0x00100000,
158 	0, 0x7fe00000,
159 };
160 
161 #define	tiny	C[0].d
162 #define	huge	C[1].d
163 
164 double
165 __nexttoward(double x, long double y) {
166 	union {
167 		unsigned i[2];
168 		double d;
169 	} xx;
170 	unsigned hx;
171 	long double lx;
172 	volatile double	dummy;
173 
174 	lx = xx.d = x;
175 	hx = (xx.i[1] & ~0x80000000) | xx.i[0];
176 
177 	/* check for each of four possible orderings */
178 	if (isunordered(lx, y))
179 		return ((double) (lx + y));
180 
181 	if (lx == y)
182 		return ((double) y);
183 
184 	if (lx < y) {
185 		if (hx == 0) {	/* x is zero */
186 			xx.i[0] = 0x00000001;
187 			xx.i[1] = 0;
188 		} else if ((int)xx.i[1] >= 0) {	/* x is positive */
189 			if (++xx.i[0] == 0)
190 				xx.i[1]++;
191 		} else {
192 			if (xx.i[0]-- == 0)
193 				xx.i[1]--;
194 		}
195 	} else {
196 		if (hx == 0) {	/* x is zero */
197 			xx.i[0] = 0x00000001;
198 			xx.i[1] = 0x80000000;
199 		} else if ((int)xx.i[1] >= 0) {	/* x is positive */
200 			if (xx.i[0]-- == 0)
201 				xx.i[1]--;
202 		} else {
203 			if (++xx.i[0] == 0)
204 				xx.i[1]++;
205 		}
206 	}
207 
208 	/* raise exceptions as needed */
209 	hx = xx.i[1] & ~0x80000000;
210 	if (hx == 0x7ff00000) {
211 		dummy = huge;
212 		dummy *= huge;
213 	} else if (hx < 0x00100000) {
214 		dummy = tiny;
215 		dummy *= tiny;
216 	}
217 
218 	return (xx.d);
219 }
220 
221 #else
222 #error Unknown architecture
223 #endif
224