Open64 (mfef90, whirl2f, and IR tools)  TAG: version-openad; SVN changeset: 916
c_q_to_a.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  * ====================================================================
00038  *
00039  *
00040  * Revision history:
00041  *  26-jul-93 - Original Version
00042  *
00043  * Description: Convert a quad precision binary number to decimal.
00044  *
00045  * ====================================================================
00046  * ====================================================================
00047  */
00048 
00049 
00050 #if QUAD_DEBUG
00051 #include <stdio.h>
00052 #endif
00053 
00054 /* Macros to pull apart parts of single and  double precision
00055  * floating point numbers in IEEE format
00056  */
00057 
00058 /* double precision */
00059 
00060 typedef  union {
00061         struct {
00062                 unsigned  sign  :1;
00063                 unsigned  exp   :11;
00064                 unsigned  hi    :20;
00065                 unsigned  lo    :32;
00066         } fparts;
00067         struct {
00068                 unsigned  sign  :1;
00069                 unsigned  exp   :11;
00070                 unsigned  qnan_bit      :1;
00071                 unsigned  hi    :19;
00072                 unsigned  lo    :32;
00073         } nparts;
00074         struct {
00075                 unsigned hi;
00076                 unsigned lo;
00077         } fwords;
00078         double  d;
00079 } _dval;
00080 
00081 /* quad precision */
00082 
00083 typedef  union {
00084         struct {
00085                 _dval   hi;
00086                 _dval   lo;
00087         } qparts;
00088         struct {
00089                 unsigned long long hi;
00090                 unsigned long long lo;
00091         } fwords;
00092 } _ldblval;
00093 
00094 /* parts of a double precision floating point number */
00095 
00096 #define SIGNBIT(X)      (((_dval *)&(X))->fparts.sign)
00097 #define EXPONENT(X)     (((_dval *)&(X))->fparts.exp)
00098 
00099 #include "defs.h"
00100 #include "quad.h"
00101 
00102 
00103 #define min(x,y) ((x)<(y)? (x): (y))
00104 #define max(x,y) ((x)>(y)? (x): (y))
00105 
00106 extern void     c_qtenscale( _ldblval *, INT32, INT32 *);
00107 static INT32    c_qtoa(char *buffer, INT32 ndigit, QUAD x, INT32 fflag);
00108 extern INT      c_q_to_a(char *str, QUAD x, INT *p_err );
00109 
00110 #pragma weak c_q_to_a = __c_q_to_a
00111 #define c_q_to_a __c_q_to_a
00112 
00113 
00114 /* ====================================================================
00115  *
00116  * FunctionName: c_q_to_a
00117  *
00118  * Description: Convert a quad precision binary number to decimal.
00119  *
00120  * ====================================================================
00121  */
00122 
00123 
00124 INT
00125 c_q_to_a(char *str, QUAD x, INT *p_err )
00126 {
00127 char    buffer[42];
00128 char    *pbuff;
00129 INT32   ndigit;
00130 INT32   fflag;
00131 INT32   m, n;
00132 
00133         *p_err = 0;
00134 
00135         ndigit = 34;
00136         fflag = 0;
00137 
00138         n = c_qtoa(buffer, ndigit, x, fflag);
00139 
00140         if ( strncmp(buffer, "inf", 3) == 0 )
00141         {
00142                 strncpy( str, buffer, 3 );
00143 
00144                 *(str + 3) = '\0';
00145 
00146                 return ( *p_err );
00147         }
00148 
00149         if ( strncmp(buffer, "nan", 3) == 0 )
00150         {
00151                 strncpy( str, buffer, 3 );
00152 
00153                 *(str + 3) = '\0';
00154 
00155                 return ( *p_err );
00156         }
00157 
00158         if ( strncmp(buffer+1, "inf", 3) == 0 )
00159         {
00160                 strncpy( str, buffer, 4 );
00161 
00162                 *(str + 4) = '\0';
00163 
00164                 return ( *p_err );
00165         }
00166 
00167         if ( strncmp(buffer+1, "nan", 3) == 0 )
00168         {
00169                 strncpy( str, buffer+1, 3 );
00170 
00171                 *(str + 3) = '\0';
00172 
00173                 return ( *p_err );
00174         }
00175 
00176         if ( (n <= -1000) || (n >= 1000) )
00177         {
00178                 *p_err = 1;
00179 
00180                 *str = '\0';
00181 
00182                 return ( *p_err );
00183         }
00184 
00185         pbuff = buffer;
00186 
00187         if ( (buffer[0] == ' ') || (buffer[0] == '-') )
00188                 *str++ = *pbuff++;
00189 
00190         *str++ = *pbuff++;      /* copy first digit to output string */
00191 
00192         *str++ = '.';
00193 
00194         if ( ndigit > 1 )
00195         {
00196                 strncpy(str, pbuff, ndigit-1);
00197 
00198                 str += ndigit - 1;      /* skip over digits copied */
00199         }
00200 
00201         *str++ = 'E';
00202 
00203         if ( n < 0 )
00204         {
00205                 n = -n;
00206                 *str++ = '-';
00207         }
00208 
00209         m = n/100;
00210 
00211         if ( m!= 0 )
00212                 *str++ = m + '0';
00213 
00214         n = n%100;
00215 
00216         m = n/10;
00217 
00218         *str++ = m + '0';
00219 
00220         m = n%10;
00221 
00222         *str++ = m + '0';
00223 
00224         *str++ = '\0';
00225 
00226         return ( *p_err );
00227 }
00228 
00229 
00230 /* ====================================================================
00231  *
00232  * FunctionName: c_qtoa
00233  *
00234  * Description: Convert a quad precision binary number to decimal.
00235  *
00236  * Except for minor changes, this routine is the same as _qtoa()
00237  * in libc.  Included here, so we can do cross compilations on
00238  * machines not supporting quad precision.
00239  *
00240  * ====================================================================
00241  */
00242 
00243 static
00244 INT32                           /* returns decimal exponent */
00245 c_qtoa(buffer,ndigit,x,fflag) 
00246      char *buffer;              /* Destination for ascii string */ 
00247      INT32 ndigit;              /* number of digits to convert.
00248                                  * 1 <= ndigits <= 34
00249                                  * Log2(1e34) = 112.9 bits, so the
00250                                  * 107 significant bits can be con-
00251                                  * verted to decimal with room left
00252                                  * over.
00253                                  */ 
00254      QUAD x;                    /* number to convert to ascii */ 
00255      INT32 fflag;               /* 0 for e format, 1 for f format */ 
00256 {
00257   _ldblval value;               /* the value manipulated */ 
00258 #define HI (value.fwords.hi)    /* top 64b of 128b fraction */ 
00259 #define LO (value.fwords.lo)    /* bottom 64b of 128b fraction */
00260 
00261   INT32 signhi, signlo;         /* sign of HI = sign of number */ 
00262   INT32 exphi, explo;           /* exponents of HI and LO */ 
00263   INT32 dexp;                   /* decimal exponent */ 
00264   INT32 bexp;                   /* binary exponent */ 
00265   UINT32 lohi;                  /* top 4 bits of lo */ 
00266   UINT64 lolo;                  /* bottom 60 bits of lo */ 
00267   INT32 nd;                     /* number of digits output */ 
00268   INT32 guard;                  /* guard digit */
00269 
00270 #if QUAD_DEBUG 
00271   char *buffer0=buffer;         /* initial value of buffer */
00272 #endif
00273 
00274 
00275   value.qparts.hi.d = x.hi;
00276   value.qparts.lo.d = x.lo;
00277 
00278 #if QUAD_DEBUG 
00279   printf("initially: HI=0x%016llx\n",HI); 
00280   printf("LO=0x%016llx\n",LO); 
00281 #endif
00282 
00283   signhi = SIGNBIT(HI); 
00284   HI = (HI<<1)>>1;              /* discard sign bit */ 
00285   *buffer++ = signhi? '-': ' ';
00286 
00287 #if QUAD_DEBUG 
00288   printf("after de-signing hi: HI=0x%016llx\n",HI); 
00289   printf("signhi=%d\n",signhi); 
00290   *buffer = '\0'; 
00291   printf(" buffer=%s\n",buffer0);
00292 #endif
00293 
00294   if( HI == 0 ) {               /* true zero */ 
00295     char *b;                    /* fencepost for buffer */
00296 
00297     b = buffer + ndigit; 
00298     while(buffer < b) 
00299       *buffer++ = '0';
00300 
00301 #if QUAD_DEBUG 
00302     printf("HI was zero: HI=0x%016llx\n",HI); 
00303     printf("signhi=%d\n",signhi); 
00304     *buffer = '\0'; 
00305     printf(" buffer=%s\n",buffer0);
00306 #endif
00307 
00308     return(0);
00309   }
00310 
00311   exphi = EXPONENT(HI); 
00312   EXPONENT(HI) = 0;
00313 
00314 #if QUAD_DEBUG 
00315   printf("HI non-zero: HI=0x%016llx\n",HI); 
00316   printf("exphi=%d\n",exphi); 
00317 #endif
00318 
00319   if(exphi == 2047) {           /* infinity or NaN */ 
00320     char *s;                    /* infinity or nan string */ 
00321     char *infinity = "inf"; 
00322     char *nan = "nan";
00323 
00324     s = HI==0? infinity: nan;
00325 
00326     do 
00327       *buffer++ = *s; 
00328     while(*s++);
00329 
00330 #if QUAD_DEBUG 
00331     printf("NaN or Infinity: buffer=%s\n",buffer0); 
00332 #endif
00333 
00334     return(0); 
00335   }
00336 
00337   /* processing a number. create 128b fraction */ 
00338   /* hi is non-zero, or the following while loop wouldn't terminate */ 
00339   if(exphi == 0) {              /* HI denorm */ 
00340     exphi++;
00341     while( !(HI & (1ULL<<52))) { /* normalize - need not be fast */ 
00342       HI <<=1; 
00343       exphi--;
00344 
00345 #if QUAD_DEBUG 
00346       printf("HI denorm: HI=0x%016llx\n",HI); 
00347       printf("exphi=%d\n",exphi); 
00348 #endif
00349 
00350     }
00351   } 
00352   else {                        /* HI is normal number */ 
00353     HI |= 1ULL<<52;             /* expose hidden bit */
00354 
00355 #if QUAD_DEBUG 
00356     printf("HI normal: HI=0x%016llx\n",HI); 
00357     printf("exphi=%d\n",exphi); 
00358 #endif
00359 
00360   }
00361 
00362   HI <<=11;                     /* left align */
00363 
00364 #if QUAD_DEBUG 
00365   printf("HI aligned: HI=0x%016llx\n",HI); 
00366 #endif
00367 
00368   /* handle LO */
00369 
00370   signlo = SIGNBIT(LO) ^ signhi; /* HI,LO signs differ? */
00371   SIGNBIT(LO) = 0;              /* discard sign */
00372 
00373 #if QUAD_DEBUG
00374   printf("handle LO: LO=0x%016llx\n",LO);
00375   printf("           signlo=%d\n",signlo);
00376 #endif
00377 
00378   if(LO) {                      /* lo is non-zero */
00379 
00380     explo = EXPONENT(LO);
00381     EXPONENT(LO) = 0;
00382 
00383 #if QUAD_DEBUG
00384   printf("non-zero LO: LO=0x%016llx\n",LO);
00385   printf("             explo=%d\n",explo);
00386 #endif
00387 
00388     LO <<=1;                    /* shift LO to expose 107th bit */
00389 
00390 #if QUAD_DEBUG
00391     printf("left-shifted LO: LO=0x%016llx\n",LO);
00392 #endif
00393 
00394     if(explo == 0) {            /* denorm */
00395       INT32 shift_n;            /* shift count */
00396 
00397       LO <<= 1;                 /* shift up one more bit */
00398 #if QUAD_DEBUG
00399       printf("shifted up LO: LO=0x%016llx\n",LO);
00400 #endif
00401       shift_n = 53 - (exphi-explo);
00402       /* normalize to HI */
00403       if(shift_n > 0) {
00404         LO <<= shift_n; 
00405       }
00406       else if(shift_n < 0) {
00407         LO >>= -shift_n;
00408       }
00409     }
00410     else {                      /* LO normal number */
00411       LO |= 1ULL<<53;           /* expose hidden bit */
00412       
00413 #if QUAD_DEBUG
00414       printf("expose hidden bit: LO=0x%016llx\n",LO);
00415 #endif
00416       
00417       LO >>= (exphi-explo) - 53; /* normalize to HI */
00418     }
00419 
00420 #if QUAD_DEBUG
00421     printf("normalize LO to HI: LO=0x%016llx\n",LO);
00422 #endif
00423     
00424     if( signlo ) {              /* LO is negative */
00425       HI-= 1<<11;                       /* unround HI */
00426       LO = (1ULL<<54) - LO;     /* complement LO */
00427       
00428 #if QUAD_DEBUG
00429       printf("LO negative: HI=0x%016llx\n",HI);
00430       printf("             LO=0x%016llx\n",LO);
00431 #endif
00432       
00433     }
00434 
00435     HI |= LO>>43;               /* combine HI and LO into 107b fract. */
00436     LO <<=21;
00437 #if QUAD_DEBUG
00438   printf("LO&HI combined: HI=0x%016llx\n",HI);
00439   printf("                LO=0x%016llx\n",LO);
00440 #endif
00441 
00442   }
00443 
00444   /* At this point we have a 128b binary fraction HILO, the low 21
00445    * bits of which are zero, and a biased binary exponent exphi.
00446    *
00447    * Generate the decimal exponent by multiplying the binary 
00448    * exponent by log10(2). 
00449    */
00450 
00451   /* exphi is at most 9 bits plus sign. Shifts avoid overflow
00452    * and recover integer part.
00453    */
00454 
00455   dexp = ( ((INT32) (exphi-1023)) * (0x4D104D42L >> 21) );
00456   /* truncate to -infinity */
00457   dexp >>= 11;
00458   dexp++;
00459 
00460 #if QUAD_DEBUG
00461   printf("before scaling: dexp=%d\n",dexp);
00462 #endif
00463 
00464   /* Scale fraction by decimal exponent. */
00465 
00466   if(dexp)                      /* value *= 10 ** -dexp */
00467     c_qtenscale(&value, -dexp, &bexp); 
00468   else
00469     bexp=0;
00470 
00471 #if QUAD_DEBUG
00472   printf("after scaling: HI=0x%016llx\n",HI);
00473   printf("               LO=0x%016llx\n",LO);
00474   printf("               bexp=%d\n",bexp);
00475 #endif
00476 
00477   exphi += bexp;
00478 
00479 #if QUAD_DEBUG
00480   printf("adjusted exphi: exphi=%d\n",exphi);
00481 #endif
00482 
00483   /* unbias exphi */
00484 
00485   exphi -= 1022;
00486 
00487   /* Remove binary exponent by denormalizing */
00488   /* Shift an extra 4 bits to allow for later digit generation */
00489 
00490   LO = (LO >> 4-exphi) | (HI << (60+exphi));
00491   HI >>= 4-exphi;
00492 
00493 #if QUAD_DEBUG
00494   printf("denormalized: HI=0x%016llx\n",HI);
00495   printf("              LO=0x%016llx\n",LO);
00496 #endif
00497 
00498   /* Split LO inpreparation to producing digits */
00499 
00500   lohi = LO >> 60;
00501   lolo = LO & ((1ULL<<60)-1);
00502 
00503 #if QUAD_DEBUG
00504   printf("split LO: lohi=0x%02x\n",lohi);
00505   printf("          lolo=0x%016llx\n",lolo);
00506 #endif
00507 
00508   /* find first non-zero digit */
00509   while( !(HI >> 60) ) {
00510     lolo *= 10;
00511     lohi = lohi * 10 + (lolo>>60);
00512     lolo &= (1ULL<<60)-1;
00513     HI = HI * 10 + (lohi>>4);
00514     lohi &= 0xF;
00515     dexp--;
00516 
00517 #if QUAD_DEBUG
00518   printf("finding first digit: HI=0x%016llx\n",HI);
00519   printf("                     lohi=0x%02x\n",lohi);
00520   printf("                     lolo=0x%016llx\n",lolo);
00521   printf("                     dexp=%d\n",dexp);
00522 #endif
00523 
00524   }
00525   /* produce digits */
00526 
00527   if(fflag) {                   /* f format */
00528     nd = min(34, ndigit + dexp + 1); /* need 1 integer digit */
00529   }
00530   else {
00531     nd = ndigit;                /* e format */
00532   }
00533 
00534 #if QUAD_DEBUG
00535   printf("number of digits: nd=%d\n",nd);
00536   printf("                  ndigit=%d\n",ndigit);
00537   printf("                  dexp=%d\n",dexp);
00538 #endif
00539 
00540   /* produce digits - always at least one */
00541   do {
00542     *buffer++ = '0' + (HI>>60);
00543     HI &= (1ULL<<60) - 1;
00544     lolo *= 10;
00545     lohi = lohi * 10 + (lolo>>60);
00546     lolo &= (1ULL<<60)-1;
00547     HI = HI * 10 + (lohi>>4);
00548     lohi &= 0xF;
00549 
00550 #if QUAD_DEBUG
00551   printf("another digit: HI=0x%016llx\n",HI);
00552   printf("               lohi=0x%02x\n",lohi);
00553   printf("               lolo=0x%016llx\n",lolo);
00554   *buffer = '\0';
00555   printf("               buffer=%s\n",buffer0);
00556 #endif
00557 
00558   }
00559   while(--nd > 0);
00560 
00561   /* decimal round */
00562 
00563   /*    *buffer guard   rest    Action
00564    *    
00565    *    dc      0-4     dc      none
00566    *    dc      6-9     dc      round
00567    *    odd     5       dc      round
00568    *    even    5       0       none
00569    *    even    5       !=0     round
00570    */
00571 
00572   guard = HI>>60;
00573   if(guard >= 5) {
00574     if(guard > 5 ||
00575        (*buffer-1)&1 ||         /* buffer odd */
00576        HI & ((1ULL<<60) - 1) ||
00577        lohi || lolo) {          /* rest non-zero */
00578       char *b=buffer;           /* buffer pointer */
00579 
00580       /* must round */
00581 
00582 #if QUAD_DEBUG
00583   printf("must round\n");
00584 #endif
00585       for(b=buffer-1; ; b--) {
00586         if(*b < '0' || '9' < *b) { /* attempt to carry into sign */
00587           *(b+1) = '1';
00588           dexp++;
00589           if(fflag && nd != min(34, ndigit + dexp + 1)) { 
00590             *buffer++ = '0';    /* need one more digit */
00591 #if QUAD_DEBUG
00592             printf("added a zero: fflag=%d\n",fflag);
00593             printf("              ndigit=%d\n",ndigit);
00594             printf("              nd=%d\n",nd);
00595 #endif
00596           }
00597 
00598 #if QUAD_DEBUG
00599   printf("carry into sign: dexp=%d\n",dexp);
00600   printf("                 buffer=%s\n",buffer0);
00601 #endif
00602 
00603           break;
00604         }
00605         (*b)++;
00606 
00607 #if QUAD_DEBUG
00608   *buffer = '\0';
00609   printf("round: buffer=%s\n",buffer0);
00610 #endif
00611 
00612         if(*b > '9') {          /* carry */
00613           *b = '0';
00614 
00615 #if QUAD_DEBUG
00616   printf("carry: buffer=%s\n",buffer0);
00617 #endif
00618 
00619         }
00620         else
00621           break;                /* no carry */
00622       }
00623       
00624     }
00625   }
00626 
00627 #if REALLYNEEDED
00628   if(fflag && ndigit+dexp < 0) { /* no significant digits */
00629 
00630     dexp--;                     /* This is a lie. However, that's the
00631                                  * way dtoa behaves (sometimes!), so 
00632                                  * make qtoa work the same way.
00633                                  */
00634   }
00635 #endif
00636 
00637   *buffer = '\0';
00638 
00639 #if QUAD_DEBUG
00640   printf("done: buffer=%s\n",buffer0);
00641   printf("      dexp=%d\n", dexp);
00642 #endif
00643 
00644   return dexp;
00645 }
00646 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines