163d1a8abSmrg /* Decimal 128-bit format module for the decNumber C Library.
2*ec02198aSmrg Copyright (C) 2005-2020 Free Software Foundation, Inc.
363d1a8abSmrg Contributed by IBM Corporation. Author Mike Cowlishaw.
463d1a8abSmrg
563d1a8abSmrg This file is part of GCC.
663d1a8abSmrg
763d1a8abSmrg GCC is free software; you can redistribute it and/or modify it under
863d1a8abSmrg the terms of the GNU General Public License as published by the Free
963d1a8abSmrg Software Foundation; either version 3, or (at your option) any later
1063d1a8abSmrg version.
1163d1a8abSmrg
1263d1a8abSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1363d1a8abSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
1463d1a8abSmrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1563d1a8abSmrg for more details.
1663d1a8abSmrg
1763d1a8abSmrg Under Section 7 of GPL version 3, you are granted additional
1863d1a8abSmrg permissions described in the GCC Runtime Library Exception, version
1963d1a8abSmrg 3.1, as published by the Free Software Foundation.
2063d1a8abSmrg
2163d1a8abSmrg You should have received a copy of the GNU General Public License and
2263d1a8abSmrg a copy of the GCC Runtime Library Exception along with this program;
2363d1a8abSmrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
2463d1a8abSmrg <http://www.gnu.org/licenses/>. */
2563d1a8abSmrg
2663d1a8abSmrg /* ------------------------------------------------------------------ */
2763d1a8abSmrg /* Decimal 128-bit format module */
2863d1a8abSmrg /* ------------------------------------------------------------------ */
2963d1a8abSmrg /* This module comprises the routines for decimal128 format numbers. */
3063d1a8abSmrg /* Conversions are supplied to and from decNumber and String. */
3163d1a8abSmrg /* */
3263d1a8abSmrg /* This is used when decNumber provides operations, either for all */
3363d1a8abSmrg /* operations or as a proxy between decNumber and decSingle. */
3463d1a8abSmrg /* */
3563d1a8abSmrg /* Error handling is the same as decNumber (qv.). */
3663d1a8abSmrg /* ------------------------------------------------------------------ */
3763d1a8abSmrg #include <string.h> /* [for memset/memcpy] */
3863d1a8abSmrg #include <stdio.h> /* [for printf] */
3963d1a8abSmrg
4063d1a8abSmrg #include "dconfig.h" /* GCC definitions */
4163d1a8abSmrg #define DECNUMDIGITS 34 /* make decNumbers with space for 34 */
4263d1a8abSmrg #include "decNumber.h" /* base number library */
4363d1a8abSmrg #include "decNumberLocal.h" /* decNumber local types, etc. */
4463d1a8abSmrg #include "decimal128.h" /* our primary include */
4563d1a8abSmrg
4663d1a8abSmrg /* Utility routines and tables [in decimal64.c] */
4763d1a8abSmrg extern const uInt COMBEXP[32], COMBMSD[32];
4863d1a8abSmrg extern const uShort DPD2BIN[1024];
4963d1a8abSmrg extern const uShort BIN2DPD[1000]; /* [not used] */
5063d1a8abSmrg extern const uByte BIN2CHAR[4001];
5163d1a8abSmrg
5263d1a8abSmrg extern void decDigitsFromDPD(decNumber *, const uInt *, Int);
5363d1a8abSmrg extern void decDigitsToDPD(const decNumber *, uInt *, Int);
5463d1a8abSmrg
5563d1a8abSmrg #if DECTRACE || DECCHECK
5663d1a8abSmrg void decimal128Show(const decimal128 *); /* for debug */
5763d1a8abSmrg extern void decNumberShow(const decNumber *); /* .. */
5863d1a8abSmrg #endif
5963d1a8abSmrg
6063d1a8abSmrg /* Useful macro */
6163d1a8abSmrg /* Clear a structure (e.g., a decNumber) */
6263d1a8abSmrg #define DEC_clear(d) memset(d, 0, sizeof(*d))
6363d1a8abSmrg
6463d1a8abSmrg /* ------------------------------------------------------------------ */
6563d1a8abSmrg /* decimal128FromNumber -- convert decNumber to decimal128 */
6663d1a8abSmrg /* */
6763d1a8abSmrg /* ds is the target decimal128 */
6863d1a8abSmrg /* dn is the source number (assumed valid) */
6963d1a8abSmrg /* set is the context, used only for reporting errors */
7063d1a8abSmrg /* */
7163d1a8abSmrg /* The set argument is used only for status reporting and for the */
7263d1a8abSmrg /* rounding mode (used if the coefficient is more than DECIMAL128_Pmax*/
7363d1a8abSmrg /* digits or an overflow is detected). If the exponent is out of the */
7463d1a8abSmrg /* valid range then Overflow or Underflow will be raised. */
7563d1a8abSmrg /* After Underflow a subnormal result is possible. */
7663d1a8abSmrg /* */
7763d1a8abSmrg /* DEC_Clamped is set if the number has to be 'folded down' to fit, */
7863d1a8abSmrg /* by reducing its exponent and multiplying the coefficient by a */
7963d1a8abSmrg /* power of ten, or if the exponent on a zero had to be clamped. */
8063d1a8abSmrg /* ------------------------------------------------------------------ */
decimal128FromNumber(decimal128 * d128,const decNumber * dn,decContext * set)8163d1a8abSmrg decimal128 * decimal128FromNumber(decimal128 *d128, const decNumber *dn,
8263d1a8abSmrg decContext *set) {
8363d1a8abSmrg uInt status=0; /* status accumulator */
8463d1a8abSmrg Int ae; /* adjusted exponent */
8563d1a8abSmrg decNumber dw; /* work */
8663d1a8abSmrg decContext dc; /* .. */
8763d1a8abSmrg uInt comb, exp; /* .. */
8863d1a8abSmrg uInt uiwork; /* for macros */
8963d1a8abSmrg uInt targar[4]={0,0,0,0}; /* target 128-bit */
9063d1a8abSmrg #define targhi targar[3] /* name the word with the sign */
9163d1a8abSmrg #define targmh targar[2] /* name the words */
9263d1a8abSmrg #define targml targar[1] /* .. */
9363d1a8abSmrg #define targlo targar[0] /* .. */
9463d1a8abSmrg
9563d1a8abSmrg /* If the number has too many digits, or the exponent could be */
9663d1a8abSmrg /* out of range then reduce the number under the appropriate */
9763d1a8abSmrg /* constraints. This could push the number to Infinity or zero, */
9863d1a8abSmrg /* so this check and rounding must be done before generating the */
9963d1a8abSmrg /* decimal128] */
10063d1a8abSmrg ae=dn->exponent+dn->digits-1; /* [0 if special] */
10163d1a8abSmrg if (dn->digits>DECIMAL128_Pmax /* too many digits */
10263d1a8abSmrg || ae>DECIMAL128_Emax /* likely overflow */
10363d1a8abSmrg || ae<DECIMAL128_Emin) { /* likely underflow */
10463d1a8abSmrg decContextDefault(&dc, DEC_INIT_DECIMAL128); /* [no traps] */
10563d1a8abSmrg dc.round=set->round; /* use supplied rounding */
10663d1a8abSmrg decNumberPlus(&dw, dn, &dc); /* (round and check) */
10763d1a8abSmrg /* [this changes -0 to 0, so enforce the sign...] */
10863d1a8abSmrg dw.bits|=dn->bits&DECNEG;
10963d1a8abSmrg status=dc.status; /* save status */
11063d1a8abSmrg dn=&dw; /* use the work number */
11163d1a8abSmrg } /* maybe out of range */
11263d1a8abSmrg
11363d1a8abSmrg if (dn->bits&DECSPECIAL) { /* a special value */
11463d1a8abSmrg if (dn->bits&DECINF) targhi=DECIMAL_Inf<<24;
11563d1a8abSmrg else { /* sNaN or qNaN */
11663d1a8abSmrg if ((*dn->lsu!=0 || dn->digits>1) /* non-zero coefficient */
11763d1a8abSmrg && (dn->digits<DECIMAL128_Pmax)) { /* coefficient fits */
11863d1a8abSmrg decDigitsToDPD(dn, targar, 0);
11963d1a8abSmrg }
12063d1a8abSmrg if (dn->bits&DECNAN) targhi|=DECIMAL_NaN<<24;
12163d1a8abSmrg else targhi|=DECIMAL_sNaN<<24;
12263d1a8abSmrg } /* a NaN */
12363d1a8abSmrg } /* special */
12463d1a8abSmrg
12563d1a8abSmrg else { /* is finite */
12663d1a8abSmrg if (decNumberIsZero(dn)) { /* is a zero */
12763d1a8abSmrg /* set and clamp exponent */
12863d1a8abSmrg if (dn->exponent<-DECIMAL128_Bias) {
12963d1a8abSmrg exp=0; /* low clamp */
13063d1a8abSmrg status|=DEC_Clamped;
13163d1a8abSmrg }
13263d1a8abSmrg else {
13363d1a8abSmrg exp=dn->exponent+DECIMAL128_Bias; /* bias exponent */
13463d1a8abSmrg if (exp>DECIMAL128_Ehigh) { /* top clamp */
13563d1a8abSmrg exp=DECIMAL128_Ehigh;
13663d1a8abSmrg status|=DEC_Clamped;
13763d1a8abSmrg }
13863d1a8abSmrg }
13963d1a8abSmrg comb=(exp>>9) & 0x18; /* msd=0, exp top 2 bits .. */
14063d1a8abSmrg }
14163d1a8abSmrg else { /* non-zero finite number */
14263d1a8abSmrg uInt msd; /* work */
14363d1a8abSmrg Int pad=0; /* coefficient pad digits */
14463d1a8abSmrg
14563d1a8abSmrg /* the dn is known to fit, but it may need to be padded */
14663d1a8abSmrg exp=(uInt)(dn->exponent+DECIMAL128_Bias); /* bias exponent */
14763d1a8abSmrg if (exp>DECIMAL128_Ehigh) { /* fold-down case */
14863d1a8abSmrg pad=exp-DECIMAL128_Ehigh;
14963d1a8abSmrg exp=DECIMAL128_Ehigh; /* [to maximum] */
15063d1a8abSmrg status|=DEC_Clamped;
15163d1a8abSmrg }
15263d1a8abSmrg
15363d1a8abSmrg /* [fastpath for common case is not a win, here] */
15463d1a8abSmrg decDigitsToDPD(dn, targar, pad);
15563d1a8abSmrg /* save and clear the top digit */
15663d1a8abSmrg msd=targhi>>14;
15763d1a8abSmrg targhi&=0x00003fff;
15863d1a8abSmrg
15963d1a8abSmrg /* create the combination field */
16063d1a8abSmrg if (msd>=8) comb=0x18 | ((exp>>11) & 0x06) | (msd & 0x01);
16163d1a8abSmrg else comb=((exp>>9) & 0x18) | msd;
16263d1a8abSmrg }
16363d1a8abSmrg targhi|=comb<<26; /* add combination field .. */
16463d1a8abSmrg targhi|=(exp&0xfff)<<14; /* .. and exponent continuation */
16563d1a8abSmrg } /* finite */
16663d1a8abSmrg
16763d1a8abSmrg if (dn->bits&DECNEG) targhi|=0x80000000; /* add sign bit */
16863d1a8abSmrg
16963d1a8abSmrg /* now write to storage; this is endian */
17063d1a8abSmrg if (DECLITEND) {
17163d1a8abSmrg /* lo -> hi */
17263d1a8abSmrg UBFROMUI(d128->bytes, targlo);
17363d1a8abSmrg UBFROMUI(d128->bytes+4, targml);
17463d1a8abSmrg UBFROMUI(d128->bytes+8, targmh);
17563d1a8abSmrg UBFROMUI(d128->bytes+12, targhi);
17663d1a8abSmrg }
17763d1a8abSmrg else {
17863d1a8abSmrg /* hi -> lo */
17963d1a8abSmrg UBFROMUI(d128->bytes, targhi);
18063d1a8abSmrg UBFROMUI(d128->bytes+4, targmh);
18163d1a8abSmrg UBFROMUI(d128->bytes+8, targml);
18263d1a8abSmrg UBFROMUI(d128->bytes+12, targlo);
18363d1a8abSmrg }
18463d1a8abSmrg
18563d1a8abSmrg if (status!=0) decContextSetStatus(set, status); /* pass on status */
18663d1a8abSmrg /* decimal128Show(d128); */
18763d1a8abSmrg return d128;
18863d1a8abSmrg } /* decimal128FromNumber */
18963d1a8abSmrg
19063d1a8abSmrg /* ------------------------------------------------------------------ */
19163d1a8abSmrg /* decimal128ToNumber -- convert decimal128 to decNumber */
19263d1a8abSmrg /* d128 is the source decimal128 */
19363d1a8abSmrg /* dn is the target number, with appropriate space */
19463d1a8abSmrg /* No error is possible. */
19563d1a8abSmrg /* ------------------------------------------------------------------ */
decimal128ToNumber(const decimal128 * d128,decNumber * dn)19663d1a8abSmrg decNumber * decimal128ToNumber(const decimal128 *d128, decNumber *dn) {
19763d1a8abSmrg uInt msd; /* coefficient MSD */
19863d1a8abSmrg uInt exp; /* exponent top two bits */
19963d1a8abSmrg uInt comb; /* combination field */
20063d1a8abSmrg Int need; /* work */
20163d1a8abSmrg uInt uiwork; /* for macros */
20263d1a8abSmrg uInt sourar[4]; /* source 128-bit */
20363d1a8abSmrg #define sourhi sourar[3] /* name the word with the sign */
20463d1a8abSmrg #define sourmh sourar[2] /* and the mid-high word */
20563d1a8abSmrg #define sourml sourar[1] /* and the mod-low word */
20663d1a8abSmrg #define sourlo sourar[0] /* and the lowest word */
20763d1a8abSmrg
20863d1a8abSmrg /* load source from storage; this is endian */
20963d1a8abSmrg if (DECLITEND) {
21063d1a8abSmrg sourlo=UBTOUI(d128->bytes ); /* directly load the low int */
21163d1a8abSmrg sourml=UBTOUI(d128->bytes+4 ); /* then the mid-low */
21263d1a8abSmrg sourmh=UBTOUI(d128->bytes+8 ); /* then the mid-high */
21363d1a8abSmrg sourhi=UBTOUI(d128->bytes+12); /* then the high int */
21463d1a8abSmrg }
21563d1a8abSmrg else {
21663d1a8abSmrg sourhi=UBTOUI(d128->bytes ); /* directly load the high int */
21763d1a8abSmrg sourmh=UBTOUI(d128->bytes+4 ); /* then the mid-high */
21863d1a8abSmrg sourml=UBTOUI(d128->bytes+8 ); /* then the mid-low */
21963d1a8abSmrg sourlo=UBTOUI(d128->bytes+12); /* then the low int */
22063d1a8abSmrg }
22163d1a8abSmrg
22263d1a8abSmrg comb=(sourhi>>26)&0x1f; /* combination field */
22363d1a8abSmrg
22463d1a8abSmrg decNumberZero(dn); /* clean number */
22563d1a8abSmrg if (sourhi&0x80000000) dn->bits=DECNEG; /* set sign if negative */
22663d1a8abSmrg
22763d1a8abSmrg msd=COMBMSD[comb]; /* decode the combination field */
22863d1a8abSmrg exp=COMBEXP[comb]; /* .. */
22963d1a8abSmrg
23063d1a8abSmrg if (exp==3) { /* is a special */
23163d1a8abSmrg if (msd==0) {
23263d1a8abSmrg dn->bits|=DECINF;
23363d1a8abSmrg return dn; /* no coefficient needed */
23463d1a8abSmrg }
23563d1a8abSmrg else if (sourhi&0x02000000) dn->bits|=DECSNAN;
23663d1a8abSmrg else dn->bits|=DECNAN;
23763d1a8abSmrg msd=0; /* no top digit */
23863d1a8abSmrg }
23963d1a8abSmrg else { /* is a finite number */
24063d1a8abSmrg dn->exponent=(exp<<12)+((sourhi>>14)&0xfff)-DECIMAL128_Bias; /* unbiased */
24163d1a8abSmrg }
24263d1a8abSmrg
24363d1a8abSmrg /* get the coefficient */
24463d1a8abSmrg sourhi&=0x00003fff; /* clean coefficient continuation */
24563d1a8abSmrg if (msd) { /* non-zero msd */
24663d1a8abSmrg sourhi|=msd<<14; /* prefix to coefficient */
24763d1a8abSmrg need=12; /* process 12 declets */
24863d1a8abSmrg }
24963d1a8abSmrg else { /* msd=0 */
25063d1a8abSmrg if (sourhi) need=11; /* declets to process */
25163d1a8abSmrg else if (sourmh) need=10;
25263d1a8abSmrg else if (sourml) need=7;
25363d1a8abSmrg else if (sourlo) need=4;
25463d1a8abSmrg else return dn; /* easy: coefficient is 0 */
25563d1a8abSmrg } /*msd=0 */
25663d1a8abSmrg
25763d1a8abSmrg decDigitsFromDPD(dn, sourar, need); /* process declets */
25863d1a8abSmrg /* decNumberShow(dn); */
25963d1a8abSmrg return dn;
26063d1a8abSmrg } /* decimal128ToNumber */
26163d1a8abSmrg
26263d1a8abSmrg /* ------------------------------------------------------------------ */
26363d1a8abSmrg /* to-scientific-string -- conversion to numeric string */
26463d1a8abSmrg /* to-engineering-string -- conversion to numeric string */
26563d1a8abSmrg /* */
26663d1a8abSmrg /* decimal128ToString(d128, string); */
26763d1a8abSmrg /* decimal128ToEngString(d128, string); */
26863d1a8abSmrg /* */
26963d1a8abSmrg /* d128 is the decimal128 format number to convert */
27063d1a8abSmrg /* string is the string where the result will be laid out */
27163d1a8abSmrg /* */
27263d1a8abSmrg /* string must be at least 24 characters */
27363d1a8abSmrg /* */
27463d1a8abSmrg /* No error is possible, and no status can be set. */
27563d1a8abSmrg /* ------------------------------------------------------------------ */
decimal128ToEngString(const decimal128 * d128,char * string)27663d1a8abSmrg char * decimal128ToEngString(const decimal128 *d128, char *string){
27763d1a8abSmrg decNumber dn; /* work */
27863d1a8abSmrg decimal128ToNumber(d128, &dn);
27963d1a8abSmrg decNumberToEngString(&dn, string);
28063d1a8abSmrg return string;
28163d1a8abSmrg } /* decimal128ToEngString */
28263d1a8abSmrg
decimal128ToString(const decimal128 * d128,char * string)28363d1a8abSmrg char * decimal128ToString(const decimal128 *d128, char *string){
28463d1a8abSmrg uInt msd; /* coefficient MSD */
28563d1a8abSmrg Int exp; /* exponent top two bits or full */
28663d1a8abSmrg uInt comb; /* combination field */
28763d1a8abSmrg char *cstart; /* coefficient start */
28863d1a8abSmrg char *c; /* output pointer in string */
28963d1a8abSmrg const uByte *u; /* work */
29063d1a8abSmrg char *s, *t; /* .. (source, target) */
29163d1a8abSmrg Int dpd; /* .. */
29263d1a8abSmrg Int pre, e; /* .. */
29363d1a8abSmrg uInt uiwork; /* for macros */
29463d1a8abSmrg
29563d1a8abSmrg uInt sourar[4]; /* source 128-bit */
29663d1a8abSmrg #define sourhi sourar[3] /* name the word with the sign */
29763d1a8abSmrg #define sourmh sourar[2] /* and the mid-high word */
29863d1a8abSmrg #define sourml sourar[1] /* and the mod-low word */
29963d1a8abSmrg #define sourlo sourar[0] /* and the lowest word */
30063d1a8abSmrg
30163d1a8abSmrg /* load source from storage; this is endian */
30263d1a8abSmrg if (DECLITEND) {
30363d1a8abSmrg sourlo=UBTOUI(d128->bytes ); /* directly load the low int */
30463d1a8abSmrg sourml=UBTOUI(d128->bytes+4 ); /* then the mid-low */
30563d1a8abSmrg sourmh=UBTOUI(d128->bytes+8 ); /* then the mid-high */
30663d1a8abSmrg sourhi=UBTOUI(d128->bytes+12); /* then the high int */
30763d1a8abSmrg }
30863d1a8abSmrg else {
30963d1a8abSmrg sourhi=UBTOUI(d128->bytes ); /* directly load the high int */
31063d1a8abSmrg sourmh=UBTOUI(d128->bytes+4 ); /* then the mid-high */
31163d1a8abSmrg sourml=UBTOUI(d128->bytes+8 ); /* then the mid-low */
31263d1a8abSmrg sourlo=UBTOUI(d128->bytes+12); /* then the low int */
31363d1a8abSmrg }
31463d1a8abSmrg
31563d1a8abSmrg c=string; /* where result will go */
31663d1a8abSmrg if (((Int)sourhi)<0) *c++='-'; /* handle sign */
31763d1a8abSmrg
31863d1a8abSmrg comb=(sourhi>>26)&0x1f; /* combination field */
31963d1a8abSmrg msd=COMBMSD[comb]; /* decode the combination field */
32063d1a8abSmrg exp=COMBEXP[comb]; /* .. */
32163d1a8abSmrg
32263d1a8abSmrg if (exp==3) {
32363d1a8abSmrg if (msd==0) { /* infinity */
32463d1a8abSmrg strcpy(c, "Inf");
32563d1a8abSmrg strcpy(c+3, "inity");
32663d1a8abSmrg return string; /* easy */
32763d1a8abSmrg }
32863d1a8abSmrg if (sourhi&0x02000000) *c++='s'; /* sNaN */
32963d1a8abSmrg strcpy(c, "NaN"); /* complete word */
33063d1a8abSmrg c+=3; /* step past */
33163d1a8abSmrg if (sourlo==0 && sourml==0 && sourmh==0
33263d1a8abSmrg && (sourhi&0x0003ffff)==0) return string; /* zero payload */
33363d1a8abSmrg /* otherwise drop through to add integer; set correct exp */
33463d1a8abSmrg exp=0; msd=0; /* setup for following code */
33563d1a8abSmrg }
33663d1a8abSmrg else exp=(exp<<12)+((sourhi>>14)&0xfff)-DECIMAL128_Bias; /* unbiased */
33763d1a8abSmrg
33863d1a8abSmrg /* convert 34 digits of significand to characters */
33963d1a8abSmrg cstart=c; /* save start of coefficient */
34063d1a8abSmrg if (msd) *c++='0'+(char)msd; /* non-zero most significant digit */
34163d1a8abSmrg
34263d1a8abSmrg /* Now decode the declets. After extracting each one, it is */
34363d1a8abSmrg /* decoded to binary and then to a 4-char sequence by table lookup; */
34463d1a8abSmrg /* the 4-chars are a 1-char length (significant digits, except 000 */
34563d1a8abSmrg /* has length 0). This allows us to left-align the first declet */
34663d1a8abSmrg /* with non-zero content, then remaining ones are full 3-char */
34763d1a8abSmrg /* length. We use fixed-length memcpys because variable-length */
34863d1a8abSmrg /* causes a subroutine call in GCC. (These are length 4 for speed */
34963d1a8abSmrg /* and are safe because the array has an extra terminator byte.) */
35063d1a8abSmrg #define dpd2char u=&BIN2CHAR[DPD2BIN[dpd]*4]; \
35163d1a8abSmrg if (c!=cstart) {memcpy(c, u+1, 4); c+=3;} \
35263d1a8abSmrg else if (*u) {memcpy(c, u+4-*u, 4); c+=*u;}
35363d1a8abSmrg dpd=(sourhi>>4)&0x3ff; /* declet 1 */
35463d1a8abSmrg dpd2char;
35563d1a8abSmrg dpd=((sourhi&0xf)<<6) | (sourmh>>26); /* declet 2 */
35663d1a8abSmrg dpd2char;
35763d1a8abSmrg dpd=(sourmh>>16)&0x3ff; /* declet 3 */
35863d1a8abSmrg dpd2char;
35963d1a8abSmrg dpd=(sourmh>>6)&0x3ff; /* declet 4 */
36063d1a8abSmrg dpd2char;
36163d1a8abSmrg dpd=((sourmh&0x3f)<<4) | (sourml>>28); /* declet 5 */
36263d1a8abSmrg dpd2char;
36363d1a8abSmrg dpd=(sourml>>18)&0x3ff; /* declet 6 */
36463d1a8abSmrg dpd2char;
36563d1a8abSmrg dpd=(sourml>>8)&0x3ff; /* declet 7 */
36663d1a8abSmrg dpd2char;
36763d1a8abSmrg dpd=((sourml&0xff)<<2) | (sourlo>>30); /* declet 8 */
36863d1a8abSmrg dpd2char;
36963d1a8abSmrg dpd=(sourlo>>20)&0x3ff; /* declet 9 */
37063d1a8abSmrg dpd2char;
37163d1a8abSmrg dpd=(sourlo>>10)&0x3ff; /* declet 10 */
37263d1a8abSmrg dpd2char;
37363d1a8abSmrg dpd=(sourlo)&0x3ff; /* declet 11 */
37463d1a8abSmrg dpd2char;
37563d1a8abSmrg
37663d1a8abSmrg if (c==cstart) *c++='0'; /* all zeros -- make 0 */
37763d1a8abSmrg
37863d1a8abSmrg if (exp==0) { /* integer or NaN case -- easy */
37963d1a8abSmrg *c='\0'; /* terminate */
38063d1a8abSmrg return string;
38163d1a8abSmrg }
38263d1a8abSmrg
38363d1a8abSmrg /* non-0 exponent */
38463d1a8abSmrg e=0; /* assume no E */
38563d1a8abSmrg pre=c-cstart+exp;
38663d1a8abSmrg /* [here, pre-exp is the digits count (==1 for zero)] */
38763d1a8abSmrg if (exp>0 || pre<-5) { /* need exponential form */
38863d1a8abSmrg e=pre-1; /* calculate E value */
38963d1a8abSmrg pre=1; /* assume one digit before '.' */
39063d1a8abSmrg } /* exponential form */
39163d1a8abSmrg
39263d1a8abSmrg /* modify the coefficient, adding 0s, '.', and E+nn as needed */
39363d1a8abSmrg s=c-1; /* source (LSD) */
39463d1a8abSmrg if (pre>0) { /* ddd.ddd (plain), perhaps with E */
39563d1a8abSmrg char *dotat=cstart+pre;
39663d1a8abSmrg if (dotat<c) { /* if embedded dot needed... */
39763d1a8abSmrg t=c; /* target */
39863d1a8abSmrg for (; s>=dotat; s--, t--) *t=*s; /* open the gap; leave t at gap */
39963d1a8abSmrg *t='.'; /* insert the dot */
40063d1a8abSmrg c++; /* length increased by one */
40163d1a8abSmrg }
40263d1a8abSmrg
40363d1a8abSmrg /* finally add the E-part, if needed; it will never be 0, and has */
40463d1a8abSmrg /* a maximum length of 4 digits */
40563d1a8abSmrg if (e!=0) {
40663d1a8abSmrg *c++='E'; /* starts with E */
40763d1a8abSmrg *c++='+'; /* assume positive */
40863d1a8abSmrg if (e<0) {
40963d1a8abSmrg *(c-1)='-'; /* oops, need '-' */
41063d1a8abSmrg e=-e; /* uInt, please */
41163d1a8abSmrg }
41263d1a8abSmrg if (e<1000) { /* 3 (or fewer) digits case */
41363d1a8abSmrg u=&BIN2CHAR[e*4]; /* -> length byte */
41463d1a8abSmrg memcpy(c, u+4-*u, 4); /* copy fixed 4 characters [is safe] */
41563d1a8abSmrg c+=*u; /* bump pointer appropriately */
41663d1a8abSmrg }
41763d1a8abSmrg else { /* 4-digits */
41863d1a8abSmrg Int thou=((e>>3)*1049)>>17; /* e/1000 */
41963d1a8abSmrg Int rem=e-(1000*thou); /* e%1000 */
42063d1a8abSmrg *c++='0'+(char)thou;
42163d1a8abSmrg u=&BIN2CHAR[rem*4]; /* -> length byte */
42263d1a8abSmrg memcpy(c, u+1, 4); /* copy fixed 3+1 characters [is safe] */
42363d1a8abSmrg c+=3; /* bump pointer, always 3 digits */
42463d1a8abSmrg }
42563d1a8abSmrg }
42663d1a8abSmrg *c='\0'; /* add terminator */
42763d1a8abSmrg /*printf("res %s\n", string); */
42863d1a8abSmrg return string;
42963d1a8abSmrg } /* pre>0 */
43063d1a8abSmrg
43163d1a8abSmrg /* -5<=pre<=0: here for plain 0.ddd or 0.000ddd forms (can never have E) */
43263d1a8abSmrg t=c+1-pre;
43363d1a8abSmrg *(t+1)='\0'; /* can add terminator now */
43463d1a8abSmrg for (; s>=cstart; s--, t--) *t=*s; /* shift whole coefficient right */
43563d1a8abSmrg c=cstart;
43663d1a8abSmrg *c++='0'; /* always starts with 0. */
43763d1a8abSmrg *c++='.';
43863d1a8abSmrg for (; pre<0; pre++) *c++='0'; /* add any 0's after '.' */
43963d1a8abSmrg /*printf("res %s\n", string); */
44063d1a8abSmrg return string;
44163d1a8abSmrg } /* decimal128ToString */
44263d1a8abSmrg
44363d1a8abSmrg /* ------------------------------------------------------------------ */
44463d1a8abSmrg /* to-number -- conversion from numeric string */
44563d1a8abSmrg /* */
44663d1a8abSmrg /* decimal128FromString(result, string, set); */
44763d1a8abSmrg /* */
44863d1a8abSmrg /* result is the decimal128 format number which gets the result of */
44963d1a8abSmrg /* the conversion */
45063d1a8abSmrg /* *string is the character string which should contain a valid */
45163d1a8abSmrg /* number (which may be a special value) */
45263d1a8abSmrg /* set is the context */
45363d1a8abSmrg /* */
45463d1a8abSmrg /* The context is supplied to this routine is used for error handling */
45563d1a8abSmrg /* (setting of status and traps) and for the rounding mode, only. */
45663d1a8abSmrg /* If an error occurs, the result will be a valid decimal128 NaN. */
45763d1a8abSmrg /* ------------------------------------------------------------------ */
decimal128FromString(decimal128 * result,const char * string,decContext * set)45863d1a8abSmrg decimal128 * decimal128FromString(decimal128 *result, const char *string,
45963d1a8abSmrg decContext *set) {
46063d1a8abSmrg decContext dc; /* work */
46163d1a8abSmrg decNumber dn; /* .. */
46263d1a8abSmrg
46363d1a8abSmrg decContextDefault(&dc, DEC_INIT_DECIMAL128); /* no traps, please */
46463d1a8abSmrg dc.round=set->round; /* use supplied rounding */
46563d1a8abSmrg
46663d1a8abSmrg decNumberFromString(&dn, string, &dc); /* will round if needed */
46763d1a8abSmrg decimal128FromNumber(result, &dn, &dc);
46863d1a8abSmrg if (dc.status!=0) { /* something happened */
46963d1a8abSmrg decContextSetStatus(set, dc.status); /* .. pass it on */
47063d1a8abSmrg }
47163d1a8abSmrg return result;
47263d1a8abSmrg } /* decimal128FromString */
47363d1a8abSmrg
47463d1a8abSmrg /* ------------------------------------------------------------------ */
47563d1a8abSmrg /* decimal128IsCanonical -- test whether encoding is canonical */
47663d1a8abSmrg /* d128 is the source decimal128 */
47763d1a8abSmrg /* returns 1 if the encoding of d128 is canonical, 0 otherwise */
47863d1a8abSmrg /* No error is possible. */
47963d1a8abSmrg /* ------------------------------------------------------------------ */
decimal128IsCanonical(const decimal128 * d128)48063d1a8abSmrg uInt decimal128IsCanonical(const decimal128 *d128) {
48163d1a8abSmrg decNumber dn; /* work */
48263d1a8abSmrg decimal128 canon; /* .. */
48363d1a8abSmrg decContext dc; /* .. */
48463d1a8abSmrg decContextDefault(&dc, DEC_INIT_DECIMAL128);
48563d1a8abSmrg decimal128ToNumber(d128, &dn);
48663d1a8abSmrg decimal128FromNumber(&canon, &dn, &dc);/* canon will now be canonical */
48763d1a8abSmrg return memcmp(d128, &canon, DECIMAL128_Bytes)==0;
48863d1a8abSmrg } /* decimal128IsCanonical */
48963d1a8abSmrg
49063d1a8abSmrg /* ------------------------------------------------------------------ */
49163d1a8abSmrg /* decimal128Canonical -- copy an encoding, ensuring it is canonical */
49263d1a8abSmrg /* d128 is the source decimal128 */
49363d1a8abSmrg /* result is the target (may be the same decimal128) */
49463d1a8abSmrg /* returns result */
49563d1a8abSmrg /* No error is possible. */
49663d1a8abSmrg /* ------------------------------------------------------------------ */
decimal128Canonical(decimal128 * result,const decimal128 * d128)49763d1a8abSmrg decimal128 * decimal128Canonical(decimal128 *result, const decimal128 *d128) {
49863d1a8abSmrg decNumber dn; /* work */
49963d1a8abSmrg decContext dc; /* .. */
50063d1a8abSmrg decContextDefault(&dc, DEC_INIT_DECIMAL128);
50163d1a8abSmrg decimal128ToNumber(d128, &dn);
50263d1a8abSmrg decimal128FromNumber(result, &dn, &dc);/* result will now be canonical */
50363d1a8abSmrg return result;
50463d1a8abSmrg } /* decimal128Canonical */
50563d1a8abSmrg
50663d1a8abSmrg #if DECTRACE || DECCHECK
50763d1a8abSmrg /* Macros for accessing decimal128 fields. These assume the argument
50863d1a8abSmrg is a reference (pointer) to the decimal128 structure, and the
50963d1a8abSmrg decimal128 is in network byte order (big-endian) */
51063d1a8abSmrg /* Get sign */
51163d1a8abSmrg #define decimal128Sign(d) ((unsigned)(d)->bytes[0]>>7)
51263d1a8abSmrg
51363d1a8abSmrg /* Get combination field */
51463d1a8abSmrg #define decimal128Comb(d) (((d)->bytes[0] & 0x7c)>>2)
51563d1a8abSmrg
51663d1a8abSmrg /* Get exponent continuation [does not remove bias] */
51763d1a8abSmrg #define decimal128ExpCon(d) ((((d)->bytes[0] & 0x03)<<10) \
51863d1a8abSmrg | ((unsigned)(d)->bytes[1]<<2) \
51963d1a8abSmrg | ((unsigned)(d)->bytes[2]>>6))
52063d1a8abSmrg
52163d1a8abSmrg /* Set sign [this assumes sign previously 0] */
52263d1a8abSmrg #define decimal128SetSign(d, b) { \
52363d1a8abSmrg (d)->bytes[0]|=((unsigned)(b)<<7);}
52463d1a8abSmrg
52563d1a8abSmrg /* Set exponent continuation [does not apply bias] */
52663d1a8abSmrg /* This assumes range has been checked and exponent previously 0; */
52763d1a8abSmrg /* type of exponent must be unsigned */
52863d1a8abSmrg #define decimal128SetExpCon(d, e) { \
52963d1a8abSmrg (d)->bytes[0]|=(uByte)((e)>>10); \
53063d1a8abSmrg (d)->bytes[1] =(uByte)(((e)&0x3fc)>>2); \
53163d1a8abSmrg (d)->bytes[2]|=(uByte)(((e)&0x03)<<6);}
53263d1a8abSmrg
53363d1a8abSmrg /* ------------------------------------------------------------------ */
53463d1a8abSmrg /* decimal128Show -- display a decimal128 in hexadecimal [debug aid] */
53563d1a8abSmrg /* d128 -- the number to show */
53663d1a8abSmrg /* ------------------------------------------------------------------ */
53763d1a8abSmrg /* Also shows sign/cob/expconfields extracted */
decimal128Show(const decimal128 * d128)53863d1a8abSmrg void decimal128Show(const decimal128 *d128) {
53963d1a8abSmrg char buf[DECIMAL128_Bytes*2+1];
54063d1a8abSmrg Int i, j=0;
54163d1a8abSmrg
54263d1a8abSmrg if (DECLITEND) {
54363d1a8abSmrg for (i=0; i<DECIMAL128_Bytes; i++, j+=2) {
54463d1a8abSmrg sprintf(&buf[j], "%02x", d128->bytes[15-i]);
54563d1a8abSmrg }
54663d1a8abSmrg printf(" D128> %s [S:%d Cb:%02x Ec:%02x] LittleEndian\n", buf,
54763d1a8abSmrg d128->bytes[15]>>7, (d128->bytes[15]>>2)&0x1f,
54863d1a8abSmrg ((d128->bytes[15]&0x3)<<10)|(d128->bytes[14]<<2)|
54963d1a8abSmrg (d128->bytes[13]>>6));
55063d1a8abSmrg }
55163d1a8abSmrg else {
55263d1a8abSmrg for (i=0; i<DECIMAL128_Bytes; i++, j+=2) {
55363d1a8abSmrg sprintf(&buf[j], "%02x", d128->bytes[i]);
55463d1a8abSmrg }
55563d1a8abSmrg printf(" D128> %s [S:%d Cb:%02x Ec:%02x] BigEndian\n", buf,
55663d1a8abSmrg decimal128Sign(d128), decimal128Comb(d128),
55763d1a8abSmrg decimal128ExpCon(d128));
55863d1a8abSmrg }
55963d1a8abSmrg } /* decimal128Show */
56063d1a8abSmrg #endif
561