Open64 (mfef90, whirl2f, and IR tools)  TAG: version-openad; SVN changeset: 916
ieee_norm.c
Go to the documentation of this file.
00001 /*
00002 
00003   Copyright (C) 2000, 2001 Silicon Graphics, Inc.  All Rights Reserved.
00004 
00005   This program is free software; you can redistribute it and/or modify it
00006   under the terms of version 2 of the GNU General Public License as
00007   published by the Free Software Foundation.
00008 
00009   This program is distributed in the hope that it would be useful, but
00010   WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
00012 
00013   Further, this software is distributed without any warranty that it is
00014   free of the rightful claim of any third person regarding infringement 
00015   or the like.  Any license provided herein, whether implied or 
00016   otherwise, applies only to this software file.  Patent licenses, if 
00017   any, provided herein do not apply to combinations of this program with 
00018   other software, or any other product whatsoever.  
00019 
00020   You should have received a copy of the GNU General Public License along
00021   with this program; if not, write the Free Software Foundation, Inc., 59
00022   Temple Place - Suite 330, Boston MA 02111-1307, USA.
00023 
00024   Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pky,
00025   Mountain View, CA 94043, or:
00026 
00027   http://www.sgi.com
00028 
00029   For further information regarding this notice, see:
00030 
00031   http://oss.sgi.com/projects/GenInfo/NoticeExplan
00032 
00033 */
00034 
00035 
00036 /*
00037  *      Common IEEE 754 normalization routines
00038  */
00039 
00040 #include "arith.internal.h"
00041 
00042 
00043 /* Normalization, rounding, and final processing common to all IEEE
00044  * arithmetic
00045  */
00046 
00047 int
00048 ar_i32norm (signed int expo,            /* exponent */
00049                         unsigned long lbits,    /* left-hand bits */
00050                         unsigned long rbits,    /* right-hand rounding bits */
00051                         AR_IEEE_32 *x,                  /* result to package; coeff and sign */
00052                         int roundmode) {                /* IEEE rounding mode */
00053 
00054         int res = AR_STAT_OK;
00055         unsigned long carry;
00056 
00057         if (x->sign)
00058                 res |= AR_STAT_NEGATIVE;
00059 
00060         /* Zero means zero */
00061         if (!(lbits | x->coeff0 | x->coeff1 | rbits)) {
00062                 x->expo = 0;
00063                 return res | AR_STAT_ZERO;
00064         }
00065 
00066         /* Normalize if necessary; preserve "sticky" rounding bit */
00067         while (expo > 1 && !lbits) {
00068                 lbits = x->coeff0 >> (AR_IEEE32_C0_BITS - 1);
00069                 SHLEFTIEEE32 (*x);
00070                 x->coeff1 |= rbits >> (AR_IEEE32_ROUND_BITS - 1);
00071                 rbits = (rbits << 1) & MASKR (AR_IEEE32_ROUND_BITS) | rbits & 1;
00072                 expo--;
00073         }
00074         if (expo == 1 && !lbits)
00075                 expo = 0;
00076         else if (!expo && lbits)
00077                 expo = 1;
00078 
00079         /* Shift right if carry; keep the sticky bit */
00080         while (lbits > 1 || expo < 0) {
00081                 rbits = (rbits >> 1) |
00082                         rbits & 1 |
00083                         ((x->coeff1 & 1) << (AR_IEEE32_ROUND_BITS - 1));
00084                 SHRIGHTIEEE32 (*x);
00085                 x->coeff0 |= lbits << (AR_IEEE32_C0_BITS - 1);
00086                 lbits >>= 1;
00087                 expo++;
00088         }
00089 
00090         /* Rounding decision */
00091         switch (roundmode) {
00092         case AR_ROUND_PLUS_INFINITY:
00093                 if (!rbits == !x->sign)
00094                         goto noround;
00095                 break;
00096         case AR_ROUND_MINUS_INFINITY:
00097                 if (!rbits != !x->sign)
00098                         goto noround;
00099                 break;
00100         case AR_ROUND_ZERO:
00101                 goto noround;
00102         default:
00103                 if (!(rbits >> (AR_IEEE32_ROUND_BITS - 1)))
00104                         goto noround;
00105                 if (!(rbits & MASKR (AR_IEEE32_ROUND_BITS - 1)) &&
00106                         !(x->coeff1 & 1))
00107                         goto noround;
00108                 break;
00109         }
00110 
00111         /* Round up the coefficient */
00112         carry = 1;
00113         INCIEEE32 (*x, carry);
00114         lbits += carry;
00115 
00116 noround:
00117 
00118         /* Shift right if necessary */
00119         if (lbits > 1) {
00120                 rbits = (rbits >> 1) |
00121                         ((x->coeff1 & 1) << (AR_IEEE32_ROUND_BITS - 1));
00122                 SHRIGHTIEEE32 (*x);
00123                 x->coeff0 |= lbits << (AR_IEEE32_C0_BITS - 1);
00124                 lbits >>= 1;
00125                 expo++;
00126         }
00127         else if (lbits) {
00128                 if (!expo)
00129                         expo = 1;
00130         }
00131         else
00132                 expo = 0;
00133 
00134         if (!(lbits | x->coeff0 | x->coeff1)) {
00135                 expo = 0;
00136                 res |= AR_STAT_ZERO | AR_STAT_UNDERFLOW;
00137         }
00138 
00139         /* Test for out-of-range result; turn into (signed) infinity */
00140         if (expo > AR_IEEE32_MAX_EXPO) {
00141                 x->expo = AR_IEEE32_MAX_EXPO + 1;
00142                 x->coeff0 = x->coeff1 = 0;
00143                 return res | AR_STAT_OVERFLOW;
00144         }
00145 
00146         /* Test for inexact */
00147         if (rbits) {
00148                 res |= AR_STAT_INEXACT;
00149         }
00150 
00151         x->expo = expo;
00152 
00153         if (!expo &&
00154                 ar_state_register.ar_underflow_mode != AR_UNDERFLOW_TO_DENORM) {
00155                 /* don't want denorms; convert to zero */
00156                 if (x->coeff0 | x->coeff1) {
00157                         /* got a denorm */
00158                         x->coeff0 = x->coeff1 = 0;
00159                         if (ar_state_register.ar_underflow_mode ==
00160                                 AR_UNDERFLOW_TO_PLUS_ZERO)
00161                                 x->sign = 0;
00162                         else if (ar_state_register.ar_underflow_mode ==
00163                                          AR_UNDERFLOW_TO_SIGNED_TINY)
00164                                 x->expo = AR_IEEE64_MIN_EXPO+1;
00165                         return res | AR_STAT_ZERO | AR_STAT_UNDERFLOW;
00166                 }
00167         }
00168 
00169         return res;
00170 }
00171 
00172 
00173 int
00174 ar_i64norm (signed int expo,            /* exponent */
00175                         unsigned long lbits,    /* left-hand bits */
00176                         unsigned long rbits,    /* right-hand rounding bits */
00177                         AR_IEEE_64 *x,                  /* result to package; coeff and sign */
00178                         int roundmode) {                /* IEEE rounding mode */
00179 
00180         int res = AR_STAT_OK;
00181         unsigned long carry;
00182 
00183         if (x->sign)
00184                 res |= AR_STAT_NEGATIVE;
00185 
00186         /* Zero means zero */
00187         if (!(lbits | x->coeff0 | x->coeff1 | x->coeff2 | x->coeff3 | rbits)) {
00188                 x->expo = 0;
00189                 return res | AR_STAT_ZERO;
00190         }
00191 
00192         /* Normalize if necessary; preserve "sticky" rounding bit */
00193         while (expo > 1 && !lbits) {
00194                 lbits = x->coeff0 >> (AR_IEEE64_C0_BITS - 1);
00195                 SHLEFTIEEE64 (*x);
00196                 x->coeff3 |= rbits >> (AR_IEEE64_ROUND_BITS - 1);
00197                 rbits = (rbits << 1) & MASKR (AR_IEEE64_ROUND_BITS) | rbits & 1;
00198                 expo--;
00199         }
00200         if (expo == 1 && !lbits)
00201                 expo = 0;
00202         else if (!expo && lbits)
00203                 expo = 1;
00204 
00205         /* Shift right if carry; keep the sticky bit */
00206         while (lbits > 1 || expo < 0) {
00207                 rbits = (rbits >> 1) |
00208                         rbits & 1 |
00209                         ((x->coeff3 & 1) << (AR_IEEE64_ROUND_BITS - 1));
00210                 SHRIGHTIEEE64 (*x);
00211                 x->coeff0 |= lbits << (AR_IEEE64_C0_BITS - 1);
00212                 lbits >>= 1;
00213                 expo++;
00214         }
00215 
00216         /* Rounding decision */
00217         switch (roundmode) {
00218         case AR_ROUND_PLUS_INFINITY:
00219                 if (!rbits == !x->sign)
00220                         goto noround;
00221                 break;
00222         case AR_ROUND_MINUS_INFINITY:
00223                 if (!rbits != !x->sign)
00224                         goto noround;
00225                 break;
00226         case AR_ROUND_ZERO:
00227                 goto noround;
00228         default:
00229                 if (!(rbits >> (AR_IEEE64_ROUND_BITS - 1)))
00230                         goto noround;
00231                 if (!(rbits & MASKR (AR_IEEE64_ROUND_BITS - 1)) &&
00232                         !(x->coeff3 & 1))
00233                         goto noround;
00234                 break;
00235         }
00236 
00237         /* Round up the coefficient */
00238         carry = 1;
00239         INCIEEE64 (*x, carry);
00240         lbits += carry;
00241 
00242 noround:
00243 
00244         /* Shift right if necessary */
00245         if (lbits > 1) {
00246                 rbits = (rbits >> 1) |
00247                         ((x->coeff3 & 1) << (AR_IEEE64_ROUND_BITS - 1));
00248                 SHRIGHTIEEE64 (*x);
00249                 x->coeff0 |= lbits << (AR_IEEE64_C0_BITS - 1);
00250                 lbits >>= 1;
00251                 expo++;
00252         }
00253         else if (lbits) {
00254                 if (!expo)
00255                         expo = 1;
00256         }
00257         else
00258                 expo = 0;
00259 
00260         if (!(lbits | x->coeff0 | x->coeff1 | x->coeff2 | x->coeff3)) {
00261                 expo = 0;
00262                 res |= AR_STAT_ZERO | AR_STAT_UNDERFLOW;
00263         }
00264 
00265         /* Test for out-of-range result; turn into (signed) infinity */
00266         if (expo > AR_IEEE64_MAX_EXPO) {
00267                 x->expo = AR_IEEE64_MAX_EXPO + 1;
00268                 x->coeff0 = x->coeff1 = x->coeff2 = x->coeff3 = 0;
00269                 return res | AR_STAT_OVERFLOW;
00270         }
00271 
00272         /* Test for inexact */
00273         if (rbits) {
00274                 res |= AR_STAT_INEXACT;
00275         }
00276 
00277         x->expo = expo;
00278 
00279         if (!expo &&
00280                 ar_state_register.ar_underflow_mode != AR_UNDERFLOW_TO_DENORM) {
00281                 /* don't want denorms; convert to zero */
00282                 if (x->coeff0 | x->coeff1 | x->coeff2 | x->coeff3) {
00283                         /* got a denorm */
00284                         x->coeff0 = x->coeff1 = x->coeff2 = x->coeff3 = 0;
00285                         if (ar_state_register.ar_underflow_mode ==
00286                                 AR_UNDERFLOW_TO_PLUS_ZERO)
00287                                 x->sign = 0;
00288                         else if (ar_state_register.ar_underflow_mode ==
00289                                          AR_UNDERFLOW_TO_SIGNED_TINY)
00290                                 x->expo = AR_IEEE64_MIN_EXPO+1;
00291                         return res | AR_STAT_ZERO | AR_STAT_UNDERFLOW;
00292                 }
00293         }
00294 
00295         return res;
00296 }
00297 
00298 
00299 int
00300 ar_i128norm(signed int expo,            /* exponent */
00301                         unsigned long lbits,    /* left-hand bits */
00302                         unsigned long rbits,    /* right-hand rounding bits */
00303                         AR_IEEE_128 *x,                 /* result to package; coeff and sign */
00304                         int roundmode) {                /* IEEE rounding mode */
00305 
00306         int res = AR_STAT_OK;
00307         unsigned long carry;
00308 
00309         if (x->sign)
00310                 res |= AR_STAT_NEGATIVE;
00311 
00312         /* Zero means zero */
00313         if (!(lbits | x->coeff0 | x->coeff1 | x->coeff2 | x->coeff3 |
00314                   x->coeff4 | x->coeff5 | x->coeff6 | rbits)) {
00315                 x->expo = 0;
00316                 return res | AR_STAT_ZERO;
00317         }
00318 
00319         /* Normalize if necessary; preserve "sticky" rounding bit */
00320         while (expo > 1 && !lbits) {
00321                 lbits = x->coeff0 >> (AR_IEEE128_C0_BITS - 1);
00322                 SHLEFTIEEE128 (*x);
00323                 x->coeff6 |= rbits >> (AR_IEEE128_ROUND_BITS - 1);
00324                 rbits = (rbits << 1) & MASKR (AR_IEEE128_ROUND_BITS) | rbits & 1;
00325                 expo--;
00326         }
00327         if (expo == 1 && !lbits)
00328                 expo = 0;
00329         else if (!expo && lbits)
00330                 expo = 1;
00331 
00332         /* Shift right if carry; keep the sticky bit */
00333         while (lbits > 1 || expo < 0) {
00334                 rbits = (rbits >> 1) |
00335                         rbits & 1 |
00336                         ((x->coeff6 & 1) << (AR_IEEE128_ROUND_BITS - 1));
00337                 SHRIGHTIEEE128 (*x);
00338                 x->coeff0 |= lbits << (AR_IEEE128_C0_BITS - 1);
00339                 lbits >>= 1;
00340                 expo++;
00341         }
00342 
00343         /* Rounding decision */
00344         switch (roundmode) {
00345         case AR_ROUND_PLUS_INFINITY:
00346                 if (!rbits == !x->sign)
00347                         goto noround;
00348                 break;
00349         case AR_ROUND_MINUS_INFINITY:
00350                 if (!rbits != !x->sign)
00351                         goto noround;
00352                 break;
00353         case AR_ROUND_ZERO:
00354                 goto noround;
00355         default:
00356                 if (!(rbits >> (AR_IEEE128_ROUND_BITS - 1)))
00357                         goto noround;
00358                 if (!(rbits & MASKR (AR_IEEE128_ROUND_BITS - 1)) &&
00359                         !(x->coeff6 & 1))
00360                         goto noround;
00361                 break;
00362         }
00363 
00364         /* Round up the coefficient */
00365         carry = 1;
00366         INCIEEE128 (*x, carry);
00367         lbits += carry;
00368 
00369 noround:
00370 
00371         /* Shift right if necessary */
00372         if (lbits > 1) {
00373                 rbits = (rbits >> 1) |
00374                         ((x->coeff6 & 1) << (AR_IEEE128_ROUND_BITS - 1));
00375                 SHRIGHTIEEE128 (*x);
00376                 x->coeff0 |= lbits << (AR_IEEE128_C0_BITS - 1);
00377                 lbits >>= 1;
00378                 expo++;
00379         }
00380         else if (lbits) {
00381                 if (!expo)
00382                         expo = 1;
00383         }
00384         else
00385                 expo = 0;
00386 
00387         if (!(lbits | x->coeff0 | x->coeff1 | x->coeff2 | x->coeff3 |
00388                   x->coeff4 | x->coeff5 | x->coeff6)) {
00389                 expo = 0;
00390                 res |= AR_STAT_ZERO | AR_STAT_UNDERFLOW;
00391         }
00392 
00393         /* Test for out-of-range result; turn into (signed) infinity */
00394         if (expo > AR_IEEE128_MAX_EXPO) {
00395                 x->expo = AR_IEEE128_MAX_EXPO + 1;
00396                 x->coeff0 = x->coeff1 = x->coeff2 = x->coeff3 =
00397                         x->coeff4 = x->coeff5 = x->coeff6 = 0;
00398                 return res | AR_STAT_OVERFLOW;
00399         }
00400 
00401         /* Test for inexact */
00402         if (rbits) {
00403                 res |= AR_STAT_INEXACT;
00404         }
00405 
00406         x->expo = expo;
00407 
00408         if (!expo &&
00409                 ar_state_register.ar_underflow_mode != AR_UNDERFLOW_TO_DENORM) {
00410                 /* don't want denorms; convert to zero */
00411                 if (x->coeff0 | x->coeff1 | x->coeff2 | x->coeff3 |
00412                         x->coeff4 | x->coeff5 | x->coeff6) {
00413                         /* got a denorm */
00414                         x->coeff0 = x->coeff1 = x->coeff2 = x->coeff3 =
00415                                 x->coeff4 = x->coeff5 = x->coeff6 = 0;
00416                         if (ar_state_register.ar_underflow_mode ==
00417                                 AR_UNDERFLOW_TO_PLUS_ZERO)
00418                                 x->sign = 0;
00419                         else if (ar_state_register.ar_underflow_mode ==
00420                                          AR_UNDERFLOW_TO_SIGNED_TINY)
00421                                 x->expo = AR_IEEE128_MIN_EXPO+1;
00422                         return res | AR_STAT_ZERO | AR_STAT_UNDERFLOW;
00423                 }
00424         }
00425 
00426         return res;
00427 }
00428 
00429 
00430 static char USMID [] = "\n%Z%%M%        %I%     %G% %U%\n";
00431 static char rcsid [] = "$Id: ieee_norm.c,v 1.1.1.1 2002-05-22 20:06:19 dsystem Exp $";
00432 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines