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., 675 Mass Ave, Cambridge, MA 02139, 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*/
47int
48sgl_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*/
151int
152dbl_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