xref: /illumos-gate/usr/src/lib/libm/common/m9x/nexttowardf.c (revision 1ec68d336ba97cd53f46053ac10401d16014d075)
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