xref: /linux/arch/parisc/math-emu/frnd.c (revision ca55b2fef3a9373fcfc30f82fd26bc7fccbda732)
1 /*
2  * Linux/PA-RISC Project (http://www.parisc-linux.org/)
3  *
4  * Floating-point emulation code
5  *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
6  *
7  *    This program is free software; you can redistribute it and/or modify
8  *    it under the terms of the GNU General Public License as published by
9  *    the Free Software Foundation; either version 2, or (at your option)
10  *    any later version.
11  *
12  *    This program is distributed in the hope that it will be useful,
13  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *    GNU General Public License for more details.
16  *
17  *    You should have received a copy of the GNU General Public License
18  *    along with this program; if not, write to the Free Software
19  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 /*
22  * BEGIN_DESC
23  *
24  *  Purpose:
25  *	Single Floating-point Round to Integer
26  *	Double Floating-point Round to Integer
27  *	Quad Floating-point Round to Integer (returns unimplemented)
28  *
29  *  External Interfaces:
30  *	dbl_frnd(srcptr,nullptr,dstptr,status)
31  *	sgl_frnd(srcptr,nullptr,dstptr,status)
32  *
33  * END_DESC
34 */
35 
36 
37 #include "float.h"
38 #include "sgl_float.h"
39 #include "dbl_float.h"
40 #include "cnv_float.h"
41 
42 /*
43  *  Single Floating-point Round to Integer
44  */
45 
46 /*ARGSUSED*/
47 int
48 sgl_frnd(sgl_floating_point *srcptr,
49 	unsigned int *nullptr,
50 	sgl_floating_point *dstptr,
51 	unsigned int *status)
52 {
53 	register unsigned int src, result;
54 	register int src_exponent;
55 	register boolean inexact = FALSE;
56 
57 	src = *srcptr;
58         /*
59          * check source operand for NaN or infinity
60          */
61         if ((src_exponent = Sgl_exponent(src)) == SGL_INFINITY_EXPONENT) {
62                 /*
63                  * is signaling NaN?
64                  */
65                 if (Sgl_isone_signaling(src)) {
66                         /* trap if INVALIDTRAP enabled */
67                         if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
68                         /* make NaN quiet */
69                         Set_invalidflag();
70                         Sgl_set_quiet(src);
71                 }
72                 /*
73                  * return quiet NaN or infinity
74                  */
75                 *dstptr = src;
76                 return(NOEXCEPTION);
77         }
78 	/*
79 	 * Need to round?
80 	 */
81 	if ((src_exponent -= SGL_BIAS) >= SGL_P - 1) {
82 		*dstptr = src;
83 		return(NOEXCEPTION);
84 	}
85 	/*
86 	 * Generate result
87 	 */
88 	if (src_exponent >= 0) {
89 		Sgl_clear_exponent_set_hidden(src);
90 		result = src;
91 		Sgl_rightshift(result,(SGL_P-1) - (src_exponent));
92 		/* check for inexact */
93 		if (Sgl_isinexact_to_fix(src,src_exponent)) {
94 			inexact = TRUE;
95 			/*  round result  */
96 			switch (Rounding_mode()) {
97 			case ROUNDPLUS:
98 			     if (Sgl_iszero_sign(src)) Sgl_increment(result);
99 			     break;
100 			case ROUNDMINUS:
101 			     if (Sgl_isone_sign(src)) Sgl_increment(result);
102 			     break;
103 			case ROUNDNEAREST:
104 			     if (Sgl_isone_roundbit(src,src_exponent))
105 			        if (Sgl_isone_stickybit(src,src_exponent)
106 				|| (Sgl_isone_lowmantissa(result)))
107 					Sgl_increment(result);
108 			}
109 		}
110 		Sgl_leftshift(result,(SGL_P-1) - (src_exponent));
111 		if (Sgl_isone_hiddenoverflow(result))
112 			Sgl_set_exponent(result,src_exponent + (SGL_BIAS+1));
113 		else Sgl_set_exponent(result,src_exponent + SGL_BIAS);
114 	}
115 	else {
116 		result = src;  		/* set sign */
117 		Sgl_setzero_exponentmantissa(result);
118 		/* check for inexact */
119 		if (Sgl_isnotzero_exponentmantissa(src)) {
120 			inexact = TRUE;
121 			/*  round result  */
122 			switch (Rounding_mode()) {
123 			case ROUNDPLUS:
124 			     if (Sgl_iszero_sign(src))
125 				Sgl_set_exponent(result,SGL_BIAS);
126 			     break;
127 			case ROUNDMINUS:
128 			     if (Sgl_isone_sign(src))
129 				Sgl_set_exponent(result,SGL_BIAS);
130 			     break;
131 			case ROUNDNEAREST:
132 			     if (src_exponent == -1)
133 			        if (Sgl_isnotzero_mantissa(src))
134 				   Sgl_set_exponent(result,SGL_BIAS);
135 			}
136 		}
137 	}
138 	*dstptr = result;
139 	if (inexact) {
140 		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
141 		else Set_inexactflag();
142 	}
143 	return(NOEXCEPTION);
144 }
145 
146 /*
147  *  Double Floating-point Round to Integer
148  */
149 
150 /*ARGSUSED*/
151 int
152 dbl_frnd(
153 	dbl_floating_point *srcptr,
154 	unsigned int *nullptr,
155 	dbl_floating_point *dstptr,
156 	unsigned int *status)
157 {
158 	register unsigned int srcp1, srcp2, resultp1, resultp2;
159 	register int src_exponent;
160 	register boolean inexact = FALSE;
161 
162 	Dbl_copyfromptr(srcptr,srcp1,srcp2);
163         /*
164          * check source operand for NaN or infinity
165          */
166         if ((src_exponent = Dbl_exponent(srcp1)) == DBL_INFINITY_EXPONENT) {
167                 /*
168                  * is signaling NaN?
169                  */
170                 if (Dbl_isone_signaling(srcp1)) {
171                         /* trap if INVALIDTRAP enabled */
172                         if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
173                         /* make NaN quiet */
174                         Set_invalidflag();
175                         Dbl_set_quiet(srcp1);
176                 }
177                 /*
178                  * return quiet NaN or infinity
179                  */
180                 Dbl_copytoptr(srcp1,srcp2,dstptr);
181                 return(NOEXCEPTION);
182         }
183 	/*
184 	 * Need to round?
185 	 */
186 	if ((src_exponent -= DBL_BIAS) >= DBL_P - 1) {
187 		Dbl_copytoptr(srcp1,srcp2,dstptr);
188 		return(NOEXCEPTION);
189 	}
190 	/*
191 	 * Generate result
192 	 */
193 	if (src_exponent >= 0) {
194 		Dbl_clear_exponent_set_hidden(srcp1);
195 		resultp1 = srcp1;
196 		resultp2 = srcp2;
197 		Dbl_rightshift(resultp1,resultp2,(DBL_P-1) - (src_exponent));
198 		/* check for inexact */
199 		if (Dbl_isinexact_to_fix(srcp1,srcp2,src_exponent)) {
200 			inexact = TRUE;
201 			/*  round result  */
202 			switch (Rounding_mode()) {
203 			case ROUNDPLUS:
204 			     if (Dbl_iszero_sign(srcp1))
205 				Dbl_increment(resultp1,resultp2);
206 			     break;
207 			case ROUNDMINUS:
208 			     if (Dbl_isone_sign(srcp1))
209 				Dbl_increment(resultp1,resultp2);
210 			     break;
211 			case ROUNDNEAREST:
212 			     if (Dbl_isone_roundbit(srcp1,srcp2,src_exponent))
213 			      if (Dbl_isone_stickybit(srcp1,srcp2,src_exponent)
214 				  || (Dbl_isone_lowmantissap2(resultp2)))
215 					Dbl_increment(resultp1,resultp2);
216 			}
217 		}
218 		Dbl_leftshift(resultp1,resultp2,(DBL_P-1) - (src_exponent));
219 		if (Dbl_isone_hiddenoverflow(resultp1))
220 			Dbl_set_exponent(resultp1,src_exponent + (DBL_BIAS+1));
221 		else Dbl_set_exponent(resultp1,src_exponent + DBL_BIAS);
222 	}
223 	else {
224 		resultp1 = srcp1;  /* set sign */
225 		Dbl_setzero_exponentmantissa(resultp1,resultp2);
226 		/* check for inexact */
227 		if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
228 			inexact = TRUE;
229 			/*  round result  */
230 			switch (Rounding_mode()) {
231 			case ROUNDPLUS:
232 			     if (Dbl_iszero_sign(srcp1))
233 				Dbl_set_exponent(resultp1,DBL_BIAS);
234 			     break;
235 			case ROUNDMINUS:
236 			     if (Dbl_isone_sign(srcp1))
237 				Dbl_set_exponent(resultp1,DBL_BIAS);
238 			     break;
239 			case ROUNDNEAREST:
240 			     if (src_exponent == -1)
241 			        if (Dbl_isnotzero_mantissa(srcp1,srcp2))
242 				   Dbl_set_exponent(resultp1,DBL_BIAS);
243 			}
244 		}
245 	}
246 	Dbl_copytoptr(resultp1,resultp2,dstptr);
247 	if (inexact) {
248 		if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
249 		else Set_inexactflag();
250 	}
251 	return(NOEXCEPTION);
252 }
253