xref: /qemu/libdecnumber/dpd/decimal128.c (revision 7a4e543d)
172ac97cdSTom Musta /* Decimal 128-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 128-bit format module				      */
3372ac97cdSTom Musta /* ------------------------------------------------------------------ */
3472ac97cdSTom Musta /* This module comprises the routines for decimal128 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 34      /* make decNumbers with space for 34 */
460f2d3732STom Musta #include "libdecnumber/decNumber.h"
470f2d3732STom Musta #include "libdecnumber/decNumberLocal.h"
480f2d3732STom Musta #include "libdecnumber/dpd/decimal128.h"
4972ac97cdSTom Musta 
5072ac97cdSTom Musta /* Utility routines and tables [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 decDigitsFromDPD(decNumber *, const uInt *, Int);
5572ac97cdSTom Musta extern void decDigitsToDPD(const decNumber *, uInt *, Int);
5672ac97cdSTom Musta 
5772ac97cdSTom Musta #if DECTRACE || DECCHECK
5872ac97cdSTom Musta void decimal128Show(const decimal128 *);	  /* 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 /* decimal128FromNumber -- convert decNumber to decimal128	      */
6872ac97cdSTom Musta /*								      */
6972ac97cdSTom Musta /*   ds is the target decimal128				      */
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 DECIMAL128_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 /* ------------------------------------------------------------------ */
decimal128FromNumber(decimal128 * d128,const decNumber * dn,decContext * set)8372ac97cdSTom Musta decimal128 * decimal128FromNumber(decimal128 *d128, 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 targar[4]={0,0,0,0};	   /* target 128-bit */
9272ac97cdSTom Musta   #define targhi targar[3]	   /* name the word with the sign */
9372ac97cdSTom Musta   #define targmh targar[2]	   /* name the words */
9472ac97cdSTom Musta   #define targml targar[1]	   /* .. */
9572ac97cdSTom Musta   #define targlo targar[0]	   /* .. */
9672ac97cdSTom Musta 
9772ac97cdSTom Musta   /* If the number has too many digits, or the exponent could be */
9872ac97cdSTom Musta   /* out of range then reduce the number under the appropriate */
9972ac97cdSTom Musta   /* constraints.  This could push the number to Infinity or zero, */
10072ac97cdSTom Musta   /* so this check and rounding must be done before generating the */
10172ac97cdSTom Musta   /* decimal128] */
10272ac97cdSTom Musta   ae=dn->exponent+dn->digits-1;		     /* [0 if special] */
10372ac97cdSTom Musta   if (dn->digits>DECIMAL128_Pmax	     /* too many digits */
10472ac97cdSTom Musta    || ae>DECIMAL128_Emax		     /* likely overflow */
10572ac97cdSTom Musta    || ae<DECIMAL128_Emin) {		     /* likely underflow */
10672ac97cdSTom Musta     decContextDefault(&dc, DEC_INIT_DECIMAL128); /* [no traps] */
10772ac97cdSTom Musta     dc.round=set->round;		     /* use supplied rounding */
10872ac97cdSTom Musta     decNumberPlus(&dw, dn, &dc);	     /* (round and check) */
10972ac97cdSTom Musta     /* [this changes -0 to 0, so enforce the sign...] */
11072ac97cdSTom Musta     dw.bits|=dn->bits&DECNEG;
11172ac97cdSTom Musta     status=dc.status;			     /* save status */
11272ac97cdSTom Musta     dn=&dw;				     /* use the work number */
11372ac97cdSTom Musta     } /* maybe out of range */
11472ac97cdSTom Musta 
11572ac97cdSTom Musta   if (dn->bits&DECSPECIAL) {			  /* a special value */
11672ac97cdSTom Musta     if (dn->bits&DECINF) targhi=DECIMAL_Inf<<24;
11772ac97cdSTom Musta      else {					  /* sNaN or qNaN */
11872ac97cdSTom Musta       if ((*dn->lsu!=0 || dn->digits>1)		  /* non-zero coefficient */
11972ac97cdSTom Musta        && (dn->digits<DECIMAL128_Pmax)) {	  /* coefficient fits */
12072ac97cdSTom Musta 	decDigitsToDPD(dn, targar, 0);
12172ac97cdSTom Musta 	}
12272ac97cdSTom Musta       if (dn->bits&DECNAN) targhi|=DECIMAL_NaN<<24;
12372ac97cdSTom Musta        else targhi|=DECIMAL_sNaN<<24;
12472ac97cdSTom Musta       } /* a NaN */
12572ac97cdSTom Musta     } /* special */
12672ac97cdSTom Musta 
12772ac97cdSTom Musta    else { /* is finite */
12872ac97cdSTom Musta     if (decNumberIsZero(dn)) {		     /* is a zero */
12972ac97cdSTom Musta       /* set and clamp exponent */
13072ac97cdSTom Musta       if (dn->exponent<-DECIMAL128_Bias) {
13172ac97cdSTom Musta 	exp=0;				     /* low clamp */
13272ac97cdSTom Musta 	status|=DEC_Clamped;
13372ac97cdSTom Musta 	}
13472ac97cdSTom Musta        else {
13572ac97cdSTom Musta 	exp=dn->exponent+DECIMAL128_Bias;    /* bias exponent */
13672ac97cdSTom Musta 	if (exp>DECIMAL128_Ehigh) {	     /* top clamp */
13772ac97cdSTom Musta 	  exp=DECIMAL128_Ehigh;
13872ac97cdSTom Musta 	  status|=DEC_Clamped;
13972ac97cdSTom Musta 	  }
14072ac97cdSTom Musta 	}
14172ac97cdSTom Musta       comb=(exp>>9) & 0x18;		/* msd=0, exp top 2 bits .. */
14272ac97cdSTom Musta       }
14372ac97cdSTom Musta      else {				/* non-zero finite number */
14472ac97cdSTom Musta       uInt msd;				/* work */
14572ac97cdSTom Musta       Int pad=0;			/* coefficient pad digits */
14672ac97cdSTom Musta 
14772ac97cdSTom Musta       /* the dn is known to fit, but it may need to be padded */
14872ac97cdSTom Musta       exp=(uInt)(dn->exponent+DECIMAL128_Bias);	   /* bias exponent */
14972ac97cdSTom Musta       if (exp>DECIMAL128_Ehigh) {		   /* fold-down case */
15072ac97cdSTom Musta 	pad=exp-DECIMAL128_Ehigh;
15172ac97cdSTom Musta 	exp=DECIMAL128_Ehigh;			   /* [to maximum] */
15272ac97cdSTom Musta 	status|=DEC_Clamped;
15372ac97cdSTom Musta 	}
15472ac97cdSTom Musta 
15572ac97cdSTom Musta       /* [fastpath for common case is not a win, here] */
15672ac97cdSTom Musta       decDigitsToDPD(dn, targar, pad);
15772ac97cdSTom Musta       /* save and clear the top digit */
15872ac97cdSTom Musta       msd=targhi>>14;
15972ac97cdSTom Musta       targhi&=0x00003fff;
16072ac97cdSTom Musta 
16172ac97cdSTom Musta       /* create the combination field */
16272ac97cdSTom Musta       if (msd>=8) comb=0x18 | ((exp>>11) & 0x06) | (msd & 0x01);
16372ac97cdSTom Musta 	     else comb=((exp>>9) & 0x18) | msd;
16472ac97cdSTom Musta       }
16572ac97cdSTom Musta     targhi|=comb<<26;		   /* add combination field .. */
16672ac97cdSTom Musta     targhi|=(exp&0xfff)<<14;	   /* .. and exponent continuation */
16772ac97cdSTom Musta     } /* finite */
16872ac97cdSTom Musta 
16972ac97cdSTom Musta   if (dn->bits&DECNEG) targhi|=0x80000000; /* add sign bit */
17072ac97cdSTom Musta 
17172ac97cdSTom Musta   /* now write to storage; this is endian */
17272ac97cdSTom Musta   pu=(uInt *)d128->bytes;	   /* overlay */
17372ac97cdSTom Musta   if (DECLITEND) {
17472ac97cdSTom Musta     pu[0]=targlo;		   /* directly store the low int */
17572ac97cdSTom Musta     pu[1]=targml;		   /* then the mid-low */
17672ac97cdSTom Musta     pu[2]=targmh;		   /* then the mid-high */
17772ac97cdSTom Musta     pu[3]=targhi;		   /* then the high int */
17872ac97cdSTom Musta     }
17972ac97cdSTom Musta    else {
18072ac97cdSTom Musta     pu[0]=targhi;		   /* directly store the high int */
18172ac97cdSTom Musta     pu[1]=targmh;		   /* then the mid-high */
18272ac97cdSTom Musta     pu[2]=targml;		   /* then the mid-low */
18372ac97cdSTom Musta     pu[3]=targlo;		   /* then the low int */
18472ac97cdSTom Musta     }
18572ac97cdSTom Musta 
18672ac97cdSTom Musta   if (status!=0) decContextSetStatus(set, status); /* pass on status */
18772ac97cdSTom Musta   /* decimal128Show(d128); */
18872ac97cdSTom Musta   return d128;
18972ac97cdSTom Musta   } /* decimal128FromNumber */
19072ac97cdSTom Musta 
19172ac97cdSTom Musta /* ------------------------------------------------------------------ */
19272ac97cdSTom Musta /* decimal128ToNumber -- convert decimal128 to decNumber	      */
19372ac97cdSTom Musta /*   d128 is the source decimal128				      */
19472ac97cdSTom Musta /*   dn is the target number, with appropriate space		      */
19572ac97cdSTom Musta /* No error is possible.					      */
19672ac97cdSTom Musta /* ------------------------------------------------------------------ */
decimal128ToNumber(const decimal128 * d128,decNumber * dn)19772ac97cdSTom Musta decNumber * decimal128ToNumber(const decimal128 *d128, decNumber *dn) {
19872ac97cdSTom Musta   uInt msd;			   /* coefficient MSD */
19972ac97cdSTom Musta   uInt exp;			   /* exponent top two bits */
20072ac97cdSTom Musta   uInt comb;			   /* combination field */
20172ac97cdSTom Musta   const uInt *pu;		   /* work */
20272ac97cdSTom Musta   Int  need;			   /* .. */
20372ac97cdSTom Musta   uInt sourar[4];		   /* source 128-bit */
20472ac97cdSTom Musta   #define sourhi sourar[3]	   /* name the word with the sign */
20572ac97cdSTom Musta   #define sourmh sourar[2]	   /* and the mid-high word */
20672ac97cdSTom Musta   #define sourml sourar[1]	   /* and the mod-low word */
20772ac97cdSTom Musta   #define sourlo sourar[0]	   /* and the lowest word */
20872ac97cdSTom Musta 
20972ac97cdSTom Musta   /* load source from storage; this is endian */
21072ac97cdSTom Musta   pu=(const uInt *)d128->bytes;	   /* overlay */
21172ac97cdSTom Musta   if (DECLITEND) {
21272ac97cdSTom Musta     sourlo=pu[0];		   /* directly load the low int */
21372ac97cdSTom Musta     sourml=pu[1];		   /* then the mid-low */
21472ac97cdSTom Musta     sourmh=pu[2];		   /* then the mid-high */
21572ac97cdSTom Musta     sourhi=pu[3];		   /* then the high int */
21672ac97cdSTom Musta     }
21772ac97cdSTom Musta    else {
21872ac97cdSTom Musta     sourhi=pu[0];		   /* directly load the high int */
21972ac97cdSTom Musta     sourmh=pu[1];		   /* then the mid-high */
22072ac97cdSTom Musta     sourml=pu[2];		   /* then the mid-low */
22172ac97cdSTom Musta     sourlo=pu[3];		   /* then the low int */
22272ac97cdSTom Musta     }
22372ac97cdSTom Musta 
22472ac97cdSTom Musta   comb=(sourhi>>26)&0x1f;	   /* combination field */
22572ac97cdSTom Musta 
22672ac97cdSTom Musta   decNumberZero(dn);		   /* clean number */
22772ac97cdSTom Musta   if (sourhi&0x80000000) dn->bits=DECNEG; /* set sign if negative */
22872ac97cdSTom Musta 
22972ac97cdSTom Musta   msd=COMBMSD[comb];		   /* decode the combination field */
23072ac97cdSTom Musta   exp=COMBEXP[comb];		   /* .. */
23172ac97cdSTom Musta 
23272ac97cdSTom Musta   if (exp==3) {			   /* is a special */
23372ac97cdSTom Musta     if (msd==0) {
23472ac97cdSTom Musta       dn->bits|=DECINF;
23572ac97cdSTom Musta       return dn;		   /* no coefficient needed */
23672ac97cdSTom Musta       }
23772ac97cdSTom Musta     else if (sourhi&0x02000000) dn->bits|=DECSNAN;
23872ac97cdSTom Musta     else dn->bits|=DECNAN;
23972ac97cdSTom Musta     msd=0;			   /* no top digit */
24072ac97cdSTom Musta     }
24172ac97cdSTom Musta    else {			   /* is a finite number */
24272ac97cdSTom Musta     dn->exponent=(exp<<12)+((sourhi>>14)&0xfff)-DECIMAL128_Bias; /* unbiased */
24372ac97cdSTom Musta     }
24472ac97cdSTom Musta 
24572ac97cdSTom Musta   /* get the coefficient */
24672ac97cdSTom Musta   sourhi&=0x00003fff;		   /* clean coefficient continuation */
24772ac97cdSTom Musta   if (msd) {			   /* non-zero msd */
24872ac97cdSTom Musta     sourhi|=msd<<14;		   /* prefix to coefficient */
24972ac97cdSTom Musta     need=12;			   /* process 12 declets */
25072ac97cdSTom Musta     }
25172ac97cdSTom Musta    else { /* msd=0 */
25272ac97cdSTom Musta     if (sourhi) need=11;	   /* declets to process */
25372ac97cdSTom Musta      else if (sourmh) need=10;
25472ac97cdSTom Musta      else if (sourml) need=7;
25572ac97cdSTom Musta      else if (sourlo) need=4;
25672ac97cdSTom Musta      else return dn;		   /* easy: coefficient is 0 */
25772ac97cdSTom Musta     } /*msd=0 */
25872ac97cdSTom Musta 
25972ac97cdSTom Musta   decDigitsFromDPD(dn, sourar, need);	/* process declets */
26072ac97cdSTom Musta   /* decNumberShow(dn); */
26172ac97cdSTom Musta   return dn;
26272ac97cdSTom Musta   } /* decimal128ToNumber */
26372ac97cdSTom Musta 
26472ac97cdSTom Musta /* ------------------------------------------------------------------ */
26572ac97cdSTom Musta /* to-scientific-string -- conversion to numeric string		      */
26672ac97cdSTom Musta /* to-engineering-string -- conversion to numeric string	      */
26772ac97cdSTom Musta /*								      */
26872ac97cdSTom Musta /*   decimal128ToString(d128, string);				      */
26972ac97cdSTom Musta /*   decimal128ToEngString(d128, string);			      */
27072ac97cdSTom Musta /*								      */
27172ac97cdSTom Musta /*  d128 is the decimal128 format number to convert		      */
27272ac97cdSTom Musta /*  string is the string where the result will be laid out	      */
27372ac97cdSTom Musta /*								      */
27472ac97cdSTom Musta /*  string must be at least 24 characters			      */
27572ac97cdSTom Musta /*								      */
27672ac97cdSTom Musta /*  No error is possible, and no status can be set.		      */
27772ac97cdSTom Musta /* ------------------------------------------------------------------ */
decimal128ToEngString(const decimal128 * d128,char * string)27872ac97cdSTom Musta char * decimal128ToEngString(const decimal128 *d128, char *string){
27972ac97cdSTom Musta   decNumber dn;				/* work */
28072ac97cdSTom Musta   decimal128ToNumber(d128, &dn);
28172ac97cdSTom Musta   decNumberToEngString(&dn, string);
28272ac97cdSTom Musta   return string;
28372ac97cdSTom Musta   } /* decimal128ToEngString */
28472ac97cdSTom Musta 
decimal128ToString(const decimal128 * d128,char * string)28572ac97cdSTom Musta char * decimal128ToString(const decimal128 *d128, char *string){
28672ac97cdSTom Musta   uInt msd;			   /* coefficient MSD */
28772ac97cdSTom Musta   Int  exp;			   /* exponent top two bits or full */
28872ac97cdSTom Musta   uInt comb;			   /* combination field */
28972ac97cdSTom Musta   char *cstart;			   /* coefficient start */
29072ac97cdSTom Musta   char *c;			   /* output pointer in string */
29172ac97cdSTom Musta   const uInt *pu;		   /* work */
29272ac97cdSTom Musta   char *s, *t;			   /* .. (source, target) */
29372ac97cdSTom Musta   Int  dpd;			   /* .. */
29472ac97cdSTom Musta   Int  pre, e;			   /* .. */
29572ac97cdSTom Musta   const uByte *u;		   /* .. */
29672ac97cdSTom Musta 
29772ac97cdSTom Musta   uInt sourar[4];		   /* source 128-bit */
29872ac97cdSTom Musta   #define sourhi sourar[3]	   /* name the word with the sign */
29972ac97cdSTom Musta   #define sourmh sourar[2]	   /* and the mid-high word */
30072ac97cdSTom Musta   #define sourml sourar[1]	   /* and the mod-low word */
30172ac97cdSTom Musta   #define sourlo sourar[0]	   /* and the lowest word */
30272ac97cdSTom Musta 
30372ac97cdSTom Musta   /* load source from storage; this is endian */
30472ac97cdSTom Musta   pu=(const uInt *)d128->bytes;	   /* overlay */
30572ac97cdSTom Musta   if (DECLITEND) {
30672ac97cdSTom Musta     sourlo=pu[0];		   /* directly load the low int */
30772ac97cdSTom Musta     sourml=pu[1];		   /* then the mid-low */
30872ac97cdSTom Musta     sourmh=pu[2];		   /* then the mid-high */
30972ac97cdSTom Musta     sourhi=pu[3];		   /* then the high int */
31072ac97cdSTom Musta     }
31172ac97cdSTom Musta    else {
31272ac97cdSTom Musta     sourhi=pu[0];		   /* directly load the high int */
31372ac97cdSTom Musta     sourmh=pu[1];		   /* then the mid-high */
31472ac97cdSTom Musta     sourml=pu[2];		   /* then the mid-low */
31572ac97cdSTom Musta     sourlo=pu[3];		   /* then the low int */
31672ac97cdSTom Musta     }
31772ac97cdSTom Musta 
31872ac97cdSTom Musta   c=string;			   /* where result will go */
31972ac97cdSTom Musta   if (((Int)sourhi)<0) *c++='-';   /* handle sign */
32072ac97cdSTom Musta 
32172ac97cdSTom Musta   comb=(sourhi>>26)&0x1f;	   /* combination field */
32272ac97cdSTom Musta   msd=COMBMSD[comb];		   /* decode the combination field */
32372ac97cdSTom Musta   exp=COMBEXP[comb];		   /* .. */
32472ac97cdSTom Musta 
32572ac97cdSTom Musta   if (exp==3) {
32672ac97cdSTom Musta     if (msd==0) {		   /* infinity */
32772ac97cdSTom Musta       strcpy(c,	  "Inf");
32872ac97cdSTom Musta       strcpy(c+3, "inity");
32972ac97cdSTom Musta       return string;		   /* easy */
33072ac97cdSTom Musta       }
33172ac97cdSTom Musta     if (sourhi&0x02000000) *c++='s'; /* sNaN */
33272ac97cdSTom Musta     strcpy(c, "NaN");		   /* complete word */
33372ac97cdSTom Musta     c+=3;			   /* step past */
33472ac97cdSTom Musta     if (sourlo==0 && sourml==0 && sourmh==0
33572ac97cdSTom Musta      && (sourhi&0x0003ffff)==0) return string; /* zero payload */
33672ac97cdSTom Musta     /* otherwise drop through to add integer; set correct exp */
33772ac97cdSTom Musta     exp=0; msd=0;		   /* setup for following code */
33872ac97cdSTom Musta     }
33972ac97cdSTom Musta    else exp=(exp<<12)+((sourhi>>14)&0xfff)-DECIMAL128_Bias; /* unbiased */
34072ac97cdSTom Musta 
34172ac97cdSTom Musta   /* convert 34 digits of significand to characters */
34272ac97cdSTom Musta   cstart=c;			   /* save start of coefficient */
34372ac97cdSTom Musta   if (msd) *c++='0'+(char)msd;	   /* non-zero most significant digit */
34472ac97cdSTom Musta 
34572ac97cdSTom Musta   /* Now decode the declets.  After extracting each one, it is */
34672ac97cdSTom Musta   /* decoded to binary and then to a 4-char sequence by table lookup; */
34772ac97cdSTom Musta   /* the 4-chars are a 1-char length (significant digits, except 000 */
34872ac97cdSTom Musta   /* has length 0).  This allows us to left-align the first declet */
34972ac97cdSTom Musta   /* with non-zero content, then remaining ones are full 3-char */
35072ac97cdSTom Musta   /* length.  We use fixed-length memcpys because variable-length */
35172ac97cdSTom Musta   /* causes a subroutine call in GCC.  (These are length 4 for speed */
35272ac97cdSTom Musta   /* and are safe because the array has an extra terminator byte.) */
35372ac97cdSTom Musta   #define dpd2char u=&BIN2CHAR[DPD2BIN[dpd]*4];			  \
35472ac97cdSTom Musta 		   if (c!=cstart) {memcpy(c, u+1, 4); c+=3;}	  \
35572ac97cdSTom Musta 		    else if (*u)  {memcpy(c, u+4-*u, 4); c+=*u;}
35672ac97cdSTom Musta   dpd=(sourhi>>4)&0x3ff;		     /* declet 1 */
35772ac97cdSTom Musta   dpd2char;
35872ac97cdSTom Musta   dpd=((sourhi&0xf)<<6) | (sourmh>>26);	     /* declet 2 */
35972ac97cdSTom Musta   dpd2char;
36072ac97cdSTom Musta   dpd=(sourmh>>16)&0x3ff;		     /* declet 3 */
36172ac97cdSTom Musta   dpd2char;
36272ac97cdSTom Musta   dpd=(sourmh>>6)&0x3ff;		     /* declet 4 */
36372ac97cdSTom Musta   dpd2char;
36472ac97cdSTom Musta   dpd=((sourmh&0x3f)<<4) | (sourml>>28);     /* declet 5 */
36572ac97cdSTom Musta   dpd2char;
36672ac97cdSTom Musta   dpd=(sourml>>18)&0x3ff;		     /* declet 6 */
36772ac97cdSTom Musta   dpd2char;
36872ac97cdSTom Musta   dpd=(sourml>>8)&0x3ff;		     /* declet 7 */
36972ac97cdSTom Musta   dpd2char;
37072ac97cdSTom Musta   dpd=((sourml&0xff)<<2) | (sourlo>>30);     /* declet 8 */
37172ac97cdSTom Musta   dpd2char;
37272ac97cdSTom Musta   dpd=(sourlo>>20)&0x3ff;		     /* declet 9 */
37372ac97cdSTom Musta   dpd2char;
37472ac97cdSTom Musta   dpd=(sourlo>>10)&0x3ff;		     /* declet 10 */
37572ac97cdSTom Musta   dpd2char;
37672ac97cdSTom Musta   dpd=(sourlo)&0x3ff;			     /* declet 11 */
37772ac97cdSTom Musta   dpd2char;
37872ac97cdSTom Musta 
37972ac97cdSTom Musta   if (c==cstart) *c++='0';	   /* all zeros -- make 0 */
38072ac97cdSTom Musta 
38172ac97cdSTom Musta   if (exp==0) {			   /* integer or NaN case -- easy */
38272ac97cdSTom Musta     *c='\0';			   /* terminate */
38372ac97cdSTom Musta     return string;
38472ac97cdSTom Musta     }
38572ac97cdSTom Musta 
38672ac97cdSTom Musta   /* non-0 exponent */
38772ac97cdSTom Musta   e=0;				   /* assume no E */
38872ac97cdSTom Musta   pre=c-cstart+exp;
38972ac97cdSTom Musta   /* [here, pre-exp is the digits count (==1 for zero)] */
39072ac97cdSTom Musta   if (exp>0 || pre<-5) {	   /* need exponential form */
39172ac97cdSTom Musta     e=pre-1;			   /* calculate E value */
39272ac97cdSTom Musta     pre=1;			   /* assume one digit before '.' */
39372ac97cdSTom Musta     } /* exponential form */
39472ac97cdSTom Musta 
39572ac97cdSTom Musta   /* modify the coefficient, adding 0s, '.', and E+nn as needed */
39672ac97cdSTom Musta   s=c-1;			   /* source (LSD) */
39772ac97cdSTom Musta   if (pre>0) {			   /* ddd.ddd (plain), perhaps with E */
39872ac97cdSTom Musta     char *dotat=cstart+pre;
39972ac97cdSTom Musta     if (dotat<c) {		   /* if embedded dot needed... */
40072ac97cdSTom Musta       t=c;				/* target */
40172ac97cdSTom Musta       for (; s>=dotat; s--, t--) *t=*s; /* open the gap; leave t at gap */
40272ac97cdSTom Musta       *t='.';				/* insert the dot */
40372ac97cdSTom Musta       c++;				/* length increased by one */
40472ac97cdSTom Musta       }
40572ac97cdSTom Musta 
40672ac97cdSTom Musta     /* finally add the E-part, if needed; it will never be 0, and has */
40772ac97cdSTom Musta     /* a maximum length of 4 digits */
40872ac97cdSTom Musta     if (e!=0) {
40972ac97cdSTom Musta       *c++='E';			   /* starts with E */
41072ac97cdSTom Musta       *c++='+';			   /* assume positive */
41172ac97cdSTom Musta       if (e<0) {
41272ac97cdSTom Musta 	*(c-1)='-';		   /* oops, need '-' */
41372ac97cdSTom Musta 	e=-e;			   /* uInt, please */
41472ac97cdSTom Musta 	}
41572ac97cdSTom Musta       if (e<1000) {		   /* 3 (or fewer) digits case */
41672ac97cdSTom Musta 	u=&BIN2CHAR[e*4];	   /* -> length byte */
41772ac97cdSTom Musta 	memcpy(c, u+4-*u, 4);	   /* copy fixed 4 characters [is safe] */
41872ac97cdSTom Musta 	c+=*u;			   /* bump pointer appropriately */
41972ac97cdSTom Musta 	}
42072ac97cdSTom Musta        else {			   /* 4-digits */
42172ac97cdSTom Musta 	Int thou=((e>>3)*1049)>>17; /* e/1000 */
42272ac97cdSTom Musta 	Int rem=e-(1000*thou);	    /* e%1000 */
42372ac97cdSTom Musta 	*c++='0'+(char)thou;
42472ac97cdSTom Musta 	u=&BIN2CHAR[rem*4];	   /* -> length byte */
42572ac97cdSTom Musta 	memcpy(c, u+1, 4);	   /* copy fixed 3+1 characters [is safe] */
42672ac97cdSTom Musta 	c+=3;			   /* bump pointer, always 3 digits */
42772ac97cdSTom Musta 	}
42872ac97cdSTom Musta       }
42972ac97cdSTom Musta     *c='\0';			   /* add terminator */
43072ac97cdSTom Musta     /*printf("res %s\n", string); */
43172ac97cdSTom Musta     return string;
43272ac97cdSTom Musta     } /* pre>0 */
43372ac97cdSTom Musta 
43472ac97cdSTom Musta   /* -5<=pre<=0: here for plain 0.ddd or 0.000ddd forms (can never have E) */
43572ac97cdSTom Musta   t=c+1-pre;
43672ac97cdSTom Musta   *(t+1)='\0';				/* can add terminator now */
43772ac97cdSTom Musta   for (; s>=cstart; s--, t--) *t=*s;	/* shift whole coefficient right */
43872ac97cdSTom Musta   c=cstart;
43972ac97cdSTom Musta   *c++='0';				/* always starts with 0. */
44072ac97cdSTom Musta   *c++='.';
44172ac97cdSTom Musta   for (; pre<0; pre++) *c++='0';	/* add any 0's after '.' */
44272ac97cdSTom Musta   /*printf("res %s\n", string); */
44372ac97cdSTom Musta   return string;
44472ac97cdSTom Musta   } /* decimal128ToString */
44572ac97cdSTom Musta 
44672ac97cdSTom Musta /* ------------------------------------------------------------------ */
44772ac97cdSTom Musta /* to-number -- conversion from numeric string			      */
44872ac97cdSTom Musta /*								      */
44972ac97cdSTom Musta /*   decimal128FromString(result, string, set);			      */
45072ac97cdSTom Musta /*								      */
45172ac97cdSTom Musta /*  result  is the decimal128 format number which gets the result of  */
45272ac97cdSTom Musta /*	    the conversion					      */
45372ac97cdSTom Musta /*  *string is the character string which should contain a valid      */
45472ac97cdSTom Musta /*	    number (which may be a special value)		      */
45572ac97cdSTom Musta /*  set	    is the context					      */
45672ac97cdSTom Musta /*								      */
45772ac97cdSTom Musta /* The context is supplied to this routine is used for error handling */
45872ac97cdSTom Musta /* (setting of status and traps) and for the rounding mode, only.     */
45972ac97cdSTom Musta /* If an error occurs, the result will be a valid decimal128 NaN.     */
46072ac97cdSTom Musta /* ------------------------------------------------------------------ */
decimal128FromString(decimal128 * result,const char * string,decContext * set)46172ac97cdSTom Musta decimal128 * decimal128FromString(decimal128 *result, const char *string,
46272ac97cdSTom Musta 				  decContext *set) {
46372ac97cdSTom Musta   decContext dc;			     /* work */
46472ac97cdSTom Musta   decNumber dn;				     /* .. */
46572ac97cdSTom Musta 
46672ac97cdSTom Musta   decContextDefault(&dc, DEC_INIT_DECIMAL128); /* no traps, please */
46772ac97cdSTom Musta   dc.round=set->round;			       /* use supplied rounding */
46872ac97cdSTom Musta 
46972ac97cdSTom Musta   decNumberFromString(&dn, string, &dc);     /* will round if needed */
47072ac97cdSTom Musta   decimal128FromNumber(result, &dn, &dc);
47172ac97cdSTom Musta   if (dc.status!=0) {			     /* something happened */
47272ac97cdSTom Musta     decContextSetStatus(set, dc.status);     /* .. pass it on */
47372ac97cdSTom Musta     }
47472ac97cdSTom Musta   return result;
47572ac97cdSTom Musta   } /* decimal128FromString */
47672ac97cdSTom Musta 
47772ac97cdSTom Musta /* ------------------------------------------------------------------ */
47872ac97cdSTom Musta /* decimal128IsCanonical -- test whether encoding is canonical	      */
47972ac97cdSTom Musta /*   d128 is the source decimal128				      */
48072ac97cdSTom Musta /*   returns 1 if the encoding of d128 is canonical, 0 otherwise      */
48172ac97cdSTom Musta /* No error is possible.					      */
48272ac97cdSTom Musta /* ------------------------------------------------------------------ */
decimal128IsCanonical(const decimal128 * d128)48372ac97cdSTom Musta uint32_t decimal128IsCanonical(const decimal128 *d128) {
48472ac97cdSTom Musta   decNumber dn;				/* work */
48572ac97cdSTom Musta   decimal128 canon;			 /* .. */
48672ac97cdSTom Musta   decContext dc;			/* .. */
48772ac97cdSTom Musta   decContextDefault(&dc, DEC_INIT_DECIMAL128);
48872ac97cdSTom Musta   decimal128ToNumber(d128, &dn);
48972ac97cdSTom Musta   decimal128FromNumber(&canon, &dn, &dc);/* canon will now be canonical */
49072ac97cdSTom Musta   return memcmp(d128, &canon, DECIMAL128_Bytes)==0;
49172ac97cdSTom Musta   } /* decimal128IsCanonical */
49272ac97cdSTom Musta 
49372ac97cdSTom Musta /* ------------------------------------------------------------------ */
49472ac97cdSTom Musta /* decimal128Canonical -- copy an encoding, ensuring it is canonical  */
49572ac97cdSTom Musta /*   d128 is the source decimal128				      */
49672ac97cdSTom Musta /*   result is the target (may be the same decimal128)		      */
49772ac97cdSTom Musta /*   returns result						      */
49872ac97cdSTom Musta /* No error is possible.					      */
49972ac97cdSTom Musta /* ------------------------------------------------------------------ */
decimal128Canonical(decimal128 * result,const decimal128 * d128)50072ac97cdSTom Musta decimal128 * decimal128Canonical(decimal128 *result, const decimal128 *d128) {
50172ac97cdSTom Musta   decNumber dn;				/* work */
50272ac97cdSTom Musta   decContext dc;			/* .. */
50372ac97cdSTom Musta   decContextDefault(&dc, DEC_INIT_DECIMAL128);
50472ac97cdSTom Musta   decimal128ToNumber(d128, &dn);
50572ac97cdSTom Musta   decimal128FromNumber(result, &dn, &dc);/* result will now be canonical */
50672ac97cdSTom Musta   return result;
50772ac97cdSTom Musta   } /* decimal128Canonical */
50872ac97cdSTom Musta 
50972ac97cdSTom Musta #if DECTRACE || DECCHECK
51072ac97cdSTom Musta /* Macros for accessing decimal128 fields.  These assume the argument
51172ac97cdSTom Musta    is a reference (pointer) to the decimal128 structure, and the
51272ac97cdSTom Musta    decimal128 is in network byte order (big-endian) */
51372ac97cdSTom Musta /* Get sign */
51472ac97cdSTom Musta #define decimal128Sign(d)	((unsigned)(d)->bytes[0]>>7)
51572ac97cdSTom Musta 
51672ac97cdSTom Musta /* Get combination field */
51772ac97cdSTom Musta #define decimal128Comb(d)	(((d)->bytes[0] & 0x7c)>>2)
51872ac97cdSTom Musta 
51972ac97cdSTom Musta /* Get exponent continuation [does not remove bias] */
52072ac97cdSTom Musta #define decimal128ExpCon(d)	((((d)->bytes[0] & 0x03)<<10)	      \
52172ac97cdSTom Musta 			      | ((unsigned)(d)->bytes[1]<<2)	      \
52272ac97cdSTom Musta 			      | ((unsigned)(d)->bytes[2]>>6))
52372ac97cdSTom Musta 
52472ac97cdSTom Musta /* Set sign [this assumes sign previously 0] */
52572ac97cdSTom Musta #define decimal128SetSign(d, b) {				      \
52672ac97cdSTom Musta   (d)->bytes[0]|=((unsigned)(b)<<7);}
52772ac97cdSTom Musta 
52872ac97cdSTom Musta /* Set exponent continuation [does not apply bias] */
52972ac97cdSTom Musta /* This assumes range has been checked and exponent previously 0; */
53072ac97cdSTom Musta /* type of exponent must be unsigned */
53172ac97cdSTom Musta #define decimal128SetExpCon(d, e) {				      \
53272ac97cdSTom Musta   (d)->bytes[0]|=(uint8_t)((e)>>10);				      \
53372ac97cdSTom Musta   (d)->bytes[1] =(uint8_t)(((e)&0x3fc)>>2);			      \
53472ac97cdSTom Musta   (d)->bytes[2]|=(uint8_t)(((e)&0x03)<<6);}
53572ac97cdSTom Musta 
53672ac97cdSTom Musta /* ------------------------------------------------------------------ */
53772ac97cdSTom Musta /* decimal128Show -- display a decimal128 in hexadecimal [debug aid]  */
53872ac97cdSTom Musta /*   d128 -- the number to show					      */
53972ac97cdSTom Musta /* ------------------------------------------------------------------ */
54072ac97cdSTom Musta /* Also shows sign/cob/expconfields extracted */
decimal128Show(const decimal128 * d128)54172ac97cdSTom Musta void decimal128Show(const decimal128 *d128) {
54272ac97cdSTom Musta   char buf[DECIMAL128_Bytes*2+1];
54372ac97cdSTom Musta   Int i, j=0;
54472ac97cdSTom Musta 
54572ac97cdSTom Musta   if (DECLITEND) {
54672ac97cdSTom Musta     for (i=0; i<DECIMAL128_Bytes; i++, j+=2) {
54772ac97cdSTom Musta       sprintf(&buf[j], "%02x", d128->bytes[15-i]);
54872ac97cdSTom Musta       }
54972ac97cdSTom Musta     printf(" D128> %s [S:%d Cb:%02x Ec:%02x] LittleEndian\n", buf,
55072ac97cdSTom Musta 	   d128->bytes[15]>>7, (d128->bytes[15]>>2)&0x1f,
55172ac97cdSTom Musta 	   ((d128->bytes[15]&0x3)<<10)|(d128->bytes[14]<<2)|
55272ac97cdSTom Musta 	   (d128->bytes[13]>>6));
55372ac97cdSTom Musta     }
55472ac97cdSTom Musta    else {
55572ac97cdSTom Musta     for (i=0; i<DECIMAL128_Bytes; i++, j+=2) {
55672ac97cdSTom Musta       sprintf(&buf[j], "%02x", d128->bytes[i]);
55772ac97cdSTom Musta       }
55872ac97cdSTom Musta     printf(" D128> %s [S:%d Cb:%02x Ec:%02x] BigEndian\n", buf,
55972ac97cdSTom Musta 	   decimal128Sign(d128), decimal128Comb(d128),
56072ac97cdSTom Musta 	   decimal128ExpCon(d128));
56172ac97cdSTom Musta     }
56272ac97cdSTom Musta   } /* decimal128Show */
56372ac97cdSTom Musta #endif
564