1 
2 /*        $OpenBSD: fcnvfx.c,v 1.8 2010/07/30 18:05:23 kettenis Exp $ */
3 
4 /*
5  * Copyright 1996 1995 by Open Software Foundation, Inc.
6  *              All Rights Reserved
7  *
8  * Permission to use, copy, modify, and distribute this software and
9  * its documentation for any purpose and without fee is hereby granted,
10  * provided that the above copyright notice appears in all copies and
11  * that both the copyright notice and this permission notice appear in
12  * supporting documentation.
13  *
14  * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
16  * FOR A PARTICULAR PURPOSE.
17  *
18  * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
19  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
20  * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
21  * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
22  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23  *
24  */
25 /*
26  * pmk1.1
27  */
28 /*
29  * (c) Copyright 1986 HEWLETT-PACKARD COMPANY
30  *
31  * To anyone who acknowledges that this file is provided "AS IS"
32  * without any express or implied warranty:
33  *     permission to use, copy, modify, and distribute this file
34  * for any purpose is hereby granted without fee, provided that
35  * the above copyright notice and this notice appears in all
36  * copies, and that the name of Hewlett-Packard Company not be
37  * used in advertising or publicity pertaining to distribution
38  * of the software without specific, written prior permission.
39  * Hewlett-Packard Company makes no representations about the
40  * suitability of this software for any purpose.
41  */
42 
43 #include <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: fcnvfx.c,v 1.6 2012/02/04 17:03:09 skrll Exp $");
45 
46 #include "../spmath/float.h"
47 #include "../spmath/sgl_float.h"
48 #include "../spmath/dbl_float.h"
49 #include "../spmath/cnv_float.h"
50 
51 /*
52  *  Single Floating-point to Single Fixed-point
53  */
54 /*ARGSUSED*/
55 int
sgl_to_sgl_fcnvfx(sgl_floating_point * srcptr,int * dstptr,unsigned int * status)56 sgl_to_sgl_fcnvfx(sgl_floating_point *srcptr, int *dstptr,
57     unsigned int *status)
58 {
59           register unsigned int src, temp;
60           register int src_exponent, result;
61           register int inexact = false;
62 
63           src = *srcptr;
64           src_exponent = Sgl_exponent(src) - SGL_BIAS;
65 
66           /*
67            * Test for overflow
68            */
69           if (src_exponent > SGL_FX_MAX_EXP) {
70                     /* check for MININT */
71                     if ((src_exponent > SGL_FX_MAX_EXP + 1) ||
72                     Sgl_isnotzero_mantissa(src) || Sgl_iszero_sign(src)) {
73                               if (Sgl_iszero_sign(src)) result = 0x7fffffff;
74                               else result = 0x80000000;
75 
76                               if (Is_invalidtrap_enabled()) {
77                                         return(INVALIDEXCEPTION);
78                               }
79                               Set_invalidflag();
80                               *dstptr = result;
81                               return(NOEXCEPTION);
82                     }
83           }
84           /*
85            * Generate result
86            */
87           if (src_exponent >= 0) {
88                     temp = src;
89                     Sgl_clear_signexponent_set_hidden(temp);
90                     Int_from_sgl_mantissa(temp,src_exponent);
91                     if (Sgl_isone_sign(src))  result = -Sgl_all(temp);
92                     else result = Sgl_all(temp);
93 
94                     /* check for inexact */
95                     if (Sgl_isinexact_to_fix(src,src_exponent)) {
96                               inexact = true;
97                               /*  round result  */
98                               switch (Rounding_mode()) {
99                               case ROUNDPLUS:
100                                    if (Sgl_iszero_sign(src)) result++;
101                                    break;
102                               case ROUNDMINUS:
103                                    if (Sgl_isone_sign(src)) result--;
104                                    break;
105                               case ROUNDNEAREST:
106                                    if (Sgl_isone_roundbit(src,src_exponent)) {
107                                         if (Sgl_isone_stickybit(src,src_exponent)
108                                         || (Sgl_isone_lowmantissa(temp))) {
109                                            if (Sgl_iszero_sign(src)) result++;
110                                            else result--;
111                                         }
112                                    }
113                               }
114                     }
115           }
116           else {
117                     result = 0;
118 
119                     /* check for inexact */
120                     if (Sgl_isnotzero_exponentmantissa(src)) {
121                               inexact = true;
122                               /*  round result  */
123                               switch (Rounding_mode()) {
124                               case ROUNDPLUS:
125                                    if (Sgl_iszero_sign(src)) result++;
126                                    break;
127                               case ROUNDMINUS:
128                                    if (Sgl_isone_sign(src)) result--;
129                                    break;
130                               case ROUNDNEAREST:
131                                    if (src_exponent == -1)
132                                         if (Sgl_isnotzero_mantissa(src)) {
133                                            if (Sgl_iszero_sign(src)) result++;
134                                            else result--;
135                                         }
136                               }
137                     }
138           }
139           *dstptr = result;
140           if (inexact) {
141                     if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
142                     else Set_inexactflag();
143           }
144           return(NOEXCEPTION);
145 }
146 
147 /*
148  *  Single Floating-point to Double Fixed-point
149  */
150 /*ARGSUSED*/
151 int
sgl_to_dbl_fcnvfx(sgl_floating_point * srcptr,dbl_integer * dstptr,unsigned int * status)152 sgl_to_dbl_fcnvfx(sgl_floating_point *srcptr, dbl_integer *dstptr,
153     unsigned int *status)
154 {
155           register int src_exponent, resultp1;
156           register unsigned int src, temp, resultp2;
157           register int inexact = false;
158 
159           src = *srcptr;
160           src_exponent = Sgl_exponent(src) - SGL_BIAS;
161 
162           /*
163            * Test for overflow
164            */
165           if (src_exponent > DBL_FX_MAX_EXP) {
166                     /* check for MININT */
167                     if ((src_exponent > DBL_FX_MAX_EXP + 1) ||
168                     Sgl_isnotzero_mantissa(src) || Sgl_iszero_sign(src)) {
169                               if (Sgl_iszero_sign(src)) {
170                                         resultp1 = 0x7fffffff;
171                                         resultp2 = 0xffffffff;
172                               }
173                               else {
174                                         resultp1 = 0x80000000;
175                                         resultp2 = 0;
176                               }
177 
178                               if (Is_invalidtrap_enabled()) {
179                                         return(INVALIDEXCEPTION);
180                               }
181                               Set_invalidflag();
182                               Dint_copytoptr(resultp1,resultp2,dstptr);
183                               return(NOEXCEPTION);
184                     }
185                     Dint_set_minint(resultp1,resultp2);
186                     Dint_copytoptr(resultp1,resultp2,dstptr);
187                     return(NOEXCEPTION);
188           }
189           /*
190            * Generate result
191            */
192           if (src_exponent >= 0) {
193                     temp = src;
194                     Sgl_clear_signexponent_set_hidden(temp);
195                     Dint_from_sgl_mantissa(temp,src_exponent,resultp1,resultp2);
196                     if (Sgl_isone_sign(src)) {
197                               Dint_setone_sign(resultp1,resultp2);
198                     }
199 
200                     /* check for inexact */
201                     if (Sgl_isinexact_to_fix(src,src_exponent)) {
202                               inexact = true;
203                               /*  round result  */
204                               switch (Rounding_mode()) {
205                               case ROUNDPLUS:
206                                    if (Sgl_iszero_sign(src)) {
207                                         Dint_increment(resultp1,resultp2);
208                                    }
209                                    break;
210                               case ROUNDMINUS:
211                                    if (Sgl_isone_sign(src)) {
212                                         Dint_decrement(resultp1,resultp2);
213                                    }
214                                    break;
215                               case ROUNDNEAREST:
216                                    if (Sgl_isone_roundbit(src,src_exponent))
217                                         if (Sgl_isone_stickybit(src,src_exponent) ||
218                                         (Dint_isone_lowp2(resultp2))) {
219                                            if (Sgl_iszero_sign(src)) {
220                                               Dint_increment(resultp1,resultp2);
221                                            }
222                                            else {
223                                               Dint_decrement(resultp1,resultp2);
224                                            }
225                                         }
226                               }
227                     }
228           }
229           else {
230                     Dint_setzero(resultp1,resultp2);
231 
232                     /* check for inexact */
233                     if (Sgl_isnotzero_exponentmantissa(src)) {
234                               inexact = true;
235                               /*  round result  */
236                               switch (Rounding_mode()) {
237                               case ROUNDPLUS:
238                                    if (Sgl_iszero_sign(src)) {
239                                         Dint_increment(resultp1,resultp2);
240                                    }
241                                    break;
242                               case ROUNDMINUS:
243                                    if (Sgl_isone_sign(src)) {
244                                         Dint_decrement(resultp1,resultp2);
245                                    }
246                                    break;
247                               case ROUNDNEAREST:
248                                    if (src_exponent == -1)
249                                         if (Sgl_isnotzero_mantissa(src)) {
250                                            if (Sgl_iszero_sign(src)) {
251                                               Dint_increment(resultp1,resultp2);
252                                            }
253                                            else {
254                                               Dint_decrement(resultp1,resultp2);
255                                            }
256                                         }
257                               }
258                     }
259           }
260           Dint_copytoptr(resultp1,resultp2,dstptr);
261           if (inexact) {
262                     if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
263                     else Set_inexactflag();
264           }
265           return(NOEXCEPTION);
266 }
267 
268 /*
269  *  Double Floating-point to Single Fixed-point
270  */
271 /*ARGSUSED*/
272 int
dbl_to_sgl_fcnvfx(dbl_floating_point * srcptr,int * dstptr,unsigned int * status)273 dbl_to_sgl_fcnvfx(dbl_floating_point *srcptr, int *dstptr,
274    unsigned int *status)
275 {
276           register unsigned int srcp1,srcp2, tempp1,tempp2;
277           register int src_exponent, result;
278           register int inexact = false;
279 
280           Dbl_copyfromptr(srcptr,srcp1,srcp2);
281           src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
282 
283           /*
284            * Test for overflow
285            */
286           if (src_exponent > SGL_FX_MAX_EXP) {
287                     /* check for MININT */
288                     if (Dbl_isoverflow_to_int(src_exponent,srcp1,srcp2)) {
289                               if (Dbl_iszero_sign(srcp1)) result = 0x7fffffff;
290                               else result = 0x80000000;
291 
292                               if (Is_invalidtrap_enabled()) {
293                                         return(INVALIDEXCEPTION);
294                               }
295                               Set_invalidflag();
296                               *dstptr = result;
297                               return(NOEXCEPTION);
298                     }
299           }
300           /*
301            * Generate result
302            */
303           if (src_exponent >= 0) {
304                     tempp1 = srcp1;
305                     tempp2 = srcp2;
306                     Dbl_clear_signexponent_set_hidden(tempp1);
307                     Int_from_dbl_mantissa(tempp1,tempp2,src_exponent);
308                     if (Dbl_isone_sign(srcp1) && (src_exponent <= SGL_FX_MAX_EXP))
309                               result = -Dbl_allp1(tempp1);
310                     else result = Dbl_allp1(tempp1);
311 
312                     /* check for inexact */
313                     if (Dbl_isinexact_to_fix(srcp1,srcp2,src_exponent)) {
314                               inexact = true;
315                               /*  round result  */
316                               switch (Rounding_mode()) {
317                               case ROUNDPLUS:
318                                         if (Dbl_iszero_sign(srcp1))
319                                                   result++;
320                                    break;
321                               case ROUNDMINUS:
322                                    if (Dbl_isone_sign(srcp1)) result--;
323                                    break;
324                               case ROUNDNEAREST:
325                                    if (Dbl_isone_roundbit(srcp1,srcp2,src_exponent))
326                                         if (Dbl_isone_stickybit(srcp1,srcp2,src_exponent) ||
327                                         (Dbl_isone_lowmantissap1(tempp1))) {
328                                            if (Dbl_iszero_sign(srcp1)) result++;
329                                            else result--;
330                                         }
331                               }
332                               /* check for overflow */
333                               if ((Dbl_iszero_sign(srcp1) && result < 0) ||
334                                   (Dbl_isone_sign(srcp1) && result > 0)) {
335 
336                                         if (Dbl_iszero_sign(srcp1))
337                                                   result = 0x7fffffff;
338                                         else
339                                                   result = 0x80000000;
340 
341                                   if (Is_overflowtrap_enabled()) {
342                                   if (Is_inexacttrap_enabled())
343                                     return(OVERFLOWEXCEPTION|INEXACTEXCEPTION);
344                                   else Set_inexactflag();
345                                   return(OVERFLOWEXCEPTION);
346                                   }
347                                 Set_overflowflag();
348                                 *dstptr = result;
349                                 if (Is_inexacttrap_enabled() )
350                                         return(INEXACTEXCEPTION);
351                                 else Set_inexactflag();
352                                 return(NOEXCEPTION);
353                               }
354                     }
355           }
356           else {
357                     result = 0;
358 
359                     /* check for inexact */
360                     if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
361                               inexact = true;
362                               /*  round result  */
363                               switch (Rounding_mode()) {
364                               case ROUNDPLUS:
365                                    if (Dbl_iszero_sign(srcp1)) result++;
366                                    break;
367                               case ROUNDMINUS:
368                                    if (Dbl_isone_sign(srcp1)) result--;
369                                    break;
370                               case ROUNDNEAREST:
371                                    if (src_exponent == -1)
372                                         if (Dbl_isnotzero_mantissa(srcp1,srcp2)) {
373                                            if (Dbl_iszero_sign(srcp1)) result++;
374                                            else result--;
375                                         }
376                               }
377                     }
378           }
379           *dstptr = result;
380           if (inexact) {
381                     if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
382                     else Set_inexactflag();
383           }
384           return(NOEXCEPTION);
385 }
386 
387 /*
388  *  Double Floating-point to Double Fixed-point
389  */
390 /*ARGSUSED*/
391 int
dbl_to_dbl_fcnvfx(dbl_floating_point * srcptr,dbl_integer * dstptr,unsigned int * status)392 dbl_to_dbl_fcnvfx(dbl_floating_point *srcptr, dbl_integer *dstptr,
393     unsigned int *status)
394 {
395           register int src_exponent, resultp1;
396           register unsigned int srcp1, srcp2, tempp1, tempp2, resultp2;
397           register int inexact = false;
398 
399           Dbl_copyfromptr(srcptr,srcp1,srcp2);
400           src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
401 
402           /*
403            * Test for overflow
404            */
405           if (src_exponent > DBL_FX_MAX_EXP) {
406                     /* check for MININT */
407                     if ((src_exponent > DBL_FX_MAX_EXP + 1) ||
408                     Dbl_isnotzero_mantissa(srcp1,srcp2) || Dbl_iszero_sign(srcp1)) {
409                               if (Dbl_iszero_sign(srcp1)) {
410                                         resultp1 = 0x7fffffff;
411                                         resultp2 = 0xffffffff;
412                               }
413                               else {
414                                         resultp1 = 0x80000000;
415                                         resultp2 = 0;
416                               }
417 
418                               if (Is_invalidtrap_enabled()) {
419                                         return(INVALIDEXCEPTION);
420                               }
421                               Set_invalidflag();
422                               Dint_copytoptr(resultp1,resultp2,dstptr);
423                               return(NOEXCEPTION);
424                     }
425           }
426 
427           /*
428            * Generate result
429            */
430           if (src_exponent >= 0) {
431                     tempp1 = srcp1;
432                     tempp2 = srcp2;
433                     Dbl_clear_signexponent_set_hidden(tempp1);
434                     Dint_from_dbl_mantissa(tempp1,tempp2,src_exponent,
435                                                resultp1, resultp2);
436                     if (Dbl_isone_sign(srcp1)) {
437                               Dint_setone_sign(resultp1,resultp2);
438                     }
439 
440                     /* check for inexact */
441                     if (Dbl_isinexact_to_fix(srcp1,srcp2,src_exponent)) {
442                               inexact = true;
443                               /*  round result  */
444                               switch (Rounding_mode()) {
445                               case ROUNDPLUS:
446                                    if (Dbl_iszero_sign(srcp1)) {
447                                         Dint_increment(resultp1,resultp2);
448                                    }
449                                    break;
450                               case ROUNDMINUS:
451                                    if (Dbl_isone_sign(srcp1)) {
452                                         Dint_decrement(resultp1,resultp2);
453                                    }
454                                    break;
455                               case ROUNDNEAREST:
456                                    if (Dbl_isone_roundbit(srcp1,srcp2,src_exponent))
457                                         if (Dbl_isone_stickybit(srcp1,srcp2,src_exponent) ||
458                                         (Dint_isone_lowp2(resultp2))) {
459                                            if (Dbl_iszero_sign(srcp1)) {
460                                               Dint_increment(resultp1,resultp2);
461                                            }
462                                            else {
463                                               Dint_decrement(resultp1,resultp2);
464                                            }
465                                         }
466                               }
467                     }
468           }
469           else {
470                     Dint_setzero(resultp1,resultp2);
471 
472                     /* check for inexact */
473                     if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
474                               inexact = true;
475                               /*  round result  */
476                               switch (Rounding_mode()) {
477                               case ROUNDPLUS:
478                                    if (Dbl_iszero_sign(srcp1)) {
479                                         Dint_increment(resultp1,resultp2);
480                                    }
481                                    break;
482                               case ROUNDMINUS:
483                                    if (Dbl_isone_sign(srcp1)) {
484                                         Dint_decrement(resultp1,resultp2);
485                                    }
486                                    break;
487                               case ROUNDNEAREST:
488                                    if (src_exponent == -1)
489                                         if (Dbl_isnotzero_mantissa(srcp1,srcp2)) {
490                                            if (Dbl_iszero_sign(srcp1)) {
491                                               Dint_increment(resultp1,resultp2);
492                                            }
493                                            else {
494                                               Dint_decrement(resultp1,resultp2);
495                                            }
496                                         }
497                               }
498                     }
499           }
500           Dint_copytoptr(resultp1,resultp2,dstptr);
501           if (inexact) {
502                     if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
503                     else Set_inexactflag();
504           }
505           return(NOEXCEPTION);
506 }
507