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 #pragma weak nexttowardf = __nexttowardf
31
32 #include "libm.h"
33
34 static union {
35 unsigned i;
36 float f;
37 } C[] = {
38 0x00800000,
39 0x7f000000,
40 0x7fffffff
41 };
42
43 #define tiny C[0].f
44 #define huge C[1].f
45 #define qnan C[2].f
46
47 #if defined(__sparc)
48
49 enum fcc_type {
50 fcc_equal = 0,
51 fcc_less = 1,
52 fcc_greater = 2,
53 fcc_unordered = 3
54 };
55
56 #ifdef __sparcv9
57 #define _Q_cmp _Qp_cmp
58 #endif
59
60 extern enum fcc_type _Q_cmp(const long double *, const long double *);
61
62 float
__nexttowardf(float x,long double y)63 __nexttowardf(float x, long double y) {
64 union {
65 unsigned i;
66 float f;
67 } xx;
68 union {
69 unsigned i[4];
70 long double q;
71 } yy;
72 long double lx;
73 unsigned hx;
74 volatile float dummy;
75 enum fcc_type rel;
76
77 /*
78 * It would be somewhat more efficient to check for NaN and
79 * zero operands before converting x to long double and then
80 * to code the comparison in line rather than calling _Q_cmp.
81 * However, since this code probably won't get used much,
82 * I'm opting in favor of simplicity instead.
83 */
84 lx = xx.f = x;
85 hx = xx.i & ~0x80000000;
86
87 /* check for each of four possible orderings */
88 rel = _Q_cmp(&lx, &y);
89 if (rel == fcc_unordered)
90 return (qnan);
91
92 if (rel == fcc_equal) {
93 if (hx == 0) { /* x is zero; return zero with y's sign */
94 yy.q = y;
95 xx.i = yy.i[0];
96 return (xx.f);
97 }
98 return (x);
99 }
100
101 if (rel == fcc_less) {
102 if (hx == 0) /* x is zero */
103 xx.i = 0x00000001;
104 else if ((int) xx.i >= 0) /* x is positive */
105 xx.i++;
106 else
107 xx.i--;
108 } else {
109 if (hx == 0) /* x is zero */
110 xx.i = 0x80000001;
111 else if ((int) xx.i >= 0) /* x is positive */
112 xx.i--;
113 else
114 xx.i++;
115 }
116
117 /* raise exceptions as needed */
118 hx = xx.i & ~0x80000000;
119 if (hx == 0x7f800000) {
120 dummy = huge;
121 dummy *= huge;
122 } else if (hx < 0x00800000) {
123 dummy = tiny;
124 dummy *= tiny;
125 }
126
127 return (xx.f);
128 }
129
130 #elif defined(__x86)
131
132 float
__nexttowardf(float x,long double y)133 __nexttowardf(float x, long double y) {
134 union {
135 unsigned i;
136 float f;
137 } xx;
138 unsigned hx;
139 long double lx;
140 volatile float dummy;
141
142 lx = xx.f = x;
143 hx = xx.i & ~0x80000000;
144
145 /* check for each of four possible orderings */
146 if (isunordered(lx, y))
147 return ((float) (lx + y));
148
149 if (lx == y)
150 return ((float) y);
151
152 if (lx < y) {
153 if (hx == 0) /* x is zero */
154 xx.i = 0x00000001;
155 else if ((int) xx.i >= 0) /* x is positive */
156 xx.i++;
157 else
158 xx.i--;
159 } else {
160 if (hx == 0) /* x is zero */
161 xx.i = 0x80000001;
162 else if ((int) xx.i >= 0) /* x is positive */
163 xx.i--;
164 else
165 xx.i++;
166 }
167
168 /* raise exceptions as needed */
169 hx = xx.i & ~0x80000000;
170 if (hx == 0x7f800000) {
171 dummy = huge;
172 dummy *= huge;
173 } else if (hx < 0x00800000) {
174 dummy = tiny;
175 dummy *= tiny;
176 }
177
178 return (xx.f);
179 }
180
181 #else
182 #error Unknown architecture
183 #endif
184