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