qemu/libdecnumber/dpd/decimal32.c
<<
>>
Prefs
   1/* Decimal 32-bit format module for the decNumber C Library.
   2   Copyright (C) 2005, 2007 Free Software Foundation, Inc.
   3   Contributed by IBM Corporation.  Author Mike Cowlishaw.
   4
   5   This file is part of GCC.
   6
   7   GCC is free software; you can redistribute it and/or modify it under
   8   the terms of the GNU General Public License as published by the Free
   9   Software Foundation; either version 2, or (at your option) any later
  10   version.
  11
  12   In addition to the permissions in the GNU General Public License,
  13   the Free Software Foundation gives you unlimited permission to link
  14   the compiled version of this file into combinations with other
  15   programs, and to distribute those combinations without any
  16   restriction coming from the use of this file.  (The General Public
  17   License restrictions do apply in other respects; for example, they
  18   cover modification of the file, and distribution when not linked
  19   into a combine executable.)
  20
  21   GCC is distributed in the hope that it will be useful, but WITHOUT ANY
  22   WARRANTY; without even the implied warranty of MERCHANTABILITY or
  23   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  24   for more details.
  25
  26   You should have received a copy of the GNU General Public License
  27   along with GCC; see the file COPYING.  If not, write to the Free
  28   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
  29   02110-1301, USA.  */
  30
  31/* ------------------------------------------------------------------ */
  32/* Decimal 32-bit format module                                       */
  33/* ------------------------------------------------------------------ */
  34/* This module comprises the routines for decimal32 format numbers.   */
  35/* Conversions are supplied to and from decNumber and String.         */
  36/*                                                                    */
  37/* This is used when decNumber provides operations, either for all    */
  38/* operations or as a proxy between decNumber and decSingle.          */
  39/*                                                                    */
  40/* Error handling is the same as decNumber (qv.).                     */
  41/* ------------------------------------------------------------------ */
  42#include "qemu/osdep.h"
  43
  44#include "libdecnumber/dconfig.h"
  45#define  DECNUMDIGITS  7      /* make decNumbers with space for 7 */
  46#include "libdecnumber/decNumber.h"
  47#include "libdecnumber/decNumberLocal.h"
  48#include "libdecnumber/dpd/decimal32.h"
  49
  50/* Utility tables and routines [in decimal64.c] */
  51extern const uInt   COMBEXP[32], COMBMSD[32];
  52extern const uByte  BIN2CHAR[4001];
  53
  54extern void decDigitsToDPD(const decNumber *, uInt *, Int);
  55extern void decDigitsFromDPD(decNumber *, const uInt *, Int);
  56
  57#if DECTRACE || DECCHECK
  58void decimal32Show(const decimal32 *);            /* for debug */
  59extern void decNumberShow(const decNumber *);     /* .. */
  60#endif
  61
  62/* Useful macro */
  63/* Clear a structure (e.g., a decNumber) */
  64#define DEC_clear(d) memset(d, 0, sizeof(*d))
  65
  66/* ------------------------------------------------------------------ */
  67/* decimal32FromNumber -- convert decNumber to decimal32              */
  68/*                                                                    */
  69/*   ds is the target decimal32                                       */
  70/*   dn is the source number (assumed valid)                          */
  71/*   set is the context, used only for reporting errors               */
  72/*                                                                    */
  73/* The set argument is used only for status reporting and for the     */
  74/* rounding mode (used if the coefficient is more than DECIMAL32_Pmax */
  75/* digits or an overflow is detected).  If the exponent is out of the */
  76/* valid range then Overflow or Underflow will be raised.             */
  77/* After Underflow a subnormal result is possible.                    */
  78/*                                                                    */
  79/* DEC_Clamped is set if the number has to be 'folded down' to fit,   */
  80/* by reducing its exponent and multiplying the coefficient by a      */
  81/* power of ten, or if the exponent on a zero had to be clamped.      */
  82/* ------------------------------------------------------------------ */
  83decimal32 * decimal32FromNumber(decimal32 *d32, const decNumber *dn,
  84                              decContext *set) {
  85  uInt status=0;                   /* status accumulator */
  86  Int ae;                          /* adjusted exponent */
  87  decNumber  dw;                   /* work */
  88  decContext dc;                   /* .. */
  89  uInt *pu;                        /* .. */
  90  uInt comb, exp;                  /* .. */
  91  uInt targ=0;                     /* target 32-bit */
  92
  93  /* If the number has too many digits, or the exponent could be */
  94  /* out of range then reduce the number under the appropriate */
  95  /* constraints.  This could push the number to Infinity or zero, */
  96  /* so this check and rounding must be done before generating the */
  97  /* decimal32] */
  98  ae=dn->exponent+dn->digits-1;              /* [0 if special] */
  99  if (dn->digits>DECIMAL32_Pmax              /* too many digits */
 100   || ae>DECIMAL32_Emax                      /* likely overflow */
 101   || ae<DECIMAL32_Emin) {                   /* likely underflow */
 102    decContextDefault(&dc, DEC_INIT_DECIMAL32); /* [no traps] */
 103    dc.round=set->round;                     /* use supplied rounding */
 104    decNumberPlus(&dw, dn, &dc);             /* (round and check) */
 105    /* [this changes -0 to 0, so enforce the sign...] */
 106    dw.bits|=dn->bits&DECNEG;
 107    status=dc.status;                        /* save status */
 108    dn=&dw;                                  /* use the work number */
 109    } /* maybe out of range */
 110
 111  if (dn->bits&DECSPECIAL) {                      /* a special value */
 112    if (dn->bits&DECINF) targ=DECIMAL_Inf<<24;
 113     else {                                       /* sNaN or qNaN */
 114      if ((*dn->lsu!=0 || dn->digits>1)           /* non-zero coefficient */
 115       && (dn->digits<DECIMAL32_Pmax)) {          /* coefficient fits */
 116        decDigitsToDPD(dn, &targ, 0);
 117        }
 118      if (dn->bits&DECNAN) targ|=DECIMAL_NaN<<24;
 119       else targ|=DECIMAL_sNaN<<24;
 120      } /* a NaN */
 121    } /* special */
 122
 123   else { /* is finite */
 124    if (decNumberIsZero(dn)) {               /* is a zero */
 125      /* set and clamp exponent */
 126      if (dn->exponent<-DECIMAL32_Bias) {
 127        exp=0;                               /* low clamp */
 128        status|=DEC_Clamped;
 129        }
 130       else {
 131        exp=dn->exponent+DECIMAL32_Bias;     /* bias exponent */
 132        if (exp>DECIMAL32_Ehigh) {           /* top clamp */
 133          exp=DECIMAL32_Ehigh;
 134          status|=DEC_Clamped;
 135          }
 136        }
 137      comb=(exp>>3) & 0x18;             /* msd=0, exp top 2 bits .. */
 138      }
 139     else {                             /* non-zero finite number */
 140      uInt msd;                         /* work */
 141      Int pad=0;                        /* coefficient pad digits */
 142
 143      /* the dn is known to fit, but it may need to be padded */
 144      exp=(uInt)(dn->exponent+DECIMAL32_Bias);    /* bias exponent */
 145      if (exp>DECIMAL32_Ehigh) {                  /* fold-down case */
 146        pad=exp-DECIMAL32_Ehigh;
 147        exp=DECIMAL32_Ehigh;                      /* [to maximum] */
 148        status|=DEC_Clamped;
 149        }
 150
 151      /* fastpath common case */
 152      if (DECDPUN==3 && pad==0) {
 153        targ=BIN2DPD[dn->lsu[0]];
 154        if (dn->digits>3) targ|=(uInt)(BIN2DPD[dn->lsu[1]])<<10;
 155        msd=(dn->digits==7 ? dn->lsu[2] : 0);
 156        }
 157       else { /* general case */
 158        decDigitsToDPD(dn, &targ, pad);
 159        /* save and clear the top digit */
 160        msd=targ>>20;
 161        targ&=0x000fffff;
 162        }
 163
 164      /* create the combination field */
 165      if (msd>=8) comb=0x18 | ((exp>>5) & 0x06) | (msd & 0x01);
 166             else comb=((exp>>3) & 0x18) | msd;
 167      }
 168    targ|=comb<<26;                /* add combination field .. */
 169    targ|=(exp&0x3f)<<20;          /* .. and exponent continuation */
 170    } /* finite */
 171
 172  if (dn->bits&DECNEG) targ|=0x80000000;  /* add sign bit */
 173
 174  /* now write to storage; this is endian */
 175  pu=(uInt *)d32->bytes;           /* overlay */
 176  *pu=targ;                        /* directly store the int */
 177
 178  if (status!=0) decContextSetStatus(set, status); /* pass on status */
 179  /* decimal32Show(d32); */
 180  return d32;
 181  } /* decimal32FromNumber */
 182
 183/* ------------------------------------------------------------------ */
 184/* decimal32ToNumber -- convert decimal32 to decNumber                */
 185/*   d32 is the source decimal32                                      */
 186/*   dn is the target number, with appropriate space                  */
 187/* No error is possible.                                              */
 188/* ------------------------------------------------------------------ */
 189decNumber * decimal32ToNumber(const decimal32 *d32, decNumber *dn) {
 190  uInt msd;                        /* coefficient MSD */
 191  uInt exp;                        /* exponent top two bits */
 192  uInt comb;                       /* combination field */
 193  uInt sour;                       /* source 32-bit */
 194  const uInt *pu;                  /* work */
 195
 196  /* load source from storage; this is endian */
 197  pu=(const uInt *)d32->bytes;     /* overlay */
 198  sour=*pu;                        /* directly load the int */
 199
 200  comb=(sour>>26)&0x1f;            /* combination field */
 201
 202  decNumberZero(dn);               /* clean number */
 203  if (sour&0x80000000) dn->bits=DECNEG; /* set sign if negative */
 204
 205  msd=COMBMSD[comb];               /* decode the combination field */
 206  exp=COMBEXP[comb];               /* .. */
 207
 208  if (exp==3) {                    /* is a special */
 209    if (msd==0) {
 210      dn->bits|=DECINF;
 211      return dn;                   /* no coefficient needed */
 212      }
 213    else if (sour&0x02000000) dn->bits|=DECSNAN;
 214    else dn->bits|=DECNAN;
 215    msd=0;                         /* no top digit */
 216    }
 217   else {                          /* is a finite number */
 218    dn->exponent=(exp<<6)+((sour>>20)&0x3f)-DECIMAL32_Bias; /* unbiased */
 219    }
 220
 221  /* get the coefficient */
 222  sour&=0x000fffff;                /* clean coefficient continuation */
 223  if (msd) {                       /* non-zero msd */
 224    sour|=msd<<20;                 /* prefix to coefficient */
 225    decDigitsFromDPD(dn, &sour, 3); /* process 3 declets */
 226    return dn;
 227    }
 228  /* msd=0 */
 229  if (!sour) return dn;            /* easy: coefficient is 0 */
 230  if (sour&0x000ffc00)             /* need 2 declets? */
 231    decDigitsFromDPD(dn, &sour, 2); /* process 2 declets */
 232   else
 233    decDigitsFromDPD(dn, &sour, 1); /* process 1 declet */
 234  return dn;
 235  } /* decimal32ToNumber */
 236
 237/* ------------------------------------------------------------------ */
 238/* to-scientific-string -- conversion to numeric string               */
 239/* to-engineering-string -- conversion to numeric string              */
 240/*                                                                    */
 241/*   decimal32ToString(d32, string);                                  */
 242/*   decimal32ToEngString(d32, string);                               */
 243/*                                                                    */
 244/*  d32 is the decimal32 format number to convert                     */
 245/*  string is the string where the result will be laid out            */
 246/*                                                                    */
 247/*  string must be at least 24 characters                             */
 248/*                                                                    */
 249/*  No error is possible, and no status can be set.                   */
 250/* ------------------------------------------------------------------ */
 251char * decimal32ToEngString(const decimal32 *d32, char *string){
 252  decNumber dn;                         /* work */
 253  decimal32ToNumber(d32, &dn);
 254  decNumberToEngString(&dn, string);
 255  return string;
 256  } /* decimal32ToEngString */
 257
 258char * decimal32ToString(const decimal32 *d32, char *string){
 259  uInt msd;                        /* coefficient MSD */
 260  Int  exp;                        /* exponent top two bits or full */
 261  uInt comb;                       /* combination field */
 262  char *cstart;                    /* coefficient start */
 263  char *c;                         /* output pointer in string */
 264  const uInt *pu;                  /* work */
 265  const uByte *u;                  /* .. */
 266  char *s, *t;                     /* .. (source, target) */
 267  Int  dpd;                        /* .. */
 268  Int  pre, e;                     /* .. */
 269  uInt sour;                       /* source 32-bit */
 270
 271  /* load source from storage; this is endian */
 272  pu=(const uInt *)d32->bytes;     /* overlay */
 273  sour=*pu;                        /* directly load the int */
 274
 275  c=string;                        /* where result will go */
 276  if (((Int)sour)<0) *c++='-';     /* handle sign */
 277
 278  comb=(sour>>26)&0x1f;            /* combination field */
 279  msd=COMBMSD[comb];               /* decode the combination field */
 280  exp=COMBEXP[comb];               /* .. */
 281
 282  if (exp==3) {
 283    if (msd==0) {                  /* infinity */
 284      strcpy(c,   "Inf");
 285      strcpy(c+3, "inity");
 286      return string;               /* easy */
 287      }
 288    if (sour&0x02000000) *c++='s'; /* sNaN */
 289    strcpy(c, "NaN");              /* complete word */
 290    c+=3;                          /* step past */
 291    if ((sour&0x000fffff)==0) return string; /* zero payload */
 292    /* otherwise drop through to add integer; set correct exp */
 293    exp=0; msd=0;                  /* setup for following code */
 294    }
 295   else exp=(exp<<6)+((sour>>20)&0x3f)-DECIMAL32_Bias; /* unbiased */
 296
 297  /* convert 7 digits of significand to characters */
 298  cstart=c;                        /* save start of coefficient */
 299  if (msd) *c++='0'+(char)msd;     /* non-zero most significant digit */
 300
 301  /* Now decode the declets.  After extracting each one, it is */
 302  /* decoded to binary and then to a 4-char sequence by table lookup; */
 303  /* the 4-chars are a 1-char length (significant digits, except 000 */
 304  /* has length 0).  This allows us to left-align the first declet */
 305  /* with non-zero content, then remaining ones are full 3-char */
 306  /* length.  We use fixed-length memcpys because variable-length */
 307  /* causes a subroutine call in GCC.  (These are length 4 for speed */
 308  /* and are safe because the array has an extra terminator byte.) */
 309  #define dpd2char u=&BIN2CHAR[DPD2BIN[dpd]*4];                   \
 310                   if (c!=cstart) {memcpy(c, u+1, 4); c+=3;}      \
 311                    else if (*u)  {memcpy(c, u+4-*u, 4); c+=*u;}
 312
 313  dpd=(sour>>10)&0x3ff;            /* declet 1 */
 314  dpd2char;
 315  dpd=(sour)&0x3ff;                /* declet 2 */
 316  dpd2char;
 317
 318  if (c==cstart) *c++='0';         /* all zeros -- make 0 */
 319
 320  if (exp==0) {                    /* integer or NaN case -- easy */
 321    *c='\0';                       /* terminate */
 322    return string;
 323    }
 324
 325  /* non-0 exponent */
 326  e=0;                             /* assume no E */
 327  pre=c-cstart+exp;
 328  /* [here, pre-exp is the digits count (==1 for zero)] */
 329  if (exp>0 || pre<-5) {           /* need exponential form */
 330    e=pre-1;                       /* calculate E value */
 331    pre=1;                         /* assume one digit before '.' */
 332    } /* exponential form */
 333
 334  /* modify the coefficient, adding 0s, '.', and E+nn as needed */
 335  s=c-1;                           /* source (LSD) */
 336  if (pre>0) {                     /* ddd.ddd (plain), perhaps with E */
 337    char *dotat=cstart+pre;
 338    if (dotat<c) {                 /* if embedded dot needed... */
 339      t=c;                              /* target */
 340      for (; s>=dotat; s--, t--) *t=*s; /* open the gap; leave t at gap */
 341      *t='.';                           /* insert the dot */
 342      c++;                              /* length increased by one */
 343      }
 344
 345    /* finally add the E-part, if needed; it will never be 0, and has */
 346    /* a maximum length of 3 digits (E-101 case) */
 347    if (e!=0) {
 348      *c++='E';                    /* starts with E */
 349      *c++='+';                    /* assume positive */
 350      if (e<0) {
 351        *(c-1)='-';                /* oops, need '-' */
 352        e=-e;                      /* uInt, please */
 353        }
 354      u=&BIN2CHAR[e*4];            /* -> length byte */
 355      memcpy(c, u+4-*u, 4);        /* copy fixed 4 characters [is safe] */
 356      c+=*u;                       /* bump pointer appropriately */
 357      }
 358    *c='\0';                       /* add terminator */
 359    /*printf("res %s\n", string); */
 360    return string;
 361    } /* pre>0 */
 362
 363  /* -5<=pre<=0: here for plain 0.ddd or 0.000ddd forms (can never have E) */
 364  t=c+1-pre;
 365  *(t+1)='\0';                          /* can add terminator now */
 366  for (; s>=cstart; s--, t--) *t=*s;    /* shift whole coefficient right */
 367  c=cstart;
 368  *c++='0';                             /* always starts with 0. */
 369  *c++='.';
 370  for (; pre<0; pre++) *c++='0';        /* add any 0's after '.' */
 371  /*printf("res %s\n", string); */
 372  return string;
 373  } /* decimal32ToString */
 374
 375/* ------------------------------------------------------------------ */
 376/* to-number -- conversion from numeric string                        */
 377/*                                                                    */
 378/*   decimal32FromString(result, string, set);                        */
 379/*                                                                    */
 380/*  result  is the decimal32 format number which gets the result of   */
 381/*          the conversion                                            */
 382/*  *string is the character string which should contain a valid      */
 383/*          number (which may be a special value)                     */
 384/*  set     is the context                                            */
 385/*                                                                    */
 386/* The context is supplied to this routine is used for error handling */
 387/* (setting of status and traps) and for the rounding mode, only.     */
 388/* If an error occurs, the result will be a valid decimal32 NaN.      */
 389/* ------------------------------------------------------------------ */
 390decimal32 * decimal32FromString(decimal32 *result, const char *string,
 391                                decContext *set) {
 392  decContext dc;                             /* work */
 393  decNumber dn;                              /* .. */
 394
 395  decContextDefault(&dc, DEC_INIT_DECIMAL32); /* no traps, please */
 396  dc.round=set->round;                        /* use supplied rounding */
 397
 398  decNumberFromString(&dn, string, &dc);     /* will round if needed */
 399  decimal32FromNumber(result, &dn, &dc);
 400  if (dc.status!=0) {                        /* something happened */
 401    decContextSetStatus(set, dc.status);     /* .. pass it on */
 402    }
 403  return result;
 404  } /* decimal32FromString */
 405
 406/* ------------------------------------------------------------------ */
 407/* decimal32IsCanonical -- test whether encoding is canonical         */
 408/*   d32 is the source decimal32                                      */
 409/*   returns 1 if the encoding of d32 is canonical, 0 otherwise       */
 410/* No error is possible.                                              */
 411/* ------------------------------------------------------------------ */
 412uint32_t decimal32IsCanonical(const decimal32 *d32) {
 413  decNumber dn;                         /* work */
 414  decimal32 canon;                      /* .. */
 415  decContext dc;                        /* .. */
 416  decContextDefault(&dc, DEC_INIT_DECIMAL32);
 417  decimal32ToNumber(d32, &dn);
 418  decimal32FromNumber(&canon, &dn, &dc);/* canon will now be canonical */
 419  return memcmp(d32, &canon, DECIMAL32_Bytes)==0;
 420  } /* decimal32IsCanonical */
 421
 422/* ------------------------------------------------------------------ */
 423/* decimal32Canonical -- copy an encoding, ensuring it is canonical   */
 424/*   d32 is the source decimal32                                      */
 425/*   result is the target (may be the same decimal32)                 */
 426/*   returns result                                                   */
 427/* No error is possible.                                              */
 428/* ------------------------------------------------------------------ */
 429decimal32 * decimal32Canonical(decimal32 *result, const decimal32 *d32) {
 430  decNumber dn;                         /* work */
 431  decContext dc;                        /* .. */
 432  decContextDefault(&dc, DEC_INIT_DECIMAL32);
 433  decimal32ToNumber(d32, &dn);
 434  decimal32FromNumber(result, &dn, &dc);/* result will now be canonical */
 435  return result;
 436  } /* decimal32Canonical */
 437
 438#if DECTRACE || DECCHECK
 439/* Macros for accessing decimal32 fields.  These assume the argument
 440   is a reference (pointer) to the decimal32 structure, and the
 441   decimal32 is in network byte order (big-endian) */
 442/* Get sign */
 443#define decimal32Sign(d)       ((unsigned)(d)->bytes[0]>>7)
 444
 445/* Get combination field */
 446#define decimal32Comb(d)       (((d)->bytes[0] & 0x7c)>>2)
 447
 448/* Get exponent continuation [does not remove bias] */
 449#define decimal32ExpCon(d)     ((((d)->bytes[0] & 0x03)<<4)           \
 450                             | ((unsigned)(d)->bytes[1]>>4))
 451
 452/* Set sign [this assumes sign previously 0] */
 453#define decimal32SetSign(d, b) {                                      \
 454  (d)->bytes[0]|=((unsigned)(b)<<7);}
 455
 456/* Set exponent continuation [does not apply bias] */
 457/* This assumes range has been checked and exponent previously 0; */
 458/* type of exponent must be unsigned */
 459#define decimal32SetExpCon(d, e) {                                    \
 460  (d)->bytes[0]|=(uint8_t)((e)>>4);                                   \
 461  (d)->bytes[1]|=(uint8_t)(((e)&0x0F)<<4);}
 462
 463/* ------------------------------------------------------------------ */
 464/* decimal32Show -- display a decimal32 in hexadecimal [debug aid]    */
 465/*   d32 -- the number to show                                        */
 466/* ------------------------------------------------------------------ */
 467/* Also shows sign/cob/expconfields extracted - valid bigendian only */
 468void decimal32Show(const decimal32 *d32) {
 469  char buf[DECIMAL32_Bytes*2+1];
 470  Int i, j=0;
 471
 472  if (DECLITEND) {
 473    for (i=0; i<DECIMAL32_Bytes; i++, j+=2) {
 474      sprintf(&buf[j], "%02x", d32->bytes[3-i]);
 475      }
 476    printf(" D32> %s [S:%d Cb:%02x Ec:%02x] LittleEndian\n", buf,
 477           d32->bytes[3]>>7, (d32->bytes[3]>>2)&0x1f,
 478           ((d32->bytes[3]&0x3)<<4)| (d32->bytes[2]>>4));
 479    }
 480   else {
 481    for (i=0; i<DECIMAL32_Bytes; i++, j+=2) {
 482      sprintf(&buf[j], "%02x", d32->bytes[i]);
 483      }
 484    printf(" D32> %s [S:%d Cb:%02x Ec:%02x] BigEndian\n", buf,
 485           decimal32Sign(d32), decimal32Comb(d32), decimal32ExpCon(d32));
 486    }
 487  } /* decimal32Show */
 488#endif
 489