xref: /openbmc/qemu/libdecnumber/dpd/decimal32.c (revision 09125c5e)
172ac97cdSTom Musta /* Decimal 32-bit format module for the decNumber C Library.
272ac97cdSTom Musta    Copyright (C) 2005, 2007 Free Software Foundation, Inc.
372ac97cdSTom Musta    Contributed by IBM Corporation.  Author Mike Cowlishaw.
472ac97cdSTom Musta 
572ac97cdSTom Musta    This file is part of GCC.
672ac97cdSTom Musta 
772ac97cdSTom Musta    GCC is free software; you can redistribute it and/or modify it under
872ac97cdSTom Musta    the terms of the GNU General Public License as published by the Free
972ac97cdSTom Musta    Software Foundation; either version 2, or (at your option) any later
1072ac97cdSTom Musta    version.
1172ac97cdSTom Musta 
1272ac97cdSTom Musta    In addition to the permissions in the GNU General Public License,
1372ac97cdSTom Musta    the Free Software Foundation gives you unlimited permission to link
1472ac97cdSTom Musta    the compiled version of this file into combinations with other
1572ac97cdSTom Musta    programs, and to distribute those combinations without any
1672ac97cdSTom Musta    restriction coming from the use of this file.  (The General Public
1772ac97cdSTom Musta    License restrictions do apply in other respects; for example, they
1872ac97cdSTom Musta    cover modification of the file, and distribution when not linked
1972ac97cdSTom Musta    into a combine executable.)
2072ac97cdSTom Musta 
2172ac97cdSTom Musta    GCC is distributed in the hope that it will be useful, but WITHOUT ANY
2272ac97cdSTom Musta    WARRANTY; without even the implied warranty of MERCHANTABILITY or
2372ac97cdSTom Musta    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
2472ac97cdSTom Musta    for more details.
2572ac97cdSTom Musta 
2672ac97cdSTom Musta    You should have received a copy of the GNU General Public License
2772ac97cdSTom Musta    along with GCC; see the file COPYING.  If not, write to the Free
2872ac97cdSTom Musta    Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
2972ac97cdSTom Musta    02110-1301, USA.  */
3072ac97cdSTom Musta 
3172ac97cdSTom Musta /* ------------------------------------------------------------------ */
3272ac97cdSTom Musta /* Decimal 32-bit format module					      */
3372ac97cdSTom Musta /* ------------------------------------------------------------------ */
3472ac97cdSTom Musta /* This module comprises the routines for decimal32 format numbers.   */
3572ac97cdSTom Musta /* Conversions are supplied to and from decNumber and String.	      */
3672ac97cdSTom Musta /*								      */
3772ac97cdSTom Musta /* This is used when decNumber provides operations, either for all    */
3872ac97cdSTom Musta /* operations or as a proxy between decNumber and decSingle.	      */
3972ac97cdSTom Musta /*								      */
4072ac97cdSTom Musta /* Error handling is the same as decNumber (qv.).		      */
4172ac97cdSTom Musta /* ------------------------------------------------------------------ */
42*7a4e543dSPeter Maydell #include "qemu/osdep.h"
4372ac97cdSTom Musta 
440f2d3732STom Musta #include "libdecnumber/dconfig.h"
4572ac97cdSTom Musta #define	 DECNUMDIGITS  7      /* make decNumbers with space for 7 */
460f2d3732STom Musta #include "libdecnumber/decNumber.h"
470f2d3732STom Musta #include "libdecnumber/decNumberLocal.h"
480f2d3732STom Musta #include "libdecnumber/dpd/decimal32.h"
4972ac97cdSTom Musta 
5072ac97cdSTom Musta /* Utility tables and routines [in decimal64.c] */
5172ac97cdSTom Musta extern const uInt   COMBEXP[32], COMBMSD[32];
5272ac97cdSTom Musta extern const uByte  BIN2CHAR[4001];
5372ac97cdSTom Musta 
5472ac97cdSTom Musta extern void decDigitsToDPD(const decNumber *, uInt *, Int);
5572ac97cdSTom Musta extern void decDigitsFromDPD(decNumber *, const uInt *, Int);
5672ac97cdSTom Musta 
5772ac97cdSTom Musta #if DECTRACE || DECCHECK
5872ac97cdSTom Musta void decimal32Show(const decimal32 *);		  /* for debug */
5972ac97cdSTom Musta extern void decNumberShow(const decNumber *);	  /* .. */
6072ac97cdSTom Musta #endif
6172ac97cdSTom Musta 
6272ac97cdSTom Musta /* Useful macro */
6372ac97cdSTom Musta /* Clear a structure (e.g., a decNumber) */
6472ac97cdSTom Musta #define DEC_clear(d) memset(d, 0, sizeof(*d))
6572ac97cdSTom Musta 
6672ac97cdSTom Musta /* ------------------------------------------------------------------ */
6772ac97cdSTom Musta /* decimal32FromNumber -- convert decNumber to decimal32	      */
6872ac97cdSTom Musta /*								      */
6972ac97cdSTom Musta /*   ds is the target decimal32					      */
7072ac97cdSTom Musta /*   dn is the source number (assumed valid)			      */
7172ac97cdSTom Musta /*   set is the context, used only for reporting errors		      */
7272ac97cdSTom Musta /*								      */
7372ac97cdSTom Musta /* The set argument is used only for status reporting and for the     */
7472ac97cdSTom Musta /* rounding mode (used if the coefficient is more than DECIMAL32_Pmax */
7572ac97cdSTom Musta /* digits or an overflow is detected).	If the exponent is out of the */
7672ac97cdSTom Musta /* valid range then Overflow or Underflow will be raised.	      */
7772ac97cdSTom Musta /* After Underflow a subnormal result is possible.		      */
7872ac97cdSTom Musta /*								      */
7972ac97cdSTom Musta /* DEC_Clamped is set if the number has to be 'folded down' to fit,   */
8072ac97cdSTom Musta /* by reducing its exponent and multiplying the coefficient by a      */
8172ac97cdSTom Musta /* power of ten, or if the exponent on a zero had to be clamped.      */
8272ac97cdSTom Musta /* ------------------------------------------------------------------ */
decimal32FromNumber(decimal32 * d32,const decNumber * dn,decContext * set)8372ac97cdSTom Musta decimal32 * decimal32FromNumber(decimal32 *d32, const decNumber *dn,
8472ac97cdSTom Musta 			      decContext *set) {
8572ac97cdSTom Musta   uInt status=0;		   /* status accumulator */
8672ac97cdSTom Musta   Int ae;			   /* adjusted exponent */
8772ac97cdSTom Musta   decNumber  dw;		   /* work */
8872ac97cdSTom Musta   decContext dc;		   /* .. */
8972ac97cdSTom Musta   uInt *pu;			   /* .. */
9072ac97cdSTom Musta   uInt comb, exp;		   /* .. */
9172ac97cdSTom Musta   uInt targ=0;			   /* target 32-bit */
9272ac97cdSTom Musta 
9372ac97cdSTom Musta   /* If the number has too many digits, or the exponent could be */
9472ac97cdSTom Musta   /* out of range then reduce the number under the appropriate */
9572ac97cdSTom Musta   /* constraints.  This could push the number to Infinity or zero, */
9672ac97cdSTom Musta   /* so this check and rounding must be done before generating the */
9772ac97cdSTom Musta   /* decimal32] */
9872ac97cdSTom Musta   ae=dn->exponent+dn->digits-1;		     /* [0 if special] */
9972ac97cdSTom Musta   if (dn->digits>DECIMAL32_Pmax		     /* too many digits */
10072ac97cdSTom Musta    || ae>DECIMAL32_Emax			     /* likely overflow */
10172ac97cdSTom Musta    || ae<DECIMAL32_Emin) {		     /* likely underflow */
10272ac97cdSTom Musta     decContextDefault(&dc, DEC_INIT_DECIMAL32); /* [no traps] */
10372ac97cdSTom Musta     dc.round=set->round;		     /* use supplied rounding */
10472ac97cdSTom Musta     decNumberPlus(&dw, dn, &dc);	     /* (round and check) */
10572ac97cdSTom Musta     /* [this changes -0 to 0, so enforce the sign...] */
10672ac97cdSTom Musta     dw.bits|=dn->bits&DECNEG;
10772ac97cdSTom Musta     status=dc.status;			     /* save status */
10872ac97cdSTom Musta     dn=&dw;				     /* use the work number */
10972ac97cdSTom Musta     } /* maybe out of range */
11072ac97cdSTom Musta 
11172ac97cdSTom Musta   if (dn->bits&DECSPECIAL) {			  /* a special value */
11272ac97cdSTom Musta     if (dn->bits&DECINF) targ=DECIMAL_Inf<<24;
11372ac97cdSTom Musta      else {					  /* sNaN or qNaN */
11472ac97cdSTom Musta       if ((*dn->lsu!=0 || dn->digits>1)		  /* non-zero coefficient */
11572ac97cdSTom Musta        && (dn->digits<DECIMAL32_Pmax)) {	  /* coefficient fits */
11672ac97cdSTom Musta 	decDigitsToDPD(dn, &targ, 0);
11772ac97cdSTom Musta 	}
11872ac97cdSTom Musta       if (dn->bits&DECNAN) targ|=DECIMAL_NaN<<24;
11972ac97cdSTom Musta        else targ|=DECIMAL_sNaN<<24;
12072ac97cdSTom Musta       } /* a NaN */
12172ac97cdSTom Musta     } /* special */
12272ac97cdSTom Musta 
12372ac97cdSTom Musta    else { /* is finite */
12472ac97cdSTom Musta     if (decNumberIsZero(dn)) {		     /* is a zero */
12572ac97cdSTom Musta       /* set and clamp exponent */
12672ac97cdSTom Musta       if (dn->exponent<-DECIMAL32_Bias) {
12772ac97cdSTom Musta 	exp=0;				     /* low clamp */
12872ac97cdSTom Musta 	status|=DEC_Clamped;
12972ac97cdSTom Musta 	}
13072ac97cdSTom Musta        else {
13172ac97cdSTom Musta 	exp=dn->exponent+DECIMAL32_Bias;     /* bias exponent */
13272ac97cdSTom Musta 	if (exp>DECIMAL32_Ehigh) {	     /* top clamp */
13372ac97cdSTom Musta 	  exp=DECIMAL32_Ehigh;
13472ac97cdSTom Musta 	  status|=DEC_Clamped;
13572ac97cdSTom Musta 	  }
13672ac97cdSTom Musta 	}
13772ac97cdSTom Musta       comb=(exp>>3) & 0x18;		/* msd=0, exp top 2 bits .. */
13872ac97cdSTom Musta       }
13972ac97cdSTom Musta      else {				/* non-zero finite number */
14072ac97cdSTom Musta       uInt msd;				/* work */
14172ac97cdSTom Musta       Int pad=0;			/* coefficient pad digits */
14272ac97cdSTom Musta 
14372ac97cdSTom Musta       /* the dn is known to fit, but it may need to be padded */
14472ac97cdSTom Musta       exp=(uInt)(dn->exponent+DECIMAL32_Bias);	  /* bias exponent */
14572ac97cdSTom Musta       if (exp>DECIMAL32_Ehigh) {		  /* fold-down case */
14672ac97cdSTom Musta 	pad=exp-DECIMAL32_Ehigh;
14772ac97cdSTom Musta 	exp=DECIMAL32_Ehigh;			  /* [to maximum] */
14872ac97cdSTom Musta 	status|=DEC_Clamped;
14972ac97cdSTom Musta 	}
15072ac97cdSTom Musta 
15172ac97cdSTom Musta       /* fastpath common case */
15272ac97cdSTom Musta       if (DECDPUN==3 && pad==0) {
15372ac97cdSTom Musta 	targ=BIN2DPD[dn->lsu[0]];
15472ac97cdSTom Musta 	if (dn->digits>3) targ|=(uInt)(BIN2DPD[dn->lsu[1]])<<10;
15572ac97cdSTom Musta 	msd=(dn->digits==7 ? dn->lsu[2] : 0);
15672ac97cdSTom Musta 	}
15772ac97cdSTom Musta        else { /* general case */
15872ac97cdSTom Musta 	decDigitsToDPD(dn, &targ, pad);
15972ac97cdSTom Musta 	/* save and clear the top digit */
16072ac97cdSTom Musta 	msd=targ>>20;
16172ac97cdSTom Musta 	targ&=0x000fffff;
16272ac97cdSTom Musta 	}
16372ac97cdSTom Musta 
16472ac97cdSTom Musta       /* create the combination field */
16572ac97cdSTom Musta       if (msd>=8) comb=0x18 | ((exp>>5) & 0x06) | (msd & 0x01);
16672ac97cdSTom Musta 	     else comb=((exp>>3) & 0x18) | msd;
16772ac97cdSTom Musta       }
16872ac97cdSTom Musta     targ|=comb<<26;		   /* add combination field .. */
16972ac97cdSTom Musta     targ|=(exp&0x3f)<<20;	   /* .. and exponent continuation */
17072ac97cdSTom Musta     } /* finite */
17172ac97cdSTom Musta 
17272ac97cdSTom Musta   if (dn->bits&DECNEG) targ|=0x80000000;  /* add sign bit */
17372ac97cdSTom Musta 
17472ac97cdSTom Musta   /* now write to storage; this is endian */
17572ac97cdSTom Musta   pu=(uInt *)d32->bytes;	   /* overlay */
17672ac97cdSTom Musta   *pu=targ;			   /* directly store the int */
17772ac97cdSTom Musta 
17872ac97cdSTom Musta   if (status!=0) decContextSetStatus(set, status); /* pass on status */
17972ac97cdSTom Musta   /* decimal32Show(d32); */
18072ac97cdSTom Musta   return d32;
18172ac97cdSTom Musta   } /* decimal32FromNumber */
18272ac97cdSTom Musta 
18372ac97cdSTom Musta /* ------------------------------------------------------------------ */
18472ac97cdSTom Musta /* decimal32ToNumber -- convert decimal32 to decNumber		      */
18572ac97cdSTom Musta /*   d32 is the source decimal32				      */
18672ac97cdSTom Musta /*   dn is the target number, with appropriate space		      */
18772ac97cdSTom Musta /* No error is possible.					      */
18872ac97cdSTom Musta /* ------------------------------------------------------------------ */
decimal32ToNumber(const decimal32 * d32,decNumber * dn)18972ac97cdSTom Musta decNumber * decimal32ToNumber(const decimal32 *d32, decNumber *dn) {
19072ac97cdSTom Musta   uInt msd;			   /* coefficient MSD */
19172ac97cdSTom Musta   uInt exp;			   /* exponent top two bits */
19272ac97cdSTom Musta   uInt comb;			   /* combination field */
19372ac97cdSTom Musta   uInt sour;			   /* source 32-bit */
19472ac97cdSTom Musta   const uInt *pu;		   /* work */
19572ac97cdSTom Musta 
19672ac97cdSTom Musta   /* load source from storage; this is endian */
19772ac97cdSTom Musta   pu=(const uInt *)d32->bytes;	   /* overlay */
19872ac97cdSTom Musta   sour=*pu;			   /* directly load the int */
19972ac97cdSTom Musta 
20072ac97cdSTom Musta   comb=(sour>>26)&0x1f;		   /* combination field */
20172ac97cdSTom Musta 
20272ac97cdSTom Musta   decNumberZero(dn);		   /* clean number */
20372ac97cdSTom Musta   if (sour&0x80000000) dn->bits=DECNEG; /* set sign if negative */
20472ac97cdSTom Musta 
20572ac97cdSTom Musta   msd=COMBMSD[comb];		   /* decode the combination field */
20672ac97cdSTom Musta   exp=COMBEXP[comb];		   /* .. */
20772ac97cdSTom Musta 
20872ac97cdSTom Musta   if (exp==3) {			   /* is a special */
20972ac97cdSTom Musta     if (msd==0) {
21072ac97cdSTom Musta       dn->bits|=DECINF;
21172ac97cdSTom Musta       return dn;		   /* no coefficient needed */
21272ac97cdSTom Musta       }
21372ac97cdSTom Musta     else if (sour&0x02000000) dn->bits|=DECSNAN;
21472ac97cdSTom Musta     else dn->bits|=DECNAN;
21572ac97cdSTom Musta     msd=0;			   /* no top digit */
21672ac97cdSTom Musta     }
21772ac97cdSTom Musta    else {			   /* is a finite number */
21872ac97cdSTom Musta     dn->exponent=(exp<<6)+((sour>>20)&0x3f)-DECIMAL32_Bias; /* unbiased */
21972ac97cdSTom Musta     }
22072ac97cdSTom Musta 
22172ac97cdSTom Musta   /* get the coefficient */
22272ac97cdSTom Musta   sour&=0x000fffff;		   /* clean coefficient continuation */
22372ac97cdSTom Musta   if (msd) {			   /* non-zero msd */
22472ac97cdSTom Musta     sour|=msd<<20;		   /* prefix to coefficient */
22572ac97cdSTom Musta     decDigitsFromDPD(dn, &sour, 3); /* process 3 declets */
22672ac97cdSTom Musta     return dn;
22772ac97cdSTom Musta     }
22872ac97cdSTom Musta   /* msd=0 */
22972ac97cdSTom Musta   if (!sour) return dn;		   /* easy: coefficient is 0 */
23072ac97cdSTom Musta   if (sour&0x000ffc00)		   /* need 2 declets? */
23172ac97cdSTom Musta     decDigitsFromDPD(dn, &sour, 2); /* process 2 declets */
23272ac97cdSTom Musta    else
23372ac97cdSTom Musta     decDigitsFromDPD(dn, &sour, 1); /* process 1 declet */
23472ac97cdSTom Musta   return dn;
23572ac97cdSTom Musta   } /* decimal32ToNumber */
23672ac97cdSTom Musta 
23772ac97cdSTom Musta /* ------------------------------------------------------------------ */
23872ac97cdSTom Musta /* to-scientific-string -- conversion to numeric string		      */
23972ac97cdSTom Musta /* to-engineering-string -- conversion to numeric string	      */
24072ac97cdSTom Musta /*								      */
24172ac97cdSTom Musta /*   decimal32ToString(d32, string);				      */
24272ac97cdSTom Musta /*   decimal32ToEngString(d32, string);				      */
24372ac97cdSTom Musta /*								      */
24472ac97cdSTom Musta /*  d32 is the decimal32 format number to convert		      */
24572ac97cdSTom Musta /*  string is the string where the result will be laid out	      */
24672ac97cdSTom Musta /*								      */
24772ac97cdSTom Musta /*  string must be at least 24 characters			      */
24872ac97cdSTom Musta /*								      */
24972ac97cdSTom Musta /*  No error is possible, and no status can be set.		      */
25072ac97cdSTom Musta /* ------------------------------------------------------------------ */
decimal32ToEngString(const decimal32 * d32,char * string)25172ac97cdSTom Musta char * decimal32ToEngString(const decimal32 *d32, char *string){
25272ac97cdSTom Musta   decNumber dn;				/* work */
25372ac97cdSTom Musta   decimal32ToNumber(d32, &dn);
25472ac97cdSTom Musta   decNumberToEngString(&dn, string);
25572ac97cdSTom Musta   return string;
25672ac97cdSTom Musta   } /* decimal32ToEngString */
25772ac97cdSTom Musta 
decimal32ToString(const decimal32 * d32,char * string)25872ac97cdSTom Musta char * decimal32ToString(const decimal32 *d32, char *string){
25972ac97cdSTom Musta   uInt msd;			   /* coefficient MSD */
26072ac97cdSTom Musta   Int  exp;			   /* exponent top two bits or full */
26172ac97cdSTom Musta   uInt comb;			   /* combination field */
26272ac97cdSTom Musta   char *cstart;			   /* coefficient start */
26372ac97cdSTom Musta   char *c;			   /* output pointer in string */
26472ac97cdSTom Musta   const uInt *pu;		   /* work */
26572ac97cdSTom Musta   const uByte *u;		   /* .. */
26672ac97cdSTom Musta   char *s, *t;			   /* .. (source, target) */
26772ac97cdSTom Musta   Int  dpd;			   /* .. */
26872ac97cdSTom Musta   Int  pre, e;			   /* .. */
26972ac97cdSTom Musta   uInt sour;			   /* source 32-bit */
27072ac97cdSTom Musta 
27172ac97cdSTom Musta   /* load source from storage; this is endian */
27272ac97cdSTom Musta   pu=(const uInt *)d32->bytes;	   /* overlay */
27372ac97cdSTom Musta   sour=*pu;			   /* directly load the int */
27472ac97cdSTom Musta 
27572ac97cdSTom Musta   c=string;			   /* where result will go */
27672ac97cdSTom Musta   if (((Int)sour)<0) *c++='-';	   /* handle sign */
27772ac97cdSTom Musta 
27872ac97cdSTom Musta   comb=(sour>>26)&0x1f;		   /* combination field */
27972ac97cdSTom Musta   msd=COMBMSD[comb];		   /* decode the combination field */
28072ac97cdSTom Musta   exp=COMBEXP[comb];		   /* .. */
28172ac97cdSTom Musta 
28272ac97cdSTom Musta   if (exp==3) {
28372ac97cdSTom Musta     if (msd==0) {		   /* infinity */
28472ac97cdSTom Musta       strcpy(c,	  "Inf");
28572ac97cdSTom Musta       strcpy(c+3, "inity");
28672ac97cdSTom Musta       return string;		   /* easy */
28772ac97cdSTom Musta       }
28872ac97cdSTom Musta     if (sour&0x02000000) *c++='s'; /* sNaN */
28972ac97cdSTom Musta     strcpy(c, "NaN");		   /* complete word */
29072ac97cdSTom Musta     c+=3;			   /* step past */
29172ac97cdSTom Musta     if ((sour&0x000fffff)==0) return string; /* zero payload */
29272ac97cdSTom Musta     /* otherwise drop through to add integer; set correct exp */
29372ac97cdSTom Musta     exp=0; msd=0;		   /* setup for following code */
29472ac97cdSTom Musta     }
29572ac97cdSTom Musta    else exp=(exp<<6)+((sour>>20)&0x3f)-DECIMAL32_Bias; /* unbiased */
29672ac97cdSTom Musta 
29772ac97cdSTom Musta   /* convert 7 digits of significand to characters */
29872ac97cdSTom Musta   cstart=c;			   /* save start of coefficient */
29972ac97cdSTom Musta   if (msd) *c++='0'+(char)msd;	   /* non-zero most significant digit */
30072ac97cdSTom Musta 
30172ac97cdSTom Musta   /* Now decode the declets.  After extracting each one, it is */
30272ac97cdSTom Musta   /* decoded to binary and then to a 4-char sequence by table lookup; */
30372ac97cdSTom Musta   /* the 4-chars are a 1-char length (significant digits, except 000 */
30472ac97cdSTom Musta   /* has length 0).  This allows us to left-align the first declet */
30572ac97cdSTom Musta   /* with non-zero content, then remaining ones are full 3-char */
30672ac97cdSTom Musta   /* length.  We use fixed-length memcpys because variable-length */
30772ac97cdSTom Musta   /* causes a subroutine call in GCC.  (These are length 4 for speed */
30872ac97cdSTom Musta   /* and are safe because the array has an extra terminator byte.) */
30972ac97cdSTom Musta   #define dpd2char u=&BIN2CHAR[DPD2BIN[dpd]*4];			  \
31072ac97cdSTom Musta 		   if (c!=cstart) {memcpy(c, u+1, 4); c+=3;}	  \
31172ac97cdSTom Musta 		    else if (*u)  {memcpy(c, u+4-*u, 4); c+=*u;}
31272ac97cdSTom Musta 
31372ac97cdSTom Musta   dpd=(sour>>10)&0x3ff;		   /* declet 1 */
31472ac97cdSTom Musta   dpd2char;
31572ac97cdSTom Musta   dpd=(sour)&0x3ff;		   /* declet 2 */
31672ac97cdSTom Musta   dpd2char;
31772ac97cdSTom Musta 
31872ac97cdSTom Musta   if (c==cstart) *c++='0';	   /* all zeros -- make 0 */
31972ac97cdSTom Musta 
32072ac97cdSTom Musta   if (exp==0) {			   /* integer or NaN case -- easy */
32172ac97cdSTom Musta     *c='\0';			   /* terminate */
32272ac97cdSTom Musta     return string;
32372ac97cdSTom Musta     }
32472ac97cdSTom Musta 
32572ac97cdSTom Musta   /* non-0 exponent */
32672ac97cdSTom Musta   e=0;				   /* assume no E */
32772ac97cdSTom Musta   pre=c-cstart+exp;
32872ac97cdSTom Musta   /* [here, pre-exp is the digits count (==1 for zero)] */
32972ac97cdSTom Musta   if (exp>0 || pre<-5) {	   /* need exponential form */
33072ac97cdSTom Musta     e=pre-1;			   /* calculate E value */
33172ac97cdSTom Musta     pre=1;			   /* assume one digit before '.' */
33272ac97cdSTom Musta     } /* exponential form */
33372ac97cdSTom Musta 
33472ac97cdSTom Musta   /* modify the coefficient, adding 0s, '.', and E+nn as needed */
33572ac97cdSTom Musta   s=c-1;			   /* source (LSD) */
33672ac97cdSTom Musta   if (pre>0) {			   /* ddd.ddd (plain), perhaps with E */
33772ac97cdSTom Musta     char *dotat=cstart+pre;
33872ac97cdSTom Musta     if (dotat<c) {		   /* if embedded dot needed... */
33972ac97cdSTom Musta       t=c;				/* target */
34072ac97cdSTom Musta       for (; s>=dotat; s--, t--) *t=*s; /* open the gap; leave t at gap */
34172ac97cdSTom Musta       *t='.';				/* insert the dot */
34272ac97cdSTom Musta       c++;				/* length increased by one */
34372ac97cdSTom Musta       }
34472ac97cdSTom Musta 
34572ac97cdSTom Musta     /* finally add the E-part, if needed; it will never be 0, and has */
34672ac97cdSTom Musta     /* a maximum length of 3 digits (E-101 case) */
34772ac97cdSTom Musta     if (e!=0) {
34872ac97cdSTom Musta       *c++='E';			   /* starts with E */
34972ac97cdSTom Musta       *c++='+';			   /* assume positive */
35072ac97cdSTom Musta       if (e<0) {
35172ac97cdSTom Musta 	*(c-1)='-';		   /* oops, need '-' */
35272ac97cdSTom Musta 	e=-e;			   /* uInt, please */
35372ac97cdSTom Musta 	}
35472ac97cdSTom Musta       u=&BIN2CHAR[e*4];		   /* -> length byte */
35572ac97cdSTom Musta       memcpy(c, u+4-*u, 4);	   /* copy fixed 4 characters [is safe] */
35672ac97cdSTom Musta       c+=*u;			   /* bump pointer appropriately */
35772ac97cdSTom Musta       }
35872ac97cdSTom Musta     *c='\0';			   /* add terminator */
35972ac97cdSTom Musta     /*printf("res %s\n", string); */
36072ac97cdSTom Musta     return string;
36172ac97cdSTom Musta     } /* pre>0 */
36272ac97cdSTom Musta 
36372ac97cdSTom Musta   /* -5<=pre<=0: here for plain 0.ddd or 0.000ddd forms (can never have E) */
36472ac97cdSTom Musta   t=c+1-pre;
36572ac97cdSTom Musta   *(t+1)='\0';				/* can add terminator now */
36672ac97cdSTom Musta   for (; s>=cstart; s--, t--) *t=*s;	/* shift whole coefficient right */
36772ac97cdSTom Musta   c=cstart;
36872ac97cdSTom Musta   *c++='0';				/* always starts with 0. */
36972ac97cdSTom Musta   *c++='.';
37072ac97cdSTom Musta   for (; pre<0; pre++) *c++='0';	/* add any 0's after '.' */
37172ac97cdSTom Musta   /*printf("res %s\n", string); */
37272ac97cdSTom Musta   return string;
37372ac97cdSTom Musta   } /* decimal32ToString */
37472ac97cdSTom Musta 
37572ac97cdSTom Musta /* ------------------------------------------------------------------ */
37672ac97cdSTom Musta /* to-number -- conversion from numeric string			      */
37772ac97cdSTom Musta /*								      */
37872ac97cdSTom Musta /*   decimal32FromString(result, string, set);			      */
37972ac97cdSTom Musta /*								      */
38072ac97cdSTom Musta /*  result  is the decimal32 format number which gets the result of   */
38172ac97cdSTom Musta /*	    the conversion					      */
38272ac97cdSTom Musta /*  *string is the character string which should contain a valid      */
38372ac97cdSTom Musta /*	    number (which may be a special value)		      */
38472ac97cdSTom Musta /*  set	    is the context					      */
38572ac97cdSTom Musta /*								      */
38672ac97cdSTom Musta /* The context is supplied to this routine is used for error handling */
38772ac97cdSTom Musta /* (setting of status and traps) and for the rounding mode, only.     */
38872ac97cdSTom Musta /* If an error occurs, the result will be a valid decimal32 NaN.      */
38972ac97cdSTom Musta /* ------------------------------------------------------------------ */
decimal32FromString(decimal32 * result,const char * string,decContext * set)39072ac97cdSTom Musta decimal32 * decimal32FromString(decimal32 *result, const char *string,
39172ac97cdSTom Musta 				decContext *set) {
39272ac97cdSTom Musta   decContext dc;			     /* work */
39372ac97cdSTom Musta   decNumber dn;				     /* .. */
39472ac97cdSTom Musta 
39572ac97cdSTom Musta   decContextDefault(&dc, DEC_INIT_DECIMAL32); /* no traps, please */
39672ac97cdSTom Musta   dc.round=set->round;			      /* use supplied rounding */
39772ac97cdSTom Musta 
39872ac97cdSTom Musta   decNumberFromString(&dn, string, &dc);     /* will round if needed */
39972ac97cdSTom Musta   decimal32FromNumber(result, &dn, &dc);
40072ac97cdSTom Musta   if (dc.status!=0) {			     /* something happened */
40172ac97cdSTom Musta     decContextSetStatus(set, dc.status);     /* .. pass it on */
40272ac97cdSTom Musta     }
40372ac97cdSTom Musta   return result;
40472ac97cdSTom Musta   } /* decimal32FromString */
40572ac97cdSTom Musta 
40672ac97cdSTom Musta /* ------------------------------------------------------------------ */
40772ac97cdSTom Musta /* decimal32IsCanonical -- test whether encoding is canonical	      */
40872ac97cdSTom Musta /*   d32 is the source decimal32				      */
40972ac97cdSTom Musta /*   returns 1 if the encoding of d32 is canonical, 0 otherwise	      */
41072ac97cdSTom Musta /* No error is possible.					      */
41172ac97cdSTom Musta /* ------------------------------------------------------------------ */
decimal32IsCanonical(const decimal32 * d32)41272ac97cdSTom Musta uint32_t decimal32IsCanonical(const decimal32 *d32) {
41372ac97cdSTom Musta   decNumber dn;				/* work */
41472ac97cdSTom Musta   decimal32 canon;			/* .. */
41572ac97cdSTom Musta   decContext dc;			/* .. */
41672ac97cdSTom Musta   decContextDefault(&dc, DEC_INIT_DECIMAL32);
41772ac97cdSTom Musta   decimal32ToNumber(d32, &dn);
41872ac97cdSTom Musta   decimal32FromNumber(&canon, &dn, &dc);/* canon will now be canonical */
41972ac97cdSTom Musta   return memcmp(d32, &canon, DECIMAL32_Bytes)==0;
42072ac97cdSTom Musta   } /* decimal32IsCanonical */
42172ac97cdSTom Musta 
42272ac97cdSTom Musta /* ------------------------------------------------------------------ */
42372ac97cdSTom Musta /* decimal32Canonical -- copy an encoding, ensuring it is canonical   */
42472ac97cdSTom Musta /*   d32 is the source decimal32				      */
42572ac97cdSTom Musta /*   result is the target (may be the same decimal32)		      */
42672ac97cdSTom Musta /*   returns result						      */
42772ac97cdSTom Musta /* No error is possible.					      */
42872ac97cdSTom Musta /* ------------------------------------------------------------------ */
decimal32Canonical(decimal32 * result,const decimal32 * d32)42972ac97cdSTom Musta decimal32 * decimal32Canonical(decimal32 *result, const decimal32 *d32) {
43072ac97cdSTom Musta   decNumber dn;				/* work */
43172ac97cdSTom Musta   decContext dc;			/* .. */
43272ac97cdSTom Musta   decContextDefault(&dc, DEC_INIT_DECIMAL32);
43372ac97cdSTom Musta   decimal32ToNumber(d32, &dn);
43472ac97cdSTom Musta   decimal32FromNumber(result, &dn, &dc);/* result will now be canonical */
43572ac97cdSTom Musta   return result;
43672ac97cdSTom Musta   } /* decimal32Canonical */
43772ac97cdSTom Musta 
43872ac97cdSTom Musta #if DECTRACE || DECCHECK
43972ac97cdSTom Musta /* Macros for accessing decimal32 fields.  These assume the argument
44072ac97cdSTom Musta    is a reference (pointer) to the decimal32 structure, and the
44172ac97cdSTom Musta    decimal32 is in network byte order (big-endian) */
44272ac97cdSTom Musta /* Get sign */
44372ac97cdSTom Musta #define decimal32Sign(d)       ((unsigned)(d)->bytes[0]>>7)
44472ac97cdSTom Musta 
44572ac97cdSTom Musta /* Get combination field */
44672ac97cdSTom Musta #define decimal32Comb(d)       (((d)->bytes[0] & 0x7c)>>2)
44772ac97cdSTom Musta 
44872ac97cdSTom Musta /* Get exponent continuation [does not remove bias] */
44972ac97cdSTom Musta #define decimal32ExpCon(d)     ((((d)->bytes[0] & 0x03)<<4)	      \
45072ac97cdSTom Musta 			     | ((unsigned)(d)->bytes[1]>>4))
45172ac97cdSTom Musta 
45272ac97cdSTom Musta /* Set sign [this assumes sign previously 0] */
45372ac97cdSTom Musta #define decimal32SetSign(d, b) {				      \
45472ac97cdSTom Musta   (d)->bytes[0]|=((unsigned)(b)<<7);}
45572ac97cdSTom Musta 
45672ac97cdSTom Musta /* Set exponent continuation [does not apply bias] */
45772ac97cdSTom Musta /* This assumes range has been checked and exponent previously 0; */
45872ac97cdSTom Musta /* type of exponent must be unsigned */
45972ac97cdSTom Musta #define decimal32SetExpCon(d, e) {				      \
46072ac97cdSTom Musta   (d)->bytes[0]|=(uint8_t)((e)>>4);				      \
46172ac97cdSTom Musta   (d)->bytes[1]|=(uint8_t)(((e)&0x0F)<<4);}
46272ac97cdSTom Musta 
46372ac97cdSTom Musta /* ------------------------------------------------------------------ */
46472ac97cdSTom Musta /* decimal32Show -- display a decimal32 in hexadecimal [debug aid]    */
46572ac97cdSTom Musta /*   d32 -- the number to show					      */
46672ac97cdSTom Musta /* ------------------------------------------------------------------ */
46772ac97cdSTom Musta /* Also shows sign/cob/expconfields extracted - valid bigendian only */
decimal32Show(const decimal32 * d32)46872ac97cdSTom Musta void decimal32Show(const decimal32 *d32) {
46972ac97cdSTom Musta   char buf[DECIMAL32_Bytes*2+1];
47072ac97cdSTom Musta   Int i, j=0;
47172ac97cdSTom Musta 
47272ac97cdSTom Musta   if (DECLITEND) {
47372ac97cdSTom Musta     for (i=0; i<DECIMAL32_Bytes; i++, j+=2) {
47472ac97cdSTom Musta       sprintf(&buf[j], "%02x", d32->bytes[3-i]);
47572ac97cdSTom Musta       }
47672ac97cdSTom Musta     printf(" D32> %s [S:%d Cb:%02x Ec:%02x] LittleEndian\n", buf,
47772ac97cdSTom Musta 	   d32->bytes[3]>>7, (d32->bytes[3]>>2)&0x1f,
47872ac97cdSTom Musta 	   ((d32->bytes[3]&0x3)<<4)| (d32->bytes[2]>>4));
47972ac97cdSTom Musta     }
48072ac97cdSTom Musta    else {
48172ac97cdSTom Musta     for (i=0; i<DECIMAL32_Bytes; i++, j+=2) {
48272ac97cdSTom Musta       sprintf(&buf[j], "%02x", d32->bytes[i]);
48372ac97cdSTom Musta       }
48472ac97cdSTom Musta     printf(" D32> %s [S:%d Cb:%02x Ec:%02x] BigEndian\n", buf,
48572ac97cdSTom Musta 	   decimal32Sign(d32), decimal32Comb(d32), decimal32ExpCon(d32));
48672ac97cdSTom Musta     }
48772ac97cdSTom Musta   } /* decimal32Show */
48872ac97cdSTom Musta #endif
489