Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
sfdiv.c
Go to the documentation of this file.
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) <[email protected]>
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  * File:
25  * @(#) pa/spmath/sfdiv.c $Revision: 1.1 $
26  *
27  * Purpose:
28  * Single Precision Floating-point Divide
29  *
30  * External Interfaces:
31  * sgl_fdiv(srcptr1,srcptr2,dstptr,status)
32  *
33  * Internal Interfaces:
34  *
35  * Theory:
36  * <<please update with a overview of the operation of this file>>
37  *
38  * END_DESC
39 */
40 
41 
42 #include "float.h"
43 #include "sgl_float.h"
44 
45 /*
46  * Single Precision Floating-point Divide
47  */
48 
49 int
51  sgl_floating_point * dstptr, unsigned int *status)
52 {
53  register unsigned int opnd1, opnd2, opnd3, result;
54  register int dest_exponent, count;
55  register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE;
56  boolean is_tiny;
57 
58  opnd1 = *srcptr1;
59  opnd2 = *srcptr2;
60  /*
61  * set sign bit of result
62  */
63  if (Sgl_sign(opnd1) ^ Sgl_sign(opnd2)) Sgl_setnegativezero(result);
64  else Sgl_setzero(result);
65  /*
66  * check first operand for NaN's or infinity
67  */
68  if (Sgl_isinfinity_exponent(opnd1)) {
69  if (Sgl_iszero_mantissa(opnd1)) {
70  if (Sgl_isnotnan(opnd2)) {
71  if (Sgl_isinfinity(opnd2)) {
72  /*
73  * invalid since both operands
74  * are infinity
75  */
77  return(INVALIDEXCEPTION);
79  Sgl_makequietnan(result);
80  *dstptr = result;
81  return(NOEXCEPTION);
82  }
83  /*
84  * return infinity
85  */
87  *dstptr = result;
88  return(NOEXCEPTION);
89  }
90  }
91  else {
92  /*
93  * is NaN; signaling or quiet?
94  */
95  if (Sgl_isone_signaling(opnd1)) {
96  /* trap if INVALIDTRAP enabled */
98  return(INVALIDEXCEPTION);
99  /* make NaN quiet */
100  Set_invalidflag();
101  Sgl_set_quiet(opnd1);
102  }
103  /*
104  * is second operand a signaling NaN?
105  */
106  else if (Sgl_is_signalingnan(opnd2)) {
107  /* trap if INVALIDTRAP enabled */
109  return(INVALIDEXCEPTION);
110  /* make NaN quiet */
111  Set_invalidflag();
112  Sgl_set_quiet(opnd2);
113  *dstptr = opnd2;
114  return(NOEXCEPTION);
115  }
116  /*
117  * return quiet NaN
118  */
119  *dstptr = opnd1;
120  return(NOEXCEPTION);
121  }
122  }
123  /*
124  * check second operand for NaN's or infinity
125  */
126  if (Sgl_isinfinity_exponent(opnd2)) {
127  if (Sgl_iszero_mantissa(opnd2)) {
128  /*
129  * return zero
130  */
132  *dstptr = result;
133  return(NOEXCEPTION);
134  }
135  /*
136  * is NaN; signaling or quiet?
137  */
138  if (Sgl_isone_signaling(opnd2)) {
139  /* trap if INVALIDTRAP enabled */
141  /* make NaN quiet */
142  Set_invalidflag();
143  Sgl_set_quiet(opnd2);
144  }
145  /*
146  * return quiet NaN
147  */
148  *dstptr = opnd2;
149  return(NOEXCEPTION);
150  }
151  /*
152  * check for division by zero
153  */
154  if (Sgl_iszero_exponentmantissa(opnd2)) {
155  if (Sgl_iszero_exponentmantissa(opnd1)) {
156  /* invalid since both operands are zero */
158  Set_invalidflag();
159  Sgl_makequietnan(result);
160  *dstptr = result;
161  return(NOEXCEPTION);
162  }
164  return(DIVISIONBYZEROEXCEPTION);
167  *dstptr = result;
168  return(NOEXCEPTION);
169  }
170  /*
171  * Generate exponent
172  */
173  dest_exponent = Sgl_exponent(opnd1) - Sgl_exponent(opnd2) + SGL_BIAS;
174 
175  /*
176  * Generate mantissa
177  */
178  if (Sgl_isnotzero_exponent(opnd1)) {
179  /* set hidden bit */
181  }
182  else {
183  /* check for zero */
184  if (Sgl_iszero_mantissa(opnd1)) {
186  *dstptr = result;
187  return(NOEXCEPTION);
188  }
189  /* is denormalized; want to normalize */
190  Sgl_clear_signexponent(opnd1);
191  Sgl_leftshiftby1(opnd1);
192  Sgl_normalize(opnd1,dest_exponent);
193  }
194  /* opnd2 needs to have hidden bit set with msb in hidden bit */
195  if (Sgl_isnotzero_exponent(opnd2)) {
197  }
198  else {
199  /* is denormalized; want to normalize */
200  Sgl_clear_signexponent(opnd2);
201  Sgl_leftshiftby1(opnd2);
202  while(Sgl_iszero_hiddenhigh7mantissa(opnd2)) {
203  Sgl_leftshiftby8(opnd2);
204  dest_exponent += 8;
205  }
206  if(Sgl_iszero_hiddenhigh3mantissa(opnd2)) {
207  Sgl_leftshiftby4(opnd2);
208  dest_exponent += 4;
209  }
210  while(Sgl_iszero_hidden(opnd2)) {
211  Sgl_leftshiftby1(opnd2);
212  dest_exponent += 1;
213  }
214  }
215 
216  /* Divide the source mantissas */
217 
218  /*
219  * A non_restoring divide algorithm is used.
220  */
221  Sgl_subtract(opnd1,opnd2,opnd1);
222  Sgl_setzero(opnd3);
223  for (count=1;count<=SGL_P && Sgl_all(opnd1);count++) {
224  Sgl_leftshiftby1(opnd1);
225  Sgl_leftshiftby1(opnd3);
226  if (Sgl_iszero_sign(opnd1)) {
227  Sgl_setone_lowmantissa(opnd3);
228  Sgl_subtract(opnd1,opnd2,opnd1);
229  }
230  else Sgl_addition(opnd1,opnd2,opnd1);
231  }
232  if (count <= SGL_P) {
233  Sgl_leftshiftby1(opnd3);
234  Sgl_setone_lowmantissa(opnd3);
235  Sgl_leftshift(opnd3,SGL_P-count);
236  if (Sgl_iszero_hidden(opnd3)) {
237  Sgl_leftshiftby1(opnd3);
238  dest_exponent--;
239  }
240  }
241  else {
242  if (Sgl_iszero_hidden(opnd3)) {
243  /* need to get one more bit of result */
244  Sgl_leftshiftby1(opnd1);
245  Sgl_leftshiftby1(opnd3);
246  if (Sgl_iszero_sign(opnd1)) {
247  Sgl_setone_lowmantissa(opnd3);
248  Sgl_subtract(opnd1,opnd2,opnd1);
249  }
250  else Sgl_addition(opnd1,opnd2,opnd1);
251  dest_exponent--;
252  }
253  if (Sgl_iszero_sign(opnd1)) guardbit = TRUE;
254  stickybit = Sgl_all(opnd1);
255  }
256  inexact = guardbit | stickybit;
257 
258  /*
259  * round result
260  */
261  if (inexact && (dest_exponent > 0 || Is_underflowtrap_enabled())) {
262  Sgl_clear_signexponent(opnd3);
263  switch (Rounding_mode()) {
264  case ROUNDPLUS:
265  if (Sgl_iszero_sign(result))
266  Sgl_increment_mantissa(opnd3);
267  break;
268  case ROUNDMINUS:
269  if (Sgl_isone_sign(result))
270  Sgl_increment_mantissa(opnd3);
271  break;
272  case ROUNDNEAREST:
273  if (guardbit) {
274  if (stickybit || Sgl_isone_lowmantissa(opnd3))
275  Sgl_increment_mantissa(opnd3);
276  }
277  }
278  if (Sgl_isone_hidden(opnd3)) dest_exponent++;
279  }
280  Sgl_set_mantissa(result,opnd3);
281 
282  /*
283  * Test for overflow
284  */
285  if (dest_exponent >= SGL_INFINITY_EXPONENT) {
286  /* trap if OVERFLOWTRAP enabled */
287  if (Is_overflowtrap_enabled()) {
288  /*
289  * Adjust bias of result
290  */
291  Sgl_setwrapped_exponent(result,dest_exponent,ovfl);
292  *dstptr = result;
293  if (inexact)
296  else Set_inexactflag();
297  return(OVERFLOWEXCEPTION);
298  }
300  /* set result to infinity or largest number */
301  Sgl_setoverflow(result);
302  inexact = TRUE;
303  }
304  /*
305  * Test for underflow
306  */
307  else if (dest_exponent <= 0) {
308  /* trap if UNDERFLOWTRAP enabled */
309  if (Is_underflowtrap_enabled()) {
310  /*
311  * Adjust bias of result
312  */
313  Sgl_setwrapped_exponent(result,dest_exponent,unfl);
314  *dstptr = result;
315  if (inexact)
318  else Set_inexactflag();
319  return(UNDERFLOWEXCEPTION);
320  }
321 
322  /* Determine if should set underflow flag */
323  is_tiny = TRUE;
324  if (dest_exponent == 0 && inexact) {
325  switch (Rounding_mode()) {
326  case ROUNDPLUS:
327  if (Sgl_iszero_sign(result)) {
328  Sgl_increment(opnd3);
329  if (Sgl_isone_hiddenoverflow(opnd3))
330  is_tiny = FALSE;
331  Sgl_decrement(opnd3);
332  }
333  break;
334  case ROUNDMINUS:
335  if (Sgl_isone_sign(result)) {
336  Sgl_increment(opnd3);
337  if (Sgl_isone_hiddenoverflow(opnd3))
338  is_tiny = FALSE;
339  Sgl_decrement(opnd3);
340  }
341  break;
342  case ROUNDNEAREST:
343  if (guardbit && (stickybit ||
344  Sgl_isone_lowmantissa(opnd3))) {
345  Sgl_increment(opnd3);
346  if (Sgl_isone_hiddenoverflow(opnd3))
347  is_tiny = FALSE;
348  Sgl_decrement(opnd3);
349  }
350  break;
351  }
352  }
353 
354  /*
355  * denormalize result or set to signed zero
356  */
357  stickybit = inexact;
358  Sgl_denormalize(opnd3,dest_exponent,guardbit,stickybit,inexact);
359 
360  /* return rounded number */
361  if (inexact) {
362  switch (Rounding_mode()) {
363  case ROUNDPLUS:
364  if (Sgl_iszero_sign(result)) {
365  Sgl_increment(opnd3);
366  }
367  break;
368  case ROUNDMINUS:
369  if (Sgl_isone_sign(result)) {
370  Sgl_increment(opnd3);
371  }
372  break;
373  case ROUNDNEAREST:
374  if (guardbit && (stickybit ||
375  Sgl_isone_lowmantissa(opnd3))) {
376  Sgl_increment(opnd3);
377  }
378  break;
379  }
380  if (is_tiny) Set_underflowflag();
381  }
382  Sgl_set_exponentmantissa(result,opnd3);
383  }
384  else Sgl_set_exponent(result,dest_exponent);
385  *dstptr = result;
386  /* check for inexact */
387  if (inexact) {
389  else Set_inexactflag();
390  }
391  return(NOEXCEPTION);
392 }