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