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