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