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.5 2012/01/01 20:04:36 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*/ 55int 56sgl_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*/ 151int 152sgl_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*/ 272int 273dbl_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*/ 391int 392dbl_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