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