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