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