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