Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/shaggy...
[linux-2.6] / arch / parisc / math-emu / frnd.c
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 }