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