#if DECPMAX==7
#define SINGLE 1
#define DOUBLE 0
#define QUAD 0
#define DEFCONTEXT DEC_INIT_DECIMAL32
#elif DECPMAX==16
#define SINGLE 0
#define DOUBLE 1
#define QUAD 0
#define DEFCONTEXT DEC_INIT_DECIMAL64
#elif DECPMAX==34
#define SINGLE 0
#define DOUBLE 0
#define QUAD 1
#define DEFCONTEXT DEC_INIT_DECIMAL128
#else
#error Unexpected DECPMAX value
#endif
#if DECPMAX!=7 && DECPMAX!=16 && DECPMAX!=34
#error Unexpected Pmax (DECPMAX) value for this module
#endif
#if ('9'&0x0f)!=9
#error This module assumes characters are of the form 0b....nnnn
#endif
#if ('9'&0xf0)==('.'&0xf0)
#error This module assumes '.' has a different mask than a digit
#endif
#if DECSTRING<DECPMAX+9
#error ToString needs at least 8 characters for lead-in and dot
#endif
#if DECPMAX+DECEMAXD+5 > DECSTRING
#error Exponent form can be too long for ToString to lay out safely
#endif
#if DECEMAXD > 4
#error Exponent form is too long for ToString to lay out
#endif
static decFloat * decFinalize(decFloat *, bcdnum *, decContext *);
static Flag decBiStr(const char *, const char *, const char *);
static const uInt DECCOMBEXP[64]={
0, 0, 0, 0, 0, 0, 0, 0,
1<<DECECONL, 1<<DECECONL, 1<<DECECONL, 1<<DECECONL,
1<<DECECONL, 1<<DECECONL, 1<<DECECONL, 1<<DECECONL,
2<<DECECONL, 2<<DECECONL, 2<<DECECONL, 2<<DECECONL,
2<<DECECONL, 2<<DECECONL, 2<<DECECONL, 2<<DECECONL,
0, 0, 1<<DECECONL, 1<<DECECONL,
2<<DECECONL, 2<<DECECONL, DECFLOAT_Inf, DECFLOAT_NaN,
0, 0, 0, 0, 0, 0, 0, 0,
1<<DECECONL, 1<<DECECONL, 1<<DECECONL, 1<<DECECONL,
1<<DECECONL, 1<<DECECONL, 1<<DECECONL, 1<<DECECONL,
2<<DECECONL, 2<<DECECONL, 2<<DECECONL, 2<<DECECONL,
2<<DECECONL, 2<<DECECONL, 2<<DECECONL, 2<<DECECONL,
0, 0, 1<<DECECONL, 1<<DECECONL,
2<<DECECONL, 2<<DECECONL, DECFLOAT_Inf, DECFLOAT_NaN};
#if !QUAD
static const uInt DECCOMBWEXP[64]={
0, 0, 0, 0, 0, 0, 0, 0,
1<<DECWECONL, 1<<DECWECONL, 1<<DECWECONL, 1<<DECWECONL,
1<<DECWECONL, 1<<DECWECONL, 1<<DECWECONL, 1<<DECWECONL,
2<<DECWECONL, 2<<DECWECONL, 2<<DECWECONL, 2<<DECWECONL,
2<<DECWECONL, 2<<DECWECONL, 2<<DECWECONL, 2<<DECWECONL,
0, 0, 1<<DECWECONL, 1<<DECWECONL,
2<<DECWECONL, 2<<DECWECONL, DECFLOAT_Inf, DECFLOAT_NaN,
0, 0, 0, 0, 0, 0, 0, 0,
1<<DECWECONL, 1<<DECWECONL, 1<<DECWECONL, 1<<DECWECONL,
1<<DECWECONL, 1<<DECWECONL, 1<<DECWECONL, 1<<DECWECONL,
2<<DECWECONL, 2<<DECWECONL, 2<<DECWECONL, 2<<DECWECONL,
2<<DECWECONL, 2<<DECWECONL, 2<<DECWECONL, 2<<DECWECONL,
0, 0, 1<<DECWECONL, 1<<DECWECONL,
2<<DECWECONL, 2<<DECWECONL, DECFLOAT_Inf, DECFLOAT_NaN};
#endif
#if QUAD
const uInt DECCOMBMSD[64]={
0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 9, 8, 9, 0, 0,
0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 9, 8, 9, 0, 0};
const uInt DECCOMBFROM[48]={
0x00000000, 0x04000000, 0x08000000, 0x0C000000, 0x10000000, 0x14000000,
0x18000000, 0x1C000000, 0x60000000, 0x64000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x20000000, 0x24000000,
0x28000000, 0x2C000000, 0x30000000, 0x34000000, 0x38000000, 0x3C000000,
0x68000000, 0x6C000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x40000000, 0x44000000, 0x48000000, 0x4C000000,
0x50000000, 0x54000000, 0x58000000, 0x5C000000, 0x70000000, 0x74000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000};
#define DEC_BCD2DPD 1
#define DEC_BIN2DPD 1
#define DEC_BIN2BCD8 1
#define DEC_DPD2BCD8 1
#define DEC_DPD2BIN 1
#define DEC_DPD2BINK 1
#define DEC_DPD2BINM 1
#include "decDPD.h"
#endif
static Flag decBiStr(const char *targ, const char *str1, const char *str2) {
for (;;targ++, str1++, str2++) {
if (*targ!=*str1 && *targ!=*str2) return 0;
if (*targ=='\0') break;
} return 1;
}
static uByte allnines[DECPMAX]=
#if SINGLE
{9, 9, 9, 9, 9, 9, 9};
#elif DOUBLE
{9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9};
#elif QUAD
{9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9};
#endif
static decFloat * decFinalize(decFloat *df, bcdnum *num,
decContext *set) {
uByte *ub; uInt dpd; uInt uiwork; uByte *umsd=num->msd; uByte *ulsd=num->lsd; uInt encode; Int length;
#if DECCHECK
Int clen=ulsd-umsd+1;
#if QUAD
#define COEXTRA 2
#else
#define COEXTRA 0
#endif
if (clen<1 || clen>DECPMAX*3+2+COEXTRA)
printf("decFinalize: suspect coefficient [length=%ld]\n", (LI)clen);
if (num->sign!=0 && num->sign!=DECFLOAT_Sign)
printf("decFinalize: bad sign [%08lx]\n", (LI)num->sign);
if (!EXPISSPECIAL(num->exponent)
&& (num->exponent>1999999999 || num->exponent<-1999999999))
printf("decFinalize: improbable exponent [%ld]\n", (LI)num->exponent);
#endif
length=(uInt)(ulsd-umsd+1);
if (!NUMISSPECIAL(num)) {
Int drop; if (*umsd==0) {
for (; umsd+3<ulsd && UBTOUI(umsd)==0;) umsd+=4;
for (; *umsd==0 && umsd<ulsd;) umsd++;
length=ulsd-umsd+1; }
drop=MAXI(length-DECPMAX, DECQTINY-num->exponent);
if (drop>0) { uByte *roundat; uByte reround;
num->exponent+=drop;
if (drop<length) { roundat=umsd+length-drop;
reround=*roundat;
for (ub=roundat+1; ub<=ulsd; ub++) {
if (*ub!=0) { reround=DECSTICKYTAB[reround]; break; }
} ulsd=roundat-1; }
else { if (drop==length) {
roundat=umsd;
reround=*roundat;
}
else {
roundat=umsd-1;
reround=0;
}
for (ub=roundat+1; ub<=ulsd; ub++) {
if (*ub!=0) { reround=DECSTICKYTAB[reround]; break; }
} *umsd=0; ulsd=umsd; }
if (reround!=0) { uInt bump=0;
set->status|=DEC_Inexact;
if (num->exponent<DECEMIN && (num->exponent+(ulsd-umsd+1)-1)<DECEMIN)
set->status|=DEC_Underflow;
if (set->round==DEC_ROUND_HALF_EVEN) { if (reround>5) bump=1; else if (reround==5) bump=*ulsd & 0x01; } else switch (set->round) {
case DEC_ROUND_DOWN: {
break;} case DEC_ROUND_HALF_DOWN: {
if (reround>5) bump=1;
break;} case DEC_ROUND_HALF_UP: {
if (reround>=5) bump=1;
break;} case DEC_ROUND_UP: {
if (reround>0) bump=1;
break;} case DEC_ROUND_CEILING: {
if (!num->sign && reround>0) bump=1;
break;} case DEC_ROUND_FLOOR: {
if (num->sign && reround>0) bump=1;
break;} case DEC_ROUND_05UP: {
if (reround>0) { if (*ulsd==0 || *ulsd==5) bump=1;
}
break;} default: { set->status|=DEC_Invalid_context;
#if DECCHECK
printf("Unknown rounding mode: %ld\n", (LI)set->round);
#endif
break;}
}
if (bump!=0) { ub=ulsd;
for(; ub-3>=umsd && UBTOUI(ub-3)==0x09090909; ub-=4) {
UBFROMUI(ub-3, 0); }
for (; ub>=umsd; *ub=0, ub--) {
if (*ub==9) continue; *ub+=1;
break;
}
if (ub<umsd) { *umsd=1; if ((ulsd-umsd+1)==DECPMAX) {
num->exponent++;
}
else {
ulsd++;
*ulsd=0;
#if DECCHECK
if (num->exponent!=DECQTINY) printf("decFinalize: bad all-nines extend [^%ld, %ld]\n",
(LI)num->exponent, (LI)(ulsd-umsd+1));
#endif
} } } }
length=ulsd-umsd+1; }
if (num->exponent>DECEMAX-(DECPMAX-1)) { if (*ulsd==0 && ulsd==umsd) { num->exponent=DECEMAX-(DECPMAX-1); }
else if ((num->exponent+length-1)>DECEMAX) { Flag needmax=0; set->status|=(DEC_Overflow | DEC_Inexact);
switch (set->round) {
case DEC_ROUND_DOWN: {
needmax=1; break;} case DEC_ROUND_05UP: {
needmax=1; break;} case DEC_ROUND_CEILING: {
if (num->sign) needmax=1; break;} case DEC_ROUND_FLOOR: {
if (!num->sign) needmax=1; break;} default: break; }
if (!needmax) { num->exponent=DECFLOAT_Inf;
*umsd=0; ulsd=umsd; }
else { umsd=allnines; ulsd=allnines+DECPMAX-1;
num->exponent=DECEMAX-(DECPMAX-1);
}
}
else { Int shift=num->exponent-(DECEMAX-(DECPMAX-1));
if (shift>0) { uByte buffer[ROUNDUP(DECPMAX+3, 4)]; uByte *s=umsd; uByte *t=buffer; uByte *tlsd=buffer+(ulsd-umsd)+shift; for (; s<=ulsd; s+=4, t+=4) UBFROMUI(t, UBTOUI(s));
for (t=tlsd-shift+1; t<=tlsd; t+=4) UBFROMUI(t, 0); num->exponent-=shift;
umsd=buffer;
ulsd=tlsd;
}
} length=ulsd-umsd+1; } }
if (length==DECPMAX) {
return decFloatFromBCD(df, num->exponent, umsd, num->sign);
}
if (!NUMISSPECIAL(num)) { uInt uexp=(uInt)(num->exponent+DECBIAS); uInt code=(uexp>>DECECONL)<<4; encode=DECCOMBFROM[code]; encode|=(uexp<<(32-6-DECECONL)) & 0x03ffffff; }
else encode=num->exponent; encode|=num->sign;
#define getDPDt(dpd, n) ub=ulsd-(3*(n))-2; \
if (ub<umsd-2) dpd=0; \
else if (ub>=umsd) dpd=BCD2DPD[(*ub*256)+(*(ub+1)*16)+*(ub+2)]; \
else {dpd=*(ub+2); if (ub+1==umsd) dpd+=*(ub+1)*16; dpd=BCD2DPD[dpd];}
#if DECPMAX==7
getDPDt(dpd, 1);
encode|=dpd<<10;
getDPDt(dpd, 0);
encode|=dpd;
DFWORD(df, 0)=encode;
#elif DECPMAX==16
getDPDt(dpd, 4); encode|=dpd<<8;
getDPDt(dpd, 3); encode|=dpd>>2;
DFWORD(df, 0)=encode;
encode=dpd<<30;
getDPDt(dpd, 2); encode|=dpd<<20;
getDPDt(dpd, 1); encode|=dpd<<10;
getDPDt(dpd, 0); encode|=dpd;
DFWORD(df, 1)=encode;
#elif DECPMAX==34
getDPDt(dpd,10); encode|=dpd<<4;
getDPDt(dpd, 9); encode|=dpd>>6;
DFWORD(df, 0)=encode;
encode=dpd<<26;
getDPDt(dpd, 8); encode|=dpd<<16;
getDPDt(dpd, 7); encode|=dpd<<6;
getDPDt(dpd, 6); encode|=dpd>>4;
DFWORD(df, 1)=encode;
encode=dpd<<28;
getDPDt(dpd, 5); encode|=dpd<<18;
getDPDt(dpd, 4); encode|=dpd<<8;
getDPDt(dpd, 3); encode|=dpd>>2;
DFWORD(df, 2)=encode;
encode=dpd<<30;
getDPDt(dpd, 2); encode|=dpd<<20;
getDPDt(dpd, 1); encode|=dpd<<10;
getDPDt(dpd, 0); encode|=dpd;
DFWORD(df, 3)=encode;
#endif
return df;
}
decFloat * decFloatFromBCD(decFloat *df, Int exp, const uByte *bcdar,
Int sig) {
uInt encode, dpd; const uByte *ub;
if (EXPISSPECIAL(exp)) encode=exp|sig; else { uInt uexp=(uInt)(exp+DECBIAS); uInt code=(uexp>>DECECONL)<<4; code+=bcdar[0]; encode=DECCOMBFROM[code]|sig; encode|=(uexp<<(32-6-DECECONL)) & 0x03ffffff; }
#define getDPDb(dpd, n) ub=bcdar+DECPMAX-1-(3*(n))-2; \
dpd=BCD2DPD[(*ub*256)+(*(ub+1)*16)+*(ub+2)];
#if DECPMAX==7
getDPDb(dpd, 1);
encode|=dpd<<10;
getDPDb(dpd, 0);
encode|=dpd;
DFWORD(df, 0)=encode;
#elif DECPMAX==16
getDPDb(dpd, 4); encode|=dpd<<8;
getDPDb(dpd, 3); encode|=dpd>>2;
DFWORD(df, 0)=encode;
encode=dpd<<30;
getDPDb(dpd, 2); encode|=dpd<<20;
getDPDb(dpd, 1); encode|=dpd<<10;
getDPDb(dpd, 0); encode|=dpd;
DFWORD(df, 1)=encode;
#elif DECPMAX==34
getDPDb(dpd,10); encode|=dpd<<4;
getDPDb(dpd, 9); encode|=dpd>>6;
DFWORD(df, 0)=encode;
encode=dpd<<26;
getDPDb(dpd, 8); encode|=dpd<<16;
getDPDb(dpd, 7); encode|=dpd<<6;
getDPDb(dpd, 6); encode|=dpd>>4;
DFWORD(df, 1)=encode;
encode=dpd<<28;
getDPDb(dpd, 5); encode|=dpd<<18;
getDPDb(dpd, 4); encode|=dpd<<8;
getDPDb(dpd, 3); encode|=dpd>>2;
DFWORD(df, 2)=encode;
encode=dpd<<30;
getDPDb(dpd, 2); encode|=dpd<<20;
getDPDb(dpd, 1); encode|=dpd<<10;
getDPDb(dpd, 0); encode|=dpd;
DFWORD(df, 3)=encode;
#endif
return df;
}
decFloat * decFloatFromPacked(decFloat *df, Int exp, const uByte *packed) {
uByte bcdar[DECPMAX+2]; const uByte *ip; uByte *op; Int sig=0;
#if SINGLE
op=bcdar+1; #else
op=bcdar; #endif
for (ip=packed; ip<packed+((DECPMAX+2)/2); ip++) {
*op++=*ip>>4;
*op++=(uByte)(*ip&0x0f); }
op--; if (*op==DECPMINUS || *op==DECPMINUSALT) sig=DECFLOAT_Sign;
if (EXPISSPECIAL(exp)) { if (!EXPISINF(exp)) bcdar[1]=0; else memset(bcdar+1, 0, DECPMAX); }
return decFloatFromBCD(df, exp, bcdar+1, sig);
}
decFloat * decFloatFromPackedChecked(decFloat *df, Int exp,
const uByte *packed) {
uByte bcdar[DECPMAX+2]; const uByte *ip; uByte *op; Int sig=0;
#if SINGLE
op=bcdar+1; #else
op=bcdar; #endif
for (ip=packed; ip<packed+((DECPMAX+2)/2); ip++) {
*op=*ip>>4;
if (*op>9) return NULL;
op++;
*op=(uByte)(*ip&0x0f); if (*op>9 && ip<packed+((DECPMAX+2)/2)-1) return NULL;
op++;
}
op--; if (*op<=9) return NULL; if (*op==DECPMINUS || *op==DECPMINUSALT) sig=DECFLOAT_Sign;
#if !SINGLE
if (bcdar[0]!=0) return NULL; #endif
if (EXPISNAN(exp)) { if (bcdar[1]!=0) return NULL; } else if (EXPISINF(exp)) { Int i;
for (i=0; i<DECPMAX; i++) {
if (bcdar[i+1]!=0) return NULL; }
} else { if (exp>DECEMAX-DECPMAX+1) return NULL;
if (exp<DECEMIN-DECPMAX+1) return NULL;
}
return decFloatFromBCD(df, exp, bcdar+1, sig);
}
decFloat * decFloatFromString(decFloat *result, const char *string,
decContext *set) {
Int digits; const char *dotchar=NULL; const char *cfirst=string; const char *c; uByte *ub; uInt uiwork; bcdnum num; uInt error=DEC_Conversion_syntax; uByte buffer[ROUNDUP(DECSTRING+11, 8)]; #if DECTRACE
#endif
for(;;) { num.sign=0; num.msd=buffer;
for (c=string;; c++) { if (((unsigned)(*c-'0'))<=9) continue; if (*c=='\0') break; if (*c=='.') {
if (dotchar!=NULL) break; dotchar=c; continue;}
if (c==string) { if (*c=='-') { cfirst++;
num.sign=DECFLOAT_Sign;
continue;}
if (*c=='+') { cfirst++;
continue;}
}
break;
}
digits=(uInt)(c-cfirst);
if (digits>0) { const char *clast=c-1; Int exp=0; if (*c!='\0') { uInt edig; const char *firstexp; if (*c!='E' && *c!='e') break;
c++; if (*c=='-' || *c=='+') c++; if (*c=='\0') break; for (; *c=='0';) c++; firstexp=c; edig=(uInt)*c-(uInt)'0';
if (edig<=9) { exp+=edig; c++;
for (;; c++) {
edig=(uInt)*c-(uInt)'0';
if (edig>9) break;
exp=exp*10+edig;
}
}
if (*c!='\0') break;
if (c>firstexp+DECEMAXD) exp=DECEMAX*2;
if (*(clast+2)=='-') exp=-exp; }
if (dotchar!=NULL) { digits--; if (digits==0) break; exp-=(Int)(clast-dotchar); }
num.exponent=exp;
error=0;
ub=buffer;
if (digits<=(Int)(sizeof(buffer)-3)) { c=cfirst;
if (dotchar!=NULL) { if (*(c+1)=='.') { *ub++=(uByte)(*c-'0'); c+=2; }
else for (; c<=clast;) { if (c<=clast-3 && (UBTOUI(c)&0xf0f0f0f0)==CHARMASK) { UBFROMUI(ub, UBTOUI(c)&0x0f0f0f0f); ub+=4;
c+=4;
continue;
}
if (*c=='.') { c++; break; }
*ub++=(uByte)(*c++-'0');
}
} for (; c<=clast-3; c+=4, ub+=4) UBFROMUI(ub, UBTOUI(c)&0x0f0f0f0f);
for (; c<=clast; c++, ub++) *ub=(uByte)(*c-'0');
num.lsd=buffer+digits-1; }
else { if (*cfirst=='.') cfirst++; if (*cfirst=='0') { for (; cfirst<clast; cfirst++) {
if (*cfirst!='0') { if (*cfirst=='.') continue; break; }
digits--; } }
for (c=cfirst; c<=clast && ub<=buffer+DECPMAX; c++) {
if (c<=clast-3 && (UBTOUI(c)&0xf0f0f0f0)==CHARMASK) { UBFROMUI(ub, UBTOUI(c)&0x0f0f0f0f); ub+=4;
c+=3; continue;
}
if (*c=='.') continue; *ub++=(uByte)(*c-'0');
}
ub--; for (; c<=clast; c++) { if (*c!='0') { if (*c=='.') continue; *ub=DECSTICKYTAB[*ub]; break; }
}
num.lsd=ub; num.exponent+=digits-(Int)(ub-buffer+1);
} }
else { if (*c=='\0') break; buffer[0]=0; num.lsd=buffer; if (decBiStr(c, "infinity", "INFINITY")
|| decBiStr(c, "inf", "INF")) num.exponent=DECFLOAT_Inf;
else { num.exponent=DECFLOAT_qNaN; if (*c=='s' || *c=='S') { num.exponent=DECFLOAT_sNaN; c++; }
if (*c!='N' && *c!='n') break; c++;
if (*c!='a' && *c!='A') break; c++;
if (*c!='N' && *c!='n') break; c++;
for (cfirst=c; *cfirst=='0';) cfirst++;
if (*cfirst!='\0') { ub=buffer;
for (c=cfirst;; c++, ub++) {
if ((unsigned)(*c-'0')>9) break; if (c-cfirst==DECPMAX-1) break; *ub=(uByte)(*c-'0'); }
if (*c!='\0') break; num.lsd=ub-1; }
} error=0; } break; }
if (error!=0) {
set->status|=error;
num.exponent=DECFLOAT_qNaN; num.sign=0; buffer[0]=0; num.lsd=buffer; }
decFinalize(result, &num, set); return result;
}
#if !QUAD
decFloat * decFloatFromWider(decFloat *result, const decFloatWider *wider,
decContext *set) {
bcdnum num; uByte bcdar[DECWPMAX]; uInt widerhi=DFWWORD(wider, 0); Int exp;
GETWCOEFF(wider, bcdar);
num.msd=bcdar; num.lsd=bcdar+DECWPMAX-1; num.sign=widerhi&0x80000000;
exp=DECCOMBWEXP[widerhi>>26]; if (EXPISSPECIAL(exp)) exp=widerhi&0x7e000000; else exp+=GETWECON(wider)-DECWBIAS;
num.exponent=exp;
return decFinalize(result, &num, set); } #endif
Int decFloatGetCoefficient(const decFloat *df, uByte *bcdar) {
if (DFISINF(df)) memset(bcdar, 0, DECPMAX);
else {
GETCOEFF(df, bcdar); if (DFISNAN(df)) bcdar[0]=0; }
return GETSIGN(df);
}
Int decFloatGetExponent(const decFloat *df) {
if (DFISSPECIAL(df)) return DFWORD(df, 0)&0x7e000000;
return GETEXPUN(df);
}
decFloat * decFloatSetCoefficient(decFloat *df, const uByte *bcdar,
Int sig) {
uInt exp; uByte bcdzero[DECPMAX];
if (DFISSPECIAL(df)) {
exp=DFWORD(df, 0)&0x7e000000;
if (DFISINF(df)) {
memset(bcdzero, 0, DECPMAX);
return decFloatFromBCD(df, exp, bcdzero, sig);
}
}
else exp=GETEXPUN(df);
return decFloatFromBCD(df, exp, bcdar, sig);
}
decFloat * decFloatSetExponent(decFloat *df, decContext *set, Int exp) {
uByte bcdcopy[DECPMAX]; bcdnum num; num.exponent=exp;
num.sign=decFloatGetCoefficient(df, bcdcopy); if (DFISSPECIAL(df)) { if (DFISINF(df)) memset(bcdcopy, 0, DECPMAX);
bcdcopy[0]=0;
}
num.msd=bcdcopy;
num.lsd=bcdcopy+DECPMAX-1;
return decFinalize(df, &num, set);
}
uInt decFloatRadix(const decFloat *df) {
if (df) return 10; return 10;
}
#if DECPRINT
void decFloatShow(const decFloat *df, const char *tag) {
char hexbuf[DECBYTES*2+DECBYTES/4+1]; char buff[DECSTRING]; Int i, j=0;
for (i=0; i<DECBYTES; i++) {
#if DECLITEND
sprintf(&hexbuf[j], "%02x", df->bytes[DECBYTES-1-i]);
#else
sprintf(&hexbuf[j], "%02x", df->bytes[i]);
#endif
j+=2;
if ((i+1)%4==0) {strcpy(&hexbuf[j], " "); j++;}
}
decFloatToString(df, buff);
printf(">%s> %s [big-endian] %s\n", tag, hexbuf, buff);
return;
} #endif
Int decFloatToBCD(const decFloat *df, Int *exp, uByte *bcdar) {
if (DFISINF(df)) {
memset(bcdar, 0, DECPMAX);
*exp=DFWORD(df, 0)&0x7e000000;
}
else {
GETCOEFF(df, bcdar); if (DFISNAN(df)) {
bcdar[0]=0; *exp=DFWORD(df, 0)&0x7e000000;
}
else { *exp=GETEXPUN(df);
}
}
return GETSIGN(df);
}
char * decFloatToEngString(const decFloat *df, char *string){
uInt msd; Int exp; uInt comb; char *cstart; char *c; char *s, *t; Int pre, e; const uByte *u; uInt uiwork;
uInt sourhi=DFWORD(df, 0); #if DECPMAX==16
uInt sourlo=DFWORD(df, 1);
#elif DECPMAX==34
uInt sourmh=DFWORD(df, 1);
uInt sourml=DFWORD(df, 2);
uInt sourlo=DFWORD(df, 3);
#endif
c=string; if (((Int)sourhi)<0) *c++='-'; comb=sourhi>>26; msd=DECCOMBMSD[comb]; exp=DECCOMBEXP[comb];
if (EXPISSPECIAL(exp)) { if (exp==DECFLOAT_Inf) { strcpy(c, "Inf");
strcpy(c+3, "inity");
return string; }
if (sourhi&0x02000000) *c++='s'; strcpy(c, "NaN"); c+=3; #if DECPMAX==7
if ((sourhi&0x000fffff)==0) return string;
#elif DECPMAX==16
if (sourlo==0 && (sourhi&0x0003ffff)==0) return string;
#elif DECPMAX==34
if (sourlo==0 && sourml==0 && sourmh==0
&& (sourhi&0x00003fff)==0) return string;
#endif
exp=0; msd=0; }
else { exp+=GETECON(df)-DECBIAS; }
cstart=c; if (msd) *c++=(char)('0'+(char)msd);
#define dpd2char(dpdin) u=&DPD2BCD8[((dpdin)&0x3ff)*4]; \
if (c!=cstart) {UBFROMUI(c, UBTOUI(u)|CHARMASK); c+=3;} \
else if (*(u+3)) { \
UBFROMUI(c, UBTOUI(u+3-*(u+3))|CHARMASK); c+=*(u+3);}
#if DECPMAX==7
dpd2char(sourhi>>10); dpd2char(sourhi);
#elif DECPMAX==16
dpd2char(sourhi>>8); dpd2char((sourhi<<2) | (sourlo>>30)); dpd2char(sourlo>>20); dpd2char(sourlo>>10); dpd2char(sourlo);
#elif DECPMAX==34
dpd2char(sourhi>>4); dpd2char((sourhi<<6) | (sourmh>>26)); dpd2char(sourmh>>16); dpd2char(sourmh>>6); dpd2char((sourmh<<4) | (sourml>>28)); dpd2char(sourml>>18); dpd2char(sourml>>8); dpd2char((sourml<<2) | (sourlo>>30)); dpd2char(sourlo>>20); dpd2char(sourlo>>10); dpd2char(sourlo); #endif
if (c==cstart) *c++='0';
if (exp==0) { *c='\0'; return string;
}
e=0; pre=(Int)(c-cstart)+exp;
if (exp>0 || pre<-5) { e=pre-1; pre=1; if (e!=0) { Int adj; if (e<0) {
adj=(-e)%3;
if (adj!=0) adj=3-adj;
}
else { adj=e%3;
}
e=e-adj;
if (!DFISZERO(df)) pre+=adj;
else { if (adj!=0) { e=e+3;
pre=-(2-adj);
}
} } }
if (pre>0) { char *dotat=cstart+pre;
if (dotat<c) { s=dotat+ROUNDDOWN4(c-dotat); t=s+1; for (; s>=dotat; s-=4, t-=4) UBFROMUI(t, UBTOUI(s));
*dotat='.';
c++; } else for (; c<dotat; c++) *c='0'; } else {
pre=-pre+2; t=cstart+ROUNDDOWN4(c-cstart)+pre; if (t>string+DECSTRING-5) t=string+DECSTRING-5; for (s=t-pre; s>=string; s-=4, t-=4) UBFROMUI(t, UBTOUI(s));
s+=3; for(; s>=cstart; s--, t--) *(t+3)=*(s);
if (pre>=4) {
memcpy(cstart+pre-4, "0000", 4);
memcpy(cstart, "0.00", 4);
}
else { *(cstart+pre-1)='0';
memcpy(cstart, "0.", 2);
}
c+=pre; }
if (e!=0) {
memcpy(c, "E+", 2); c++;
if (e<0) {
*c='-'; e=-e; }
c++;
#if DECEMAXD<=3
u=&BIN2BCD8[e*4]; UBFROMUI(c, UBTOUI(u+3-*(u+3))|CHARMASK);
c+=*(u+3); #elif DECEMAXD==4
if (e<1000) { u=&BIN2BCD8[e*4]; UBFROMUI(c, UBTOUI(u+3-*(u+3))|CHARMASK); c+=*(u+3); }
else { Int thou=((e>>3)*1049)>>17; Int rem=e-(1000*thou); *c++=(char)('0'+(char)thou); u=&BIN2BCD8[rem*4]; UBFROMUI(c, UBTOUI(u)|CHARMASK); c+=3; }
#endif
}
*c='\0'; return string;
}
Int decFloatToPacked(const decFloat *df, Int *exp, uByte *packed) {
uByte bcdar[DECPMAX+2]; uByte *ip=bcdar, *op=packed; if (DFISINF(df)) {
memset(bcdar, 0, DECPMAX+2);
*exp=DECFLOAT_Inf;
}
else {
GETCOEFF(df, bcdar+1); if (DFISNAN(df)) {
bcdar[1]=0; *exp=DFWORD(df, 0)&0x7e000000;
}
else { *exp=GETEXPUN(df);
}
}
#if SINGLE
ip++; #else
*ip=0; #endif
bcdar[DECPMAX+1]=(DFISSIGNED(df) ? DECPMINUS : DECPPLUS);
for (; op<packed+((DECPMAX+2)/2); op++, ip+=2) {
*op=(uByte)((*ip<<4)+*(ip+1));
}
return (bcdar[DECPMAX+1]==DECPMINUS ? DECFLOAT_Sign : 0);
}
char * decFloatToString(const decFloat *df, char *string){
uInt msd; Int exp; uInt comb; char *cstart; char *c; char *s, *t; Int pre, e; const uByte *u; uInt uiwork;
uInt sourhi=DFWORD(df, 0); #if DECPMAX==16
uInt sourlo=DFWORD(df, 1);
#elif DECPMAX==34
uInt sourmh=DFWORD(df, 1);
uInt sourml=DFWORD(df, 2);
uInt sourlo=DFWORD(df, 3);
#endif
c=string; if (((Int)sourhi)<0) *c++='-'; comb=sourhi>>26; msd=DECCOMBMSD[comb]; exp=DECCOMBEXP[comb];
if (!EXPISSPECIAL(exp)) { exp+=GETECON(df)-DECBIAS; }
else { if (exp==DECFLOAT_Inf) { strcpy(c, "Infinity");
return string; }
if (sourhi&0x02000000) *c++='s'; strcpy(c, "NaN"); c+=3; #if DECPMAX==7
if ((sourhi&0x000fffff)==0) return string;
#elif DECPMAX==16
if (sourlo==0 && (sourhi&0x0003ffff)==0) return string;
#elif DECPMAX==34
if (sourlo==0 && sourml==0 && sourmh==0
&& (sourhi&0x00003fff)==0) return string;
#endif
exp=0; msd=0; }
cstart=c; if (msd) *c++=(char)('0'+(char)msd);
#define dpd2char(dpdin) u=&DPD2BCD8[((dpdin)&0x3ff)*4]; \
if (c!=cstart) {UBFROMUI(c, UBTOUI(u)|CHARMASK); c+=3;} \
else if (*(u+3)) { \
UBFROMUI(c, UBTOUI(u+3-*(u+3))|CHARMASK); c+=*(u+3);}
#if DECPMAX==7
dpd2char(sourhi>>10); dpd2char(sourhi);
#elif DECPMAX==16
dpd2char(sourhi>>8); dpd2char((sourhi<<2) | (sourlo>>30)); dpd2char(sourlo>>20); dpd2char(sourlo>>10); dpd2char(sourlo);
#elif DECPMAX==34
dpd2char(sourhi>>4); dpd2char((sourhi<<6) | (sourmh>>26)); dpd2char(sourmh>>16); dpd2char(sourmh>>6); dpd2char((sourmh<<4) | (sourml>>28)); dpd2char(sourml>>18); dpd2char(sourml>>8); dpd2char((sourml<<2) | (sourlo>>30)); dpd2char(sourlo>>20); dpd2char(sourlo>>10); dpd2char(sourlo); #endif
if (c==cstart) *c++='0';
e=0; pre=(Int)(c-cstart)+exp;
if (exp>0 || pre<-5) { e=pre-1; pre=1; }
if (pre>0) { char *dotat=cstart+pre;
if (dotat<c) { s=dotat+ROUNDDOWN4(c-dotat); t=s+1; for (; s>=dotat; s-=4, t-=4) UBFROMUI(t, UBTOUI(s));
*dotat='.';
c++; }
if (e!=0) {
memcpy(c, "E+", 2); c++;
if (e<0) {
*c='-'; e=-e; }
c++;
#if DECEMAXD<=3
u=&BIN2BCD8[e*4]; UBFROMUI(c, UBTOUI(u+3-*(u+3))|CHARMASK);
c+=*(u+3); #elif DECEMAXD==4
if (e<1000) { u=&BIN2BCD8[e*4]; UBFROMUI(c, UBTOUI(u+3-*(u+3))|CHARMASK); c+=*(u+3); }
else { Int thou=((e>>3)*1049)>>17; Int rem=e-(1000*thou); *c++=(char)('0'+(char)thou); u=&BIN2BCD8[rem*4]; UBFROMUI(c, UBTOUI(u)|CHARMASK); c+=3; }
#endif
}
*c='\0'; return string;
}
pre=-pre+2; t=cstart+ROUNDDOWN4(c-cstart)+pre; if (t>string+DECSTRING-5) t=string+DECSTRING-5; for (s=t-pre; s>=string; s-=4, t-=4) UBFROMUI(t, UBTOUI(s));
s+=3; for(; s>=cstart; s--, t--) *(t+3)=*(s);
if (pre>=4) {
memcpy(cstart+pre-4, "0000", 4);
memcpy(cstart, "0.00", 4);
}
else { *(cstart+pre-1)='0';
memcpy(cstart, "0.", 2);
}
*(c+pre)='\0'; return string;
}
#if !QUAD
decFloatWider * decFloatToWider(const decFloat *source, decFloatWider *wider) {
uInt msd;
if (DFISSPECIAL(source)) {
DFWWORD(wider, 0)=DFWORD(source, 0)&0xfe000000;
msd=0;
}
else { uInt exp=GETEXPUN(source)+DECWBIAS; uInt code=(exp>>DECWECONL)<<29; code|=(exp<<(32-6-DECWECONL)) & 0x03ffffff; code|=DFWORD(source, 0)&0x80000000; DFWWORD(wider, 0)=code; msd=GETMSD(source); }
#if SINGLE
DFWWORD(wider, 1)=(DFWORD(source, 0)&0x000fffff)|(msd<<20);
#elif DOUBLE
DFWWORD(wider, 2)=(DFWORD(source, 0)&0x0003ffff)|(msd<<18);
DFWWORD(wider, 3)=DFWORD(source, 1);
DFWWORD(wider, 1)=0;
#endif
return wider;
} #endif
const char *decFloatVersion(void) {
return DECVERSION;
}
decFloat * decFloatZero(decFloat *df){
DFWORD(df, 0)=ZEROWORD; #if DOUBLE || QUAD
DFWORD(df, 1)=0;
#if QUAD
DFWORD(df, 2)=0;
DFWORD(df, 3)=0;
#endif
#endif
return df;
}
#if QUAD && (DECCHECK || DECTRACE)
void decShowNum(const bcdnum *num, const char *tag) {
const char *csign="+"; uByte *ub; uInt uiwork; if (num->sign==DECFLOAT_Sign) csign="-";
printf(">%s> ", tag);
if (num->exponent==DECFLOAT_Inf) printf("%sInfinity", csign);
else if (num->exponent==DECFLOAT_qNaN) printf("%sqNaN", csign);
else if (num->exponent==DECFLOAT_sNaN) printf("%ssNaN", csign);
else { char qbuf[10]; char *c; const uByte *u; Int e=num->exponent; strcpy(qbuf, "q=");
c=&qbuf[2]; if (e<0) {
*c++='-'; e=-e; }
#if DECEMAXD>4
#error Exponent form is too long for ShowNum to lay out
#endif
if (e==0) *c++='0'; else if (e<1000) { u=&BIN2BCD8[e*4]; UBFROMUI(c, UBTOUI(u+3-*(u+3))|CHARMASK); c+=*(u+3); }
else { Int thou=((e>>3)*1049)>>17; Int rem=e-(1000*thou); *c++=(char)('0'+(char)thou); u=&BIN2BCD8[rem*4]; UBFROMUI(c, UBTOUI(u)|CHARMASK); c+=3; }
*c='\0'; printf("%7s c=%s", qbuf, csign);
}
if (!EXPISSPECIAL(num->exponent) || num->msd!=num->lsd || *num->lsd!=0) {
for (ub=num->msd; ub<=num->lsd; ub++) { printf("%1x", *ub);
if ((num->lsd-ub)%3==0 && ub!=num->lsd) printf(" "); }
}
printf("\n");
} #endif