xref: /openbmc/qemu/libdecnumber/dpd/decimal64.c (revision 0f2d3732202818fb85c09d1c204a08c4d79b70bc)
172ac97cdSTom Musta /* Decimal 64-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 64-bit format module					      */
3372ac97cdSTom Musta /* ------------------------------------------------------------------ */
3472ac97cdSTom Musta /* This module comprises the routines for decimal64 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 /* ------------------------------------------------------------------ */
4272ac97cdSTom Musta #include <string.h>	      /* [for memset/memcpy] */
4372ac97cdSTom Musta #include <stdio.h>	      /* [for printf] */
4472ac97cdSTom Musta 
45*0f2d3732STom Musta #include "libdecnumber/dconfig.h"
4672ac97cdSTom Musta #define	 DECNUMDIGITS 16      /* make decNumbers with space for 16 */
47*0f2d3732STom Musta #include "libdecnumber/decNumber.h"
48*0f2d3732STom Musta #include "libdecnumber/decNumberLocal.h"
49*0f2d3732STom Musta #include "libdecnumber/dpd/decimal64.h"
5072ac97cdSTom Musta 
5172ac97cdSTom Musta /* Utility routines and tables [in decimal64.c]; externs for C++ */
5272ac97cdSTom Musta extern const uInt COMBEXP[32], COMBMSD[32];
5372ac97cdSTom Musta extern const uShort DPD2BIN[1024];
5472ac97cdSTom Musta extern const uShort BIN2DPD[1000];
5572ac97cdSTom Musta extern const uByte  BIN2CHAR[4001];
5672ac97cdSTom Musta 
5772ac97cdSTom Musta extern void decDigitsFromDPD(decNumber *, const uInt *, Int);
5872ac97cdSTom Musta extern void decDigitsToDPD(const decNumber *, uInt *, Int);
5972ac97cdSTom Musta 
6072ac97cdSTom Musta #if DECTRACE || DECCHECK
6172ac97cdSTom Musta void decimal64Show(const decimal64 *);		  /* for debug */
6272ac97cdSTom Musta extern void decNumberShow(const decNumber *);	  /* .. */
6372ac97cdSTom Musta #endif
6472ac97cdSTom Musta 
6572ac97cdSTom Musta /* Useful macro */
6672ac97cdSTom Musta /* Clear a structure (e.g., a decNumber) */
6772ac97cdSTom Musta #define DEC_clear(d) memset(d, 0, sizeof(*d))
6872ac97cdSTom Musta 
6972ac97cdSTom Musta /* define and include the tables to use for conversions */
7072ac97cdSTom Musta #define DEC_BIN2CHAR 1
7172ac97cdSTom Musta #define DEC_DPD2BIN  1
7272ac97cdSTom Musta #define DEC_BIN2DPD  1		   /* used for all sizes */
73*0f2d3732STom Musta #include "libdecnumber/decDPD.h"
7472ac97cdSTom Musta 
7572ac97cdSTom Musta /* ------------------------------------------------------------------ */
7672ac97cdSTom Musta /* decimal64FromNumber -- convert decNumber to decimal64	      */
7772ac97cdSTom Musta /*								      */
7872ac97cdSTom Musta /*   ds is the target decimal64					      */
7972ac97cdSTom Musta /*   dn is the source number (assumed valid)			      */
8072ac97cdSTom Musta /*   set is the context, used only for reporting errors		      */
8172ac97cdSTom Musta /*								      */
8272ac97cdSTom Musta /* The set argument is used only for status reporting and for the     */
8372ac97cdSTom Musta /* rounding mode (used if the coefficient is more than DECIMAL64_Pmax */
8472ac97cdSTom Musta /* digits or an overflow is detected).	If the exponent is out of the */
8572ac97cdSTom Musta /* valid range then Overflow or Underflow will be raised.	      */
8672ac97cdSTom Musta /* After Underflow a subnormal result is possible.		      */
8772ac97cdSTom Musta /*								      */
8872ac97cdSTom Musta /* DEC_Clamped is set if the number has to be 'folded down' to fit,   */
8972ac97cdSTom Musta /* by reducing its exponent and multiplying the coefficient by a      */
9072ac97cdSTom Musta /* power of ten, or if the exponent on a zero had to be clamped.      */
9172ac97cdSTom Musta /* ------------------------------------------------------------------ */
9272ac97cdSTom Musta decimal64 * decimal64FromNumber(decimal64 *d64, const decNumber *dn,
9372ac97cdSTom Musta 				decContext *set) {
9472ac97cdSTom Musta   uInt status=0;		   /* status accumulator */
9572ac97cdSTom Musta   Int ae;			   /* adjusted exponent */
9672ac97cdSTom Musta   decNumber  dw;		   /* work */
9772ac97cdSTom Musta   decContext dc;		   /* .. */
9872ac97cdSTom Musta   uInt *pu;			   /* .. */
9972ac97cdSTom Musta   uInt comb, exp;		   /* .. */
10072ac97cdSTom Musta   uInt targar[2]={0, 0};	   /* target 64-bit */
10172ac97cdSTom Musta   #define targhi targar[1]	   /* name the word with the sign */
10272ac97cdSTom Musta   #define targlo targar[0]	   /* and the other */
10372ac97cdSTom Musta 
10472ac97cdSTom Musta   /* If the number has too many digits, or the exponent could be */
10572ac97cdSTom Musta   /* out of range then reduce the number under the appropriate */
10672ac97cdSTom Musta   /* constraints.  This could push the number to Infinity or zero, */
10772ac97cdSTom Musta   /* so this check and rounding must be done before generating the */
10872ac97cdSTom Musta   /* decimal64] */
10972ac97cdSTom Musta   ae=dn->exponent+dn->digits-1;		     /* [0 if special] */
11072ac97cdSTom Musta   if (dn->digits>DECIMAL64_Pmax		     /* too many digits */
11172ac97cdSTom Musta    || ae>DECIMAL64_Emax			     /* likely overflow */
11272ac97cdSTom Musta    || ae<DECIMAL64_Emin) {		     /* likely underflow */
11372ac97cdSTom Musta     decContextDefault(&dc, DEC_INIT_DECIMAL64); /* [no traps] */
11472ac97cdSTom Musta     dc.round=set->round;		     /* use supplied rounding */
11572ac97cdSTom Musta     decNumberPlus(&dw, dn, &dc);	     /* (round and check) */
11672ac97cdSTom Musta     /* [this changes -0 to 0, so enforce the sign...] */
11772ac97cdSTom Musta     dw.bits|=dn->bits&DECNEG;
11872ac97cdSTom Musta     status=dc.status;			     /* save status */
11972ac97cdSTom Musta     dn=&dw;				     /* use the work number */
12072ac97cdSTom Musta     } /* maybe out of range */
12172ac97cdSTom Musta 
12272ac97cdSTom Musta   if (dn->bits&DECSPECIAL) {			  /* a special value */
12372ac97cdSTom Musta     if (dn->bits&DECINF) targhi=DECIMAL_Inf<<24;
12472ac97cdSTom Musta      else {					  /* sNaN or qNaN */
12572ac97cdSTom Musta       if ((*dn->lsu!=0 || dn->digits>1)		  /* non-zero coefficient */
12672ac97cdSTom Musta        && (dn->digits<DECIMAL64_Pmax)) {	  /* coefficient fits */
12772ac97cdSTom Musta 	decDigitsToDPD(dn, targar, 0);
12872ac97cdSTom Musta 	}
12972ac97cdSTom Musta       if (dn->bits&DECNAN) targhi|=DECIMAL_NaN<<24;
13072ac97cdSTom Musta        else targhi|=DECIMAL_sNaN<<24;
13172ac97cdSTom Musta       } /* a NaN */
13272ac97cdSTom Musta     } /* special */
13372ac97cdSTom Musta 
13472ac97cdSTom Musta    else { /* is finite */
13572ac97cdSTom Musta     if (decNumberIsZero(dn)) {		     /* is a zero */
13672ac97cdSTom Musta       /* set and clamp exponent */
13772ac97cdSTom Musta       if (dn->exponent<-DECIMAL64_Bias) {
13872ac97cdSTom Musta 	exp=0;				     /* low clamp */
13972ac97cdSTom Musta 	status|=DEC_Clamped;
14072ac97cdSTom Musta 	}
14172ac97cdSTom Musta        else {
14272ac97cdSTom Musta 	exp=dn->exponent+DECIMAL64_Bias;     /* bias exponent */
14372ac97cdSTom Musta 	if (exp>DECIMAL64_Ehigh) {	     /* top clamp */
14472ac97cdSTom Musta 	  exp=DECIMAL64_Ehigh;
14572ac97cdSTom Musta 	  status|=DEC_Clamped;
14672ac97cdSTom Musta 	  }
14772ac97cdSTom Musta 	}
14872ac97cdSTom Musta       comb=(exp>>5) & 0x18;		/* msd=0, exp top 2 bits .. */
14972ac97cdSTom Musta       }
15072ac97cdSTom Musta      else {				/* non-zero finite number */
15172ac97cdSTom Musta       uInt msd;				/* work */
15272ac97cdSTom Musta       Int pad=0;			/* coefficient pad digits */
15372ac97cdSTom Musta 
15472ac97cdSTom Musta       /* the dn is known to fit, but it may need to be padded */
15572ac97cdSTom Musta       exp=(uInt)(dn->exponent+DECIMAL64_Bias);	  /* bias exponent */
15672ac97cdSTom Musta       if (exp>DECIMAL64_Ehigh) {		  /* fold-down case */
15772ac97cdSTom Musta 	pad=exp-DECIMAL64_Ehigh;
15872ac97cdSTom Musta 	exp=DECIMAL64_Ehigh;			  /* [to maximum] */
15972ac97cdSTom Musta 	status|=DEC_Clamped;
16072ac97cdSTom Musta 	}
16172ac97cdSTom Musta 
16272ac97cdSTom Musta       /* fastpath common case */
16372ac97cdSTom Musta       if (DECDPUN==3 && pad==0) {
16472ac97cdSTom Musta 	uInt dpd[6]={0,0,0,0,0,0};
16572ac97cdSTom Musta 	uInt i;
16672ac97cdSTom Musta 	Int d=dn->digits;
16772ac97cdSTom Musta 	for (i=0; d>0; i++, d-=3) dpd[i]=BIN2DPD[dn->lsu[i]];
16872ac97cdSTom Musta 	targlo =dpd[0];
16972ac97cdSTom Musta 	targlo|=dpd[1]<<10;
17072ac97cdSTom Musta 	targlo|=dpd[2]<<20;
17172ac97cdSTom Musta 	if (dn->digits>6) {
17272ac97cdSTom Musta 	  targlo|=dpd[3]<<30;
17372ac97cdSTom Musta 	  targhi =dpd[3]>>2;
17472ac97cdSTom Musta 	  targhi|=dpd[4]<<8;
17572ac97cdSTom Musta 	  }
17672ac97cdSTom Musta 	msd=dpd[5];		   /* [did not really need conversion] */
17772ac97cdSTom Musta 	}
17872ac97cdSTom Musta        else { /* general case */
17972ac97cdSTom Musta 	decDigitsToDPD(dn, targar, pad);
18072ac97cdSTom Musta 	/* save and clear the top digit */
18172ac97cdSTom Musta 	msd=targhi>>18;
18272ac97cdSTom Musta 	targhi&=0x0003ffff;
18372ac97cdSTom Musta 	}
18472ac97cdSTom Musta 
18572ac97cdSTom Musta       /* create the combination field */
18672ac97cdSTom Musta       if (msd>=8) comb=0x18 | ((exp>>7) & 0x06) | (msd & 0x01);
18772ac97cdSTom Musta 	     else comb=((exp>>5) & 0x18) | msd;
18872ac97cdSTom Musta       }
18972ac97cdSTom Musta     targhi|=comb<<26;		   /* add combination field .. */
19072ac97cdSTom Musta     targhi|=(exp&0xff)<<18;	   /* .. and exponent continuation */
19172ac97cdSTom Musta     } /* finite */
19272ac97cdSTom Musta 
19372ac97cdSTom Musta   if (dn->bits&DECNEG) targhi|=0x80000000; /* add sign bit */
19472ac97cdSTom Musta 
19572ac97cdSTom Musta   /* now write to storage; this is now always endian */
19672ac97cdSTom Musta   pu=(uInt *)d64->bytes;	   /* overlay */
19772ac97cdSTom Musta   if (DECLITEND) {
19872ac97cdSTom Musta     pu[0]=targar[0];		   /* directly store the low int */
19972ac97cdSTom Musta     pu[1]=targar[1];		   /* then the high int */
20072ac97cdSTom Musta     }
20172ac97cdSTom Musta    else {
20272ac97cdSTom Musta     pu[0]=targar[1];		   /* directly store the high int */
20372ac97cdSTom Musta     pu[1]=targar[0];		   /* then the low int */
20472ac97cdSTom Musta     }
20572ac97cdSTom Musta 
20672ac97cdSTom Musta   if (status!=0) decContextSetStatus(set, status); /* pass on status */
20772ac97cdSTom Musta   /* decimal64Show(d64); */
20872ac97cdSTom Musta   return d64;
20972ac97cdSTom Musta   } /* decimal64FromNumber */
21072ac97cdSTom Musta 
21172ac97cdSTom Musta /* ------------------------------------------------------------------ */
21272ac97cdSTom Musta /* decimal64ToNumber -- convert decimal64 to decNumber		      */
21372ac97cdSTom Musta /*   d64 is the source decimal64				      */
21472ac97cdSTom Musta /*   dn is the target number, with appropriate space		      */
21572ac97cdSTom Musta /* No error is possible.					      */
21672ac97cdSTom Musta /* ------------------------------------------------------------------ */
21772ac97cdSTom Musta decNumber * decimal64ToNumber(const decimal64 *d64, decNumber *dn) {
21872ac97cdSTom Musta   uInt msd;			   /* coefficient MSD */
21972ac97cdSTom Musta   uInt exp;			   /* exponent top two bits */
22072ac97cdSTom Musta   uInt comb;			   /* combination field */
22172ac97cdSTom Musta   const uInt *pu;		   /* work */
22272ac97cdSTom Musta   Int  need;			   /* .. */
22372ac97cdSTom Musta   uInt sourar[2];		   /* source 64-bit */
22472ac97cdSTom Musta   #define sourhi sourar[1]	   /* name the word with the sign */
22572ac97cdSTom Musta   #define sourlo sourar[0]	   /* and the lower word */
22672ac97cdSTom Musta 
22772ac97cdSTom Musta   /* load source from storage; this is endian */
22872ac97cdSTom Musta   pu=(const uInt *)d64->bytes;	   /* overlay */
22972ac97cdSTom Musta   if (DECLITEND) {
23072ac97cdSTom Musta     sourlo=pu[0];		   /* directly load the low int */
23172ac97cdSTom Musta     sourhi=pu[1];		   /* then the high int */
23272ac97cdSTom Musta     }
23372ac97cdSTom Musta    else {
23472ac97cdSTom Musta     sourhi=pu[0];		   /* directly load the high int */
23572ac97cdSTom Musta     sourlo=pu[1];		   /* then the low int */
23672ac97cdSTom Musta     }
23772ac97cdSTom Musta 
23872ac97cdSTom Musta   comb=(sourhi>>26)&0x1f;	   /* combination field */
23972ac97cdSTom Musta 
24072ac97cdSTom Musta   decNumberZero(dn);		   /* clean number */
24172ac97cdSTom Musta   if (sourhi&0x80000000) dn->bits=DECNEG; /* set sign if negative */
24272ac97cdSTom Musta 
24372ac97cdSTom Musta   msd=COMBMSD[comb];		   /* decode the combination field */
24472ac97cdSTom Musta   exp=COMBEXP[comb];		   /* .. */
24572ac97cdSTom Musta 
24672ac97cdSTom Musta   if (exp==3) {			   /* is a special */
24772ac97cdSTom Musta     if (msd==0) {
24872ac97cdSTom Musta       dn->bits|=DECINF;
24972ac97cdSTom Musta       return dn;		   /* no coefficient needed */
25072ac97cdSTom Musta       }
25172ac97cdSTom Musta     else if (sourhi&0x02000000) dn->bits|=DECSNAN;
25272ac97cdSTom Musta     else dn->bits|=DECNAN;
25372ac97cdSTom Musta     msd=0;			   /* no top digit */
25472ac97cdSTom Musta     }
25572ac97cdSTom Musta    else {			   /* is a finite number */
25672ac97cdSTom Musta     dn->exponent=(exp<<8)+((sourhi>>18)&0xff)-DECIMAL64_Bias; /* unbiased */
25772ac97cdSTom Musta     }
25872ac97cdSTom Musta 
25972ac97cdSTom Musta   /* get the coefficient */
26072ac97cdSTom Musta   sourhi&=0x0003ffff;		   /* clean coefficient continuation */
26172ac97cdSTom Musta   if (msd) {			   /* non-zero msd */
26272ac97cdSTom Musta     sourhi|=msd<<18;		   /* prefix to coefficient */
26372ac97cdSTom Musta     need=6;			   /* process 6 declets */
26472ac97cdSTom Musta     }
26572ac97cdSTom Musta    else { /* msd=0 */
26672ac97cdSTom Musta     if (!sourhi) {		   /* top word 0 */
26772ac97cdSTom Musta       if (!sourlo) return dn;	   /* easy: coefficient is 0 */
26872ac97cdSTom Musta       need=3;			   /* process at least 3 declets */
26972ac97cdSTom Musta       if (sourlo&0xc0000000) need++; /* process 4 declets */
27072ac97cdSTom Musta       /* [could reduce some more, here] */
27172ac97cdSTom Musta       }
27272ac97cdSTom Musta      else {			   /* some bits in top word, msd=0 */
27372ac97cdSTom Musta       need=4;			   /* process at least 4 declets */
27472ac97cdSTom Musta       if (sourhi&0x0003ff00) need++; /* top declet!=0, process 5 */
27572ac97cdSTom Musta       }
27672ac97cdSTom Musta     } /*msd=0 */
27772ac97cdSTom Musta 
27872ac97cdSTom Musta   decDigitsFromDPD(dn, sourar, need);	/* process declets */
27972ac97cdSTom Musta   return dn;
28072ac97cdSTom Musta   } /* decimal64ToNumber */
28172ac97cdSTom Musta 
28272ac97cdSTom Musta 
28372ac97cdSTom Musta /* ------------------------------------------------------------------ */
28472ac97cdSTom Musta /* to-scientific-string -- conversion to numeric string		      */
28572ac97cdSTom Musta /* to-engineering-string -- conversion to numeric string	      */
28672ac97cdSTom Musta /*								      */
28772ac97cdSTom Musta /*   decimal64ToString(d64, string);				      */
28872ac97cdSTom Musta /*   decimal64ToEngString(d64, string);				      */
28972ac97cdSTom Musta /*								      */
29072ac97cdSTom Musta /*  d64 is the decimal64 format number to convert		      */
29172ac97cdSTom Musta /*  string is the string where the result will be laid out	      */
29272ac97cdSTom Musta /*								      */
29372ac97cdSTom Musta /*  string must be at least 24 characters			      */
29472ac97cdSTom Musta /*								      */
29572ac97cdSTom Musta /*  No error is possible, and no status can be set.		      */
29672ac97cdSTom Musta /* ------------------------------------------------------------------ */
29772ac97cdSTom Musta char * decimal64ToEngString(const decimal64 *d64, char *string){
29872ac97cdSTom Musta   decNumber dn;				/* work */
29972ac97cdSTom Musta   decimal64ToNumber(d64, &dn);
30072ac97cdSTom Musta   decNumberToEngString(&dn, string);
30172ac97cdSTom Musta   return string;
30272ac97cdSTom Musta   } /* decimal64ToEngString */
30372ac97cdSTom Musta 
30472ac97cdSTom Musta char * decimal64ToString(const decimal64 *d64, char *string){
30572ac97cdSTom Musta   uInt msd;			   /* coefficient MSD */
30672ac97cdSTom Musta   Int  exp;			   /* exponent top two bits or full */
30772ac97cdSTom Musta   uInt comb;			   /* combination field */
30872ac97cdSTom Musta   char *cstart;			   /* coefficient start */
30972ac97cdSTom Musta   char *c;			   /* output pointer in string */
31072ac97cdSTom Musta   const uInt *pu;		   /* work */
31172ac97cdSTom Musta   char *s, *t;			   /* .. (source, target) */
31272ac97cdSTom Musta   Int  dpd;			   /* .. */
31372ac97cdSTom Musta   Int  pre, e;			   /* .. */
31472ac97cdSTom Musta   const uByte *u;		   /* .. */
31572ac97cdSTom Musta 
31672ac97cdSTom Musta   uInt sourar[2];		   /* source 64-bit */
31772ac97cdSTom Musta   #define sourhi sourar[1]	   /* name the word with the sign */
31872ac97cdSTom Musta   #define sourlo sourar[0]	   /* and the lower word */
31972ac97cdSTom Musta 
32072ac97cdSTom Musta   /* load source from storage; this is endian */
32172ac97cdSTom Musta   pu=(const uInt *)d64->bytes;	   /* overlay */
32272ac97cdSTom Musta   if (DECLITEND) {
32372ac97cdSTom Musta     sourlo=pu[0];		   /* directly load the low int */
32472ac97cdSTom Musta     sourhi=pu[1];		   /* then the high int */
32572ac97cdSTom Musta     }
32672ac97cdSTom Musta    else {
32772ac97cdSTom Musta     sourhi=pu[0];		   /* directly load the high int */
32872ac97cdSTom Musta     sourlo=pu[1];		   /* then the low int */
32972ac97cdSTom Musta     }
33072ac97cdSTom Musta 
33172ac97cdSTom Musta   c=string;			   /* where result will go */
33272ac97cdSTom Musta   if (((Int)sourhi)<0) *c++='-';   /* handle sign */
33372ac97cdSTom Musta 
33472ac97cdSTom Musta   comb=(sourhi>>26)&0x1f;	   /* combination field */
33572ac97cdSTom Musta   msd=COMBMSD[comb];		   /* decode the combination field */
33672ac97cdSTom Musta   exp=COMBEXP[comb];		   /* .. */
33772ac97cdSTom Musta 
33872ac97cdSTom Musta   if (exp==3) {
33972ac97cdSTom Musta     if (msd==0) {		   /* infinity */
34072ac97cdSTom Musta       strcpy(c,	  "Inf");
34172ac97cdSTom Musta       strcpy(c+3, "inity");
34272ac97cdSTom Musta       return string;		   /* easy */
34372ac97cdSTom Musta       }
34472ac97cdSTom Musta     if (sourhi&0x02000000) *c++='s'; /* sNaN */
34572ac97cdSTom Musta     strcpy(c, "NaN");		   /* complete word */
34672ac97cdSTom Musta     c+=3;			   /* step past */
34772ac97cdSTom Musta     if (sourlo==0 && (sourhi&0x0003ffff)==0) return string; /* zero payload */
34872ac97cdSTom Musta     /* otherwise drop through to add integer; set correct exp */
34972ac97cdSTom Musta     exp=0; msd=0;		   /* setup for following code */
35072ac97cdSTom Musta     }
35172ac97cdSTom Musta    else exp=(exp<<8)+((sourhi>>18)&0xff)-DECIMAL64_Bias;
35272ac97cdSTom Musta 
35372ac97cdSTom Musta   /* convert 16 digits of significand to characters */
35472ac97cdSTom Musta   cstart=c;			   /* save start of coefficient */
35572ac97cdSTom Musta   if (msd) *c++='0'+(char)msd;	   /* non-zero most significant digit */
35672ac97cdSTom Musta 
35772ac97cdSTom Musta   /* Now decode the declets.  After extracting each one, it is */
35872ac97cdSTom Musta   /* decoded to binary and then to a 4-char sequence by table lookup; */
35972ac97cdSTom Musta   /* the 4-chars are a 1-char length (significant digits, except 000 */
36072ac97cdSTom Musta   /* has length 0).  This allows us to left-align the first declet */
36172ac97cdSTom Musta   /* with non-zero content, then remaining ones are full 3-char */
36272ac97cdSTom Musta   /* length.  We use fixed-length memcpys because variable-length */
36372ac97cdSTom Musta   /* causes a subroutine call in GCC.  (These are length 4 for speed */
36472ac97cdSTom Musta   /* and are safe because the array has an extra terminator byte.) */
36572ac97cdSTom Musta   #define dpd2char u=&BIN2CHAR[DPD2BIN[dpd]*4];			  \
36672ac97cdSTom Musta 		   if (c!=cstart) {memcpy(c, u+1, 4); c+=3;}	  \
36772ac97cdSTom Musta 		    else if (*u)  {memcpy(c, u+4-*u, 4); c+=*u;}
36872ac97cdSTom Musta 
36972ac97cdSTom Musta   dpd=(sourhi>>8)&0x3ff;		     /* declet 1 */
37072ac97cdSTom Musta   dpd2char;
37172ac97cdSTom Musta   dpd=((sourhi&0xff)<<2) | (sourlo>>30);     /* declet 2 */
37272ac97cdSTom Musta   dpd2char;
37372ac97cdSTom Musta   dpd=(sourlo>>20)&0x3ff;		     /* declet 3 */
37472ac97cdSTom Musta   dpd2char;
37572ac97cdSTom Musta   dpd=(sourlo>>10)&0x3ff;		     /* declet 4 */
37672ac97cdSTom Musta   dpd2char;
37772ac97cdSTom Musta   dpd=(sourlo)&0x3ff;			     /* declet 5 */
37872ac97cdSTom Musta   dpd2char;
37972ac97cdSTom Musta 
38072ac97cdSTom Musta   if (c==cstart) *c++='0';	   /* all zeros -- make 0 */
38172ac97cdSTom Musta 
38272ac97cdSTom Musta   if (exp==0) {			   /* integer or NaN case -- easy */
38372ac97cdSTom Musta     *c='\0';			   /* terminate */
38472ac97cdSTom Musta     return string;
38572ac97cdSTom Musta     }
38672ac97cdSTom Musta 
38772ac97cdSTom Musta   /* non-0 exponent */
38872ac97cdSTom Musta   e=0;				   /* assume no E */
38972ac97cdSTom Musta   pre=c-cstart+exp;
39072ac97cdSTom Musta   /* [here, pre-exp is the digits count (==1 for zero)] */
39172ac97cdSTom Musta   if (exp>0 || pre<-5) {	   /* need exponential form */
39272ac97cdSTom Musta     e=pre-1;			   /* calculate E value */
39372ac97cdSTom Musta     pre=1;			   /* assume one digit before '.' */
39472ac97cdSTom Musta     } /* exponential form */
39572ac97cdSTom Musta 
39672ac97cdSTom Musta   /* modify the coefficient, adding 0s, '.', and E+nn as needed */
39772ac97cdSTom Musta   s=c-1;			   /* source (LSD) */
39872ac97cdSTom Musta   if (pre>0) {			   /* ddd.ddd (plain), perhaps with E */
39972ac97cdSTom Musta     char *dotat=cstart+pre;
40072ac97cdSTom Musta     if (dotat<c) {		   /* if embedded dot needed... */
40172ac97cdSTom Musta       t=c;				/* target */
40272ac97cdSTom Musta       for (; s>=dotat; s--, t--) *t=*s; /* open the gap; leave t at gap */
40372ac97cdSTom Musta       *t='.';				/* insert the dot */
40472ac97cdSTom Musta       c++;				/* length increased by one */
40572ac97cdSTom Musta       }
40672ac97cdSTom Musta 
40772ac97cdSTom Musta     /* finally add the E-part, if needed; it will never be 0, and has */
40872ac97cdSTom Musta     /* a maximum length of 3 digits */
40972ac97cdSTom Musta     if (e!=0) {
41072ac97cdSTom Musta       *c++='E';			   /* starts with E */
41172ac97cdSTom Musta       *c++='+';			   /* assume positive */
41272ac97cdSTom Musta       if (e<0) {
41372ac97cdSTom Musta 	*(c-1)='-';		   /* oops, need '-' */
41472ac97cdSTom Musta 	e=-e;			   /* uInt, please */
41572ac97cdSTom Musta 	}
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     *c='\0';			   /* add terminator */
42172ac97cdSTom Musta     /*printf("res %s\n", string); */
42272ac97cdSTom Musta     return string;
42372ac97cdSTom Musta     } /* pre>0 */
42472ac97cdSTom Musta 
42572ac97cdSTom Musta   /* -5<=pre<=0: here for plain 0.ddd or 0.000ddd forms (can never have E) */
42672ac97cdSTom Musta   t=c+1-pre;
42772ac97cdSTom Musta   *(t+1)='\0';				/* can add terminator now */
42872ac97cdSTom Musta   for (; s>=cstart; s--, t--) *t=*s;	/* shift whole coefficient right */
42972ac97cdSTom Musta   c=cstart;
43072ac97cdSTom Musta   *c++='0';				/* always starts with 0. */
43172ac97cdSTom Musta   *c++='.';
43272ac97cdSTom Musta   for (; pre<0; pre++) *c++='0';	/* add any 0's after '.' */
43372ac97cdSTom Musta   /*printf("res %s\n", string); */
43472ac97cdSTom Musta   return string;
43572ac97cdSTom Musta   } /* decimal64ToString */
43672ac97cdSTom Musta 
43772ac97cdSTom Musta /* ------------------------------------------------------------------ */
43872ac97cdSTom Musta /* to-number -- conversion from numeric string			      */
43972ac97cdSTom Musta /*								      */
44072ac97cdSTom Musta /*   decimal64FromString(result, string, set);			      */
44172ac97cdSTom Musta /*								      */
44272ac97cdSTom Musta /*  result  is the decimal64 format number which gets the result of   */
44372ac97cdSTom Musta /*	    the conversion					      */
44472ac97cdSTom Musta /*  *string is the character string which should contain a valid      */
44572ac97cdSTom Musta /*	    number (which may be a special value)		      */
44672ac97cdSTom Musta /*  set	    is the context					      */
44772ac97cdSTom Musta /*								      */
44872ac97cdSTom Musta /* The context is supplied to this routine is used for error handling */
44972ac97cdSTom Musta /* (setting of status and traps) and for the rounding mode, only.     */
45072ac97cdSTom Musta /* If an error occurs, the result will be a valid decimal64 NaN.      */
45172ac97cdSTom Musta /* ------------------------------------------------------------------ */
45272ac97cdSTom Musta decimal64 * decimal64FromString(decimal64 *result, const char *string,
45372ac97cdSTom Musta 				decContext *set) {
45472ac97cdSTom Musta   decContext dc;			     /* work */
45572ac97cdSTom Musta   decNumber dn;				     /* .. */
45672ac97cdSTom Musta 
45772ac97cdSTom Musta   decContextDefault(&dc, DEC_INIT_DECIMAL64); /* no traps, please */
45872ac97cdSTom Musta   dc.round=set->round;			      /* use supplied rounding */
45972ac97cdSTom Musta 
46072ac97cdSTom Musta   decNumberFromString(&dn, string, &dc);     /* will round if needed */
46172ac97cdSTom Musta 
46272ac97cdSTom Musta   decimal64FromNumber(result, &dn, &dc);
46372ac97cdSTom Musta   if (dc.status!=0) {			     /* something happened */
46472ac97cdSTom Musta     decContextSetStatus(set, dc.status);     /* .. pass it on */
46572ac97cdSTom Musta     }
46672ac97cdSTom Musta   return result;
46772ac97cdSTom Musta   } /* decimal64FromString */
46872ac97cdSTom Musta 
46972ac97cdSTom Musta /* ------------------------------------------------------------------ */
47072ac97cdSTom Musta /* decimal64IsCanonical -- test whether encoding is canonical	      */
47172ac97cdSTom Musta /*   d64 is the source decimal64				      */
47272ac97cdSTom Musta /*   returns 1 if the encoding of d64 is canonical, 0 otherwise	      */
47372ac97cdSTom Musta /* No error is possible.					      */
47472ac97cdSTom Musta /* ------------------------------------------------------------------ */
47572ac97cdSTom Musta uint32_t decimal64IsCanonical(const decimal64 *d64) {
47672ac97cdSTom Musta   decNumber dn;				/* work */
47772ac97cdSTom Musta   decimal64 canon;			/* .. */
47872ac97cdSTom Musta   decContext dc;			/* .. */
47972ac97cdSTom Musta   decContextDefault(&dc, DEC_INIT_DECIMAL64);
48072ac97cdSTom Musta   decimal64ToNumber(d64, &dn);
48172ac97cdSTom Musta   decimal64FromNumber(&canon, &dn, &dc);/* canon will now be canonical */
48272ac97cdSTom Musta   return memcmp(d64, &canon, DECIMAL64_Bytes)==0;
48372ac97cdSTom Musta   } /* decimal64IsCanonical */
48472ac97cdSTom Musta 
48572ac97cdSTom Musta /* ------------------------------------------------------------------ */
48672ac97cdSTom Musta /* decimal64Canonical -- copy an encoding, ensuring it is canonical   */
48772ac97cdSTom Musta /*   d64 is the source decimal64				      */
48872ac97cdSTom Musta /*   result is the target (may be the same decimal64)		      */
48972ac97cdSTom Musta /*   returns result						      */
49072ac97cdSTom Musta /* No error is possible.					      */
49172ac97cdSTom Musta /* ------------------------------------------------------------------ */
49272ac97cdSTom Musta decimal64 * decimal64Canonical(decimal64 *result, const decimal64 *d64) {
49372ac97cdSTom Musta   decNumber dn;				/* work */
49472ac97cdSTom Musta   decContext dc;			/* .. */
49572ac97cdSTom Musta   decContextDefault(&dc, DEC_INIT_DECIMAL64);
49672ac97cdSTom Musta   decimal64ToNumber(d64, &dn);
49772ac97cdSTom Musta   decimal64FromNumber(result, &dn, &dc);/* result will now be canonical */
49872ac97cdSTom Musta   return result;
49972ac97cdSTom Musta   } /* decimal64Canonical */
50072ac97cdSTom Musta 
50172ac97cdSTom Musta #if DECTRACE || DECCHECK
50272ac97cdSTom Musta /* Macros for accessing decimal64 fields.  These assume the
50372ac97cdSTom Musta    argument is a reference (pointer) to the decimal64 structure,
50472ac97cdSTom Musta    and the decimal64 is in network byte order (big-endian) */
50572ac97cdSTom Musta /* Get sign */
50672ac97cdSTom Musta #define decimal64Sign(d)       ((unsigned)(d)->bytes[0]>>7)
50772ac97cdSTom Musta 
50872ac97cdSTom Musta /* Get combination field */
50972ac97cdSTom Musta #define decimal64Comb(d)       (((d)->bytes[0] & 0x7c)>>2)
51072ac97cdSTom Musta 
51172ac97cdSTom Musta /* Get exponent continuation [does not remove bias] */
51272ac97cdSTom Musta #define decimal64ExpCon(d)     ((((d)->bytes[0] & 0x03)<<6)	      \
51372ac97cdSTom Musta 			     | ((unsigned)(d)->bytes[1]>>2))
51472ac97cdSTom Musta 
51572ac97cdSTom Musta /* Set sign [this assumes sign previously 0] */
51672ac97cdSTom Musta #define decimal64SetSign(d, b) {				      \
51772ac97cdSTom Musta   (d)->bytes[0]|=((unsigned)(b)<<7);}
51872ac97cdSTom Musta 
51972ac97cdSTom Musta /* Set exponent continuation [does not apply bias] */
52072ac97cdSTom Musta /* This assumes range has been checked and exponent previously 0; */
52172ac97cdSTom Musta /* type of exponent must be unsigned */
52272ac97cdSTom Musta #define decimal64SetExpCon(d, e) {				      \
52372ac97cdSTom Musta   (d)->bytes[0]|=(uint8_t)((e)>>6);				      \
52472ac97cdSTom Musta   (d)->bytes[1]|=(uint8_t)(((e)&0x3F)<<2);}
52572ac97cdSTom Musta 
52672ac97cdSTom Musta /* ------------------------------------------------------------------ */
52772ac97cdSTom Musta /* decimal64Show -- display a decimal64 in hexadecimal [debug aid]    */
52872ac97cdSTom Musta /*   d64 -- the number to show					      */
52972ac97cdSTom Musta /* ------------------------------------------------------------------ */
53072ac97cdSTom Musta /* Also shows sign/cob/expconfields extracted */
53172ac97cdSTom Musta void decimal64Show(const decimal64 *d64) {
53272ac97cdSTom Musta   char buf[DECIMAL64_Bytes*2+1];
53372ac97cdSTom Musta   Int i, j=0;
53472ac97cdSTom Musta 
53572ac97cdSTom Musta   if (DECLITEND) {
53672ac97cdSTom Musta     for (i=0; i<DECIMAL64_Bytes; i++, j+=2) {
53772ac97cdSTom Musta       sprintf(&buf[j], "%02x", d64->bytes[7-i]);
53872ac97cdSTom Musta       }
53972ac97cdSTom Musta     printf(" D64> %s [S:%d Cb:%02x Ec:%02x] LittleEndian\n", buf,
54072ac97cdSTom Musta 	   d64->bytes[7]>>7, (d64->bytes[7]>>2)&0x1f,
54172ac97cdSTom Musta 	   ((d64->bytes[7]&0x3)<<6)| (d64->bytes[6]>>2));
54272ac97cdSTom Musta     }
54372ac97cdSTom Musta    else { /* big-endian */
54472ac97cdSTom Musta     for (i=0; i<DECIMAL64_Bytes; i++, j+=2) {
54572ac97cdSTom Musta       sprintf(&buf[j], "%02x", d64->bytes[i]);
54672ac97cdSTom Musta       }
54772ac97cdSTom Musta     printf(" D64> %s [S:%d Cb:%02x Ec:%02x] BigEndian\n", buf,
54872ac97cdSTom Musta 	   decimal64Sign(d64), decimal64Comb(d64), decimal64ExpCon(d64));
54972ac97cdSTom Musta     }
55072ac97cdSTom Musta   } /* decimal64Show */
55172ac97cdSTom Musta #endif
55272ac97cdSTom Musta 
55372ac97cdSTom Musta /* ================================================================== */
55472ac97cdSTom Musta /* Shared utility routines and tables				      */
55572ac97cdSTom Musta /* ================================================================== */
55672ac97cdSTom Musta /* define and include the conversion tables to use for shared code */
55772ac97cdSTom Musta #if DECDPUN==3
55872ac97cdSTom Musta   #define DEC_DPD2BIN 1
55972ac97cdSTom Musta #else
56072ac97cdSTom Musta   #define DEC_DPD2BCD 1
56172ac97cdSTom Musta #endif
562*0f2d3732STom Musta #include "libdecnumber/decDPD.h"
56372ac97cdSTom Musta 
56472ac97cdSTom Musta /* The maximum number of decNumberUnits needed for a working copy of */
56572ac97cdSTom Musta /* the units array is the ceiling of digits/DECDPUN, where digits is */
56672ac97cdSTom Musta /* the maximum number of digits in any of the formats for which this */
56772ac97cdSTom Musta /* is used.  decimal128.h must not be included in this module, so, as */
56872ac97cdSTom Musta /* a very special case, that number is defined as a literal here. */
56972ac97cdSTom Musta #define DECMAX754   34
57072ac97cdSTom Musta #define DECMAXUNITS ((DECMAX754+DECDPUN-1)/DECDPUN)
57172ac97cdSTom Musta 
57272ac97cdSTom Musta /* ------------------------------------------------------------------ */
57372ac97cdSTom Musta /* Combination field lookup tables (uInts to save measurable work)    */
57472ac97cdSTom Musta /*								      */
57572ac97cdSTom Musta /*	COMBEXP - 2-bit most-significant-bits of exponent	      */
57672ac97cdSTom Musta /*		  [11 if an Infinity or NaN]			      */
57772ac97cdSTom Musta /*	COMBMSD - 4-bit most-significant-digit			      */
57872ac97cdSTom Musta /*		  [0=Infinity, 1=NaN if COMBEXP=11]		      */
57972ac97cdSTom Musta /*								      */
58072ac97cdSTom Musta /* Both are indexed by the 5-bit combination field (0-31)	      */
58172ac97cdSTom Musta /* ------------------------------------------------------------------ */
58272ac97cdSTom Musta const uInt COMBEXP[32]={0, 0, 0, 0, 0, 0, 0, 0,
58372ac97cdSTom Musta 			1, 1, 1, 1, 1, 1, 1, 1,
58472ac97cdSTom Musta 			2, 2, 2, 2, 2, 2, 2, 2,
58572ac97cdSTom Musta 			0, 0, 1, 1, 2, 2, 3, 3};
58672ac97cdSTom Musta const uInt COMBMSD[32]={0, 1, 2, 3, 4, 5, 6, 7,
58772ac97cdSTom Musta 			0, 1, 2, 3, 4, 5, 6, 7,
58872ac97cdSTom Musta 			0, 1, 2, 3, 4, 5, 6, 7,
58972ac97cdSTom Musta 			8, 9, 8, 9, 8, 9, 0, 1};
59072ac97cdSTom Musta 
59172ac97cdSTom Musta /* ------------------------------------------------------------------ */
59272ac97cdSTom Musta /* decDigitsToDPD -- pack coefficient into DPD form		      */
59372ac97cdSTom Musta /*								      */
59472ac97cdSTom Musta /*   dn	  is the source number (assumed valid, max DECMAX754 digits)  */
59572ac97cdSTom Musta /*   targ is 1, 2, or 4-element uInt array, which the caller must     */
59672ac97cdSTom Musta /*	  have cleared to zeros					      */
59772ac97cdSTom Musta /*   shift is the number of 0 digits to add on the right (normally 0) */
59872ac97cdSTom Musta /*								      */
59972ac97cdSTom Musta /* The coefficient must be known small enough to fit.  The full	      */
60072ac97cdSTom Musta /* coefficient is copied, including the leading 'odd' digit.  This    */
60172ac97cdSTom Musta /* digit is retrieved and packed into the combination field by the    */
60272ac97cdSTom Musta /* caller.							      */
60372ac97cdSTom Musta /*								      */
60472ac97cdSTom Musta /* The target uInts are altered only as necessary to receive the      */
60572ac97cdSTom Musta /* digits of the decNumber.  When more than one uInt is needed, they  */
60672ac97cdSTom Musta /* are filled from left to right (that is, the uInt at offset 0 will  */
60772ac97cdSTom Musta /* end up with the least-significant digits).			      */
60872ac97cdSTom Musta /*								      */
60972ac97cdSTom Musta /* shift is used for 'fold-down' padding.			      */
61072ac97cdSTom Musta /*								      */
61172ac97cdSTom Musta /* No error is possible.					      */
61272ac97cdSTom Musta /* ------------------------------------------------------------------ */
61372ac97cdSTom Musta #if DECDPUN<=4
61472ac97cdSTom Musta /* Constant multipliers for divide-by-power-of five using reciprocal */
61572ac97cdSTom Musta /* multiply, after removing powers of 2 by shifting, and final shift */
61672ac97cdSTom Musta /* of 17 [we only need up to **4] */
61772ac97cdSTom Musta static const uInt multies[]={131073, 26215, 5243, 1049, 210};
61872ac97cdSTom Musta /* QUOT10 -- macro to return the quotient of unit u divided by 10**n */
61972ac97cdSTom Musta #define QUOT10(u, n) ((((uInt)(u)>>(n))*multies[n])>>17)
62072ac97cdSTom Musta #endif
62172ac97cdSTom Musta void decDigitsToDPD(const decNumber *dn, uInt *targ, Int shift) {
62272ac97cdSTom Musta   Int  cut;		      /* work */
62372ac97cdSTom Musta   Int  n;		      /* output bunch counter */
62472ac97cdSTom Musta   Int  digits=dn->digits;     /* digit countdown */
62572ac97cdSTom Musta   uInt dpd;		      /* densely packed decimal value */
62672ac97cdSTom Musta   uInt bin;		      /* binary value 0-999 */
62772ac97cdSTom Musta   uInt *uout=targ;	      /* -> current output uInt */
62872ac97cdSTom Musta   uInt	uoff=0;		      /* -> current output offset [from right] */
62972ac97cdSTom Musta   const Unit *inu=dn->lsu;    /* -> current input unit */
63072ac97cdSTom Musta   Unit	uar[DECMAXUNITS];     /* working copy of units, iff shifted */
63172ac97cdSTom Musta   #if DECDPUN!=3	      /* not fast path */
63272ac97cdSTom Musta     Unit in;		      /* current unit */
63372ac97cdSTom Musta   #endif
63472ac97cdSTom Musta 
63572ac97cdSTom Musta   if (shift!=0) {	      /* shift towards most significant required */
63672ac97cdSTom Musta     /* shift the units array to the left by pad digits and copy */
63772ac97cdSTom Musta     /* [this code is a special case of decShiftToMost, which could */
63872ac97cdSTom Musta     /* be used instead if exposed and the array were copied first] */
63972ac97cdSTom Musta     const Unit *source;			/* .. */
64072ac97cdSTom Musta     Unit  *target, *first;		/* .. */
64172ac97cdSTom Musta     uInt  next=0;			/* work */
64272ac97cdSTom Musta 
64372ac97cdSTom Musta     source=dn->lsu+D2U(digits)-1;	/* where msu comes from */
64472ac97cdSTom Musta     target=uar+D2U(digits)-1+D2U(shift);/* where upper part of first cut goes */
64572ac97cdSTom Musta     cut=DECDPUN-MSUDIGITS(shift);	/* where to slice */
64672ac97cdSTom Musta     if (cut==0) {			/* unit-boundary case */
64772ac97cdSTom Musta       for (; source>=dn->lsu; source--, target--) *target=*source;
64872ac97cdSTom Musta       }
64972ac97cdSTom Musta      else {
65072ac97cdSTom Musta       first=uar+D2U(digits+shift)-1;	/* where msu will end up */
65172ac97cdSTom Musta       for (; source>=dn->lsu; source--, target--) {
65272ac97cdSTom Musta 	/* split the source Unit and accumulate remainder for next */
65372ac97cdSTom Musta 	#if DECDPUN<=4
65472ac97cdSTom Musta 	  uInt quot=QUOT10(*source, cut);
65572ac97cdSTom Musta 	  uInt rem=*source-quot*DECPOWERS[cut];
65672ac97cdSTom Musta 	  next+=quot;
65772ac97cdSTom Musta 	#else
65872ac97cdSTom Musta 	  uInt rem=*source%DECPOWERS[cut];
65972ac97cdSTom Musta 	  next+=*source/DECPOWERS[cut];
66072ac97cdSTom Musta 	#endif
66172ac97cdSTom Musta 	if (target<=first) *target=(Unit)next; /* write to target iff valid */
66272ac97cdSTom Musta 	next=rem*DECPOWERS[DECDPUN-cut];       /* save remainder for next Unit */
66372ac97cdSTom Musta 	}
66472ac97cdSTom Musta       } /* shift-move */
66572ac97cdSTom Musta     /* propagate remainder to one below and clear the rest */
66672ac97cdSTom Musta     for (; target>=uar; target--) {
66772ac97cdSTom Musta       *target=(Unit)next;
66872ac97cdSTom Musta       next=0;
66972ac97cdSTom Musta       }
67072ac97cdSTom Musta     digits+=shift;		   /* add count (shift) of zeros added */
67172ac97cdSTom Musta     inu=uar;			   /* use units in working array */
67272ac97cdSTom Musta     }
67372ac97cdSTom Musta 
67472ac97cdSTom Musta   /* now densely pack the coefficient into DPD declets */
67572ac97cdSTom Musta 
67672ac97cdSTom Musta   #if DECDPUN!=3		   /* not fast path */
67772ac97cdSTom Musta     in=*inu;			   /* current unit */
67872ac97cdSTom Musta     cut=0;			   /* at lowest digit */
67972ac97cdSTom Musta     bin=0;			   /* [keep compiler quiet] */
68072ac97cdSTom Musta   #endif
68172ac97cdSTom Musta 
68272ac97cdSTom Musta   for(n=0; digits>0; n++) {	   /* each output bunch */
68372ac97cdSTom Musta     #if DECDPUN==3		   /* fast path, 3-at-a-time */
68472ac97cdSTom Musta       bin=*inu;			   /* 3 digits ready for convert */
68572ac97cdSTom Musta       digits-=3;		   /* [may go negative] */
68672ac97cdSTom Musta       inu++;			   /* may need another */
68772ac97cdSTom Musta 
68872ac97cdSTom Musta     #else			   /* must collect digit-by-digit */
68972ac97cdSTom Musta       Unit dig;			   /* current digit */
69072ac97cdSTom Musta       Int j;			   /* digit-in-declet count */
69172ac97cdSTom Musta       for (j=0; j<3; j++) {
69272ac97cdSTom Musta 	#if DECDPUN<=4
69372ac97cdSTom Musta 	  Unit temp=(Unit)((uInt)(in*6554)>>16);
69472ac97cdSTom Musta 	  dig=(Unit)(in-X10(temp));
69572ac97cdSTom Musta 	  in=temp;
69672ac97cdSTom Musta 	#else
69772ac97cdSTom Musta 	  dig=in%10;
69872ac97cdSTom Musta 	  in=in/10;
69972ac97cdSTom Musta 	#endif
70072ac97cdSTom Musta 	if (j==0) bin=dig;
70172ac97cdSTom Musta 	 else if (j==1)	 bin+=X10(dig);
70272ac97cdSTom Musta 	 else /* j==2 */ bin+=X100(dig);
70372ac97cdSTom Musta 	digits--;
70472ac97cdSTom Musta 	if (digits==0) break;	   /* [also protects *inu below] */
70572ac97cdSTom Musta 	cut++;
70672ac97cdSTom Musta 	if (cut==DECDPUN) {inu++; in=*inu; cut=0;}
70772ac97cdSTom Musta 	}
70872ac97cdSTom Musta     #endif
70972ac97cdSTom Musta     /* here there are 3 digits in bin, or have used all input digits */
71072ac97cdSTom Musta 
71172ac97cdSTom Musta     dpd=BIN2DPD[bin];
71272ac97cdSTom Musta 
71372ac97cdSTom Musta     /* write declet to uInt array */
71472ac97cdSTom Musta     *uout|=dpd<<uoff;
71572ac97cdSTom Musta     uoff+=10;
71672ac97cdSTom Musta     if (uoff<32) continue;	   /* no uInt boundary cross */
71772ac97cdSTom Musta     uout++;
71872ac97cdSTom Musta     uoff-=32;
71972ac97cdSTom Musta     *uout|=dpd>>(10-uoff);	   /* collect top bits */
72072ac97cdSTom Musta     } /* n declets */
72172ac97cdSTom Musta   return;
72272ac97cdSTom Musta   } /* decDigitsToDPD */
72372ac97cdSTom Musta 
72472ac97cdSTom Musta /* ------------------------------------------------------------------ */
72572ac97cdSTom Musta /* decDigitsFromDPD -- unpack a format's coefficient		      */
72672ac97cdSTom Musta /*								      */
72772ac97cdSTom Musta /*   dn is the target number, with 7, 16, or 34-digit space.	      */
72872ac97cdSTom Musta /*   sour is a 1, 2, or 4-element uInt array containing only declets  */
72972ac97cdSTom Musta /*   declets is the number of (right-aligned) declets in sour to      */
73072ac97cdSTom Musta /*     be processed.  This may be 1 more than the obvious number in   */
73172ac97cdSTom Musta /*     a format, as any top digit is prefixed to the coefficient      */
73272ac97cdSTom Musta /*     continuation field.  It also may be as small as 1, as the      */
73372ac97cdSTom Musta /*     caller may pre-process leading zero declets.		      */
73472ac97cdSTom Musta /*								      */
73572ac97cdSTom Musta /* When doing the 'extra declet' case care is taken to avoid writing  */
73672ac97cdSTom Musta /* extra digits when there are leading zeros, as these could overflow */
73772ac97cdSTom Musta /* the units array when DECDPUN is not 3.			      */
73872ac97cdSTom Musta /*								      */
73972ac97cdSTom Musta /* The target uInts are used only as necessary to process declets     */
74072ac97cdSTom Musta /* declets into the decNumber.	When more than one uInt is needed,    */
74172ac97cdSTom Musta /* they are used from left to right (that is, the uInt at offset 0    */
74272ac97cdSTom Musta /* provides the least-significant digits).			      */
74372ac97cdSTom Musta /*								      */
74472ac97cdSTom Musta /* dn->digits is set, but not the sign or exponent.		      */
74572ac97cdSTom Musta /* No error is possible [the redundant 888 codes are allowed].	      */
74672ac97cdSTom Musta /* ------------------------------------------------------------------ */
74772ac97cdSTom Musta void decDigitsFromDPD(decNumber *dn, const uInt *sour, Int declets) {
74872ac97cdSTom Musta 
74972ac97cdSTom Musta   uInt	dpd;			   /* collector for 10 bits */
75072ac97cdSTom Musta   Int	n;			   /* counter */
75172ac97cdSTom Musta   Unit	*uout=dn->lsu;		   /* -> current output unit */
75272ac97cdSTom Musta   Unit	*last=uout;		   /* will be unit containing msd */
75372ac97cdSTom Musta   const uInt *uin=sour;		   /* -> current input uInt */
75472ac97cdSTom Musta   uInt	uoff=0;			   /* -> current input offset [from right] */
75572ac97cdSTom Musta 
75672ac97cdSTom Musta   #if DECDPUN!=3
75772ac97cdSTom Musta   uInt	bcd;			   /* BCD result */
75872ac97cdSTom Musta   uInt	nibble;			   /* work */
75972ac97cdSTom Musta   Unit	out=0;			   /* accumulator */
76072ac97cdSTom Musta   Int	cut=0;			   /* power of ten in current unit */
76172ac97cdSTom Musta   #endif
76272ac97cdSTom Musta   #if DECDPUN>4
76372ac97cdSTom Musta   uInt const *pow;		   /* work */
76472ac97cdSTom Musta   #endif
76572ac97cdSTom Musta 
76672ac97cdSTom Musta   /* Expand the densely-packed integer, right to left */
76772ac97cdSTom Musta   for (n=declets-1; n>=0; n--) {   /* count down declets of 10 bits */
76872ac97cdSTom Musta     dpd=*uin>>uoff;
76972ac97cdSTom Musta     uoff+=10;
77072ac97cdSTom Musta     if (uoff>32) {		   /* crossed uInt boundary */
77172ac97cdSTom Musta       uin++;
77272ac97cdSTom Musta       uoff-=32;
77372ac97cdSTom Musta       dpd|=*uin<<(10-uoff);	   /* get waiting bits */
77472ac97cdSTom Musta       }
77572ac97cdSTom Musta     dpd&=0x3ff;			   /* clear uninteresting bits */
77672ac97cdSTom Musta 
77772ac97cdSTom Musta   #if DECDPUN==3
77872ac97cdSTom Musta     if (dpd==0) *uout=0;
77972ac97cdSTom Musta      else {
78072ac97cdSTom Musta       *uout=DPD2BIN[dpd];	   /* convert 10 bits to binary 0-999 */
78172ac97cdSTom Musta       last=uout;		   /* record most significant unit */
78272ac97cdSTom Musta       }
78372ac97cdSTom Musta     uout++;
78472ac97cdSTom Musta     } /* n */
78572ac97cdSTom Musta 
78672ac97cdSTom Musta   #else /* DECDPUN!=3 */
78772ac97cdSTom Musta     if (dpd==0) {		   /* fastpath [e.g., leading zeros] */
78872ac97cdSTom Musta       /* write out three 0 digits (nibbles); out may have digit(s) */
78972ac97cdSTom Musta       cut++;
79072ac97cdSTom Musta       if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;}
79172ac97cdSTom Musta       if (n==0) break;		   /* [as below, works even if MSD=0] */
79272ac97cdSTom Musta       cut++;
79372ac97cdSTom Musta       if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;}
79472ac97cdSTom Musta       cut++;
79572ac97cdSTom Musta       if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;}
79672ac97cdSTom Musta       continue;
79772ac97cdSTom Musta       }
79872ac97cdSTom Musta 
79972ac97cdSTom Musta     bcd=DPD2BCD[dpd];		   /* convert 10 bits to 12 bits BCD */
80072ac97cdSTom Musta 
80172ac97cdSTom Musta     /* now accumulate the 3 BCD nibbles into units */
80272ac97cdSTom Musta     nibble=bcd & 0x00f;
80372ac97cdSTom Musta     if (nibble) out=(Unit)(out+nibble*DECPOWERS[cut]);
80472ac97cdSTom Musta     cut++;
80572ac97cdSTom Musta     if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;}
80672ac97cdSTom Musta     bcd>>=4;
80772ac97cdSTom Musta 
80872ac97cdSTom Musta     /* if this is the last declet and the remaining nibbles in bcd */
80972ac97cdSTom Musta     /* are 00 then process no more nibbles, because this could be */
81072ac97cdSTom Musta     /* the 'odd' MSD declet and writing any more Units would then */
81172ac97cdSTom Musta     /* overflow the unit array */
81272ac97cdSTom Musta     if (n==0 && !bcd) break;
81372ac97cdSTom Musta 
81472ac97cdSTom Musta     nibble=bcd & 0x00f;
81572ac97cdSTom Musta     if (nibble) out=(Unit)(out+nibble*DECPOWERS[cut]);
81672ac97cdSTom Musta     cut++;
81772ac97cdSTom Musta     if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;}
81872ac97cdSTom Musta     bcd>>=4;
81972ac97cdSTom Musta 
82072ac97cdSTom Musta     nibble=bcd & 0x00f;
82172ac97cdSTom Musta     if (nibble) out=(Unit)(out+nibble*DECPOWERS[cut]);
82272ac97cdSTom Musta     cut++;
82372ac97cdSTom Musta     if (cut==DECDPUN) {*uout=out; if (out) {last=uout; out=0;} uout++; cut=0;}
82472ac97cdSTom Musta     } /* n */
82572ac97cdSTom Musta   if (cut!=0) {				/* some more left over */
82672ac97cdSTom Musta     *uout=out;				/* write out final unit */
82772ac97cdSTom Musta     if (out) last=uout;			/* and note if non-zero */
82872ac97cdSTom Musta     }
82972ac97cdSTom Musta   #endif
83072ac97cdSTom Musta 
83172ac97cdSTom Musta   /* here, last points to the most significant unit with digits; */
83272ac97cdSTom Musta   /* inspect it to get the final digits count -- this is essentially */
83372ac97cdSTom Musta   /* the same code as decGetDigits in decNumber.c */
83472ac97cdSTom Musta   dn->digits=(last-dn->lsu)*DECDPUN+1;	/* floor of digits, plus */
83572ac97cdSTom Musta 					/* must be at least 1 digit */
83672ac97cdSTom Musta   #if DECDPUN>1
83772ac97cdSTom Musta   if (*last<10) return;			/* common odd digit or 0 */
83872ac97cdSTom Musta   dn->digits++;				/* must be 2 at least */
83972ac97cdSTom Musta   #if DECDPUN>2
84072ac97cdSTom Musta   if (*last<100) return;		/* 10-99 */
84172ac97cdSTom Musta   dn->digits++;				/* must be 3 at least */
84272ac97cdSTom Musta   #if DECDPUN>3
84372ac97cdSTom Musta   if (*last<1000) return;		/* 100-999 */
84472ac97cdSTom Musta   dn->digits++;				/* must be 4 at least */
84572ac97cdSTom Musta   #if DECDPUN>4
84672ac97cdSTom Musta   for (pow=&DECPOWERS[4]; *last>=*pow; pow++) dn->digits++;
84772ac97cdSTom Musta   #endif
84872ac97cdSTom Musta   #endif
84972ac97cdSTom Musta   #endif
85072ac97cdSTom Musta   #endif
85172ac97cdSTom Musta   return;
85272ac97cdSTom Musta   } /*decDigitsFromDPD */
853