#if !defined(QUAD)
#error decBasic.c must be included after decCommon.c
#endif
#if SINGLE
#error Routines in decBasic.c are for decDouble and decQuad only
#endif
#define DIVIDE 0x80000000
#define REMAINDER 0x40000000
#define DIVIDEINT 0x20000000
#define REMNEAR 0x10000000
static decFloat *decDivide(decFloat *, const decFloat *,
const decFloat *, decContext *, uInt);
static decFloat *decCanonical(decFloat *, const decFloat *);
static void decFiniteMultiply(bcdnum *, uByte *, const decFloat *,
const decFloat *);
static decFloat *decInfinity(decFloat *, const decFloat *);
static decFloat *decInvalid(decFloat *, decContext *);
static decFloat *decNaNs(decFloat *, const decFloat *, const decFloat *,
decContext *);
static Int decNumCompare(const decFloat *, const decFloat *, Flag);
static decFloat *decToIntegral(decFloat *, const decFloat *, decContext *,
enum rounding, Flag);
static uInt decToInt32(const decFloat *, decContext *, enum rounding,
Flag, Flag);
static decFloat * decCanonical(decFloat *result, const decFloat *df) {
uInt encode, precode, dpd; uInt inword, uoff, canon; Int n; if (df!=result) *result=*df; if (DFISSPECIAL(result)) {
if (DFISINF(result)) return decInfinity(result, df); DFWORD(result, 0)&=~ECONNANMASK; if (DFISCCZERO(df)) return result; }
{ #if DOUBLE
uInt sourhi=DFWORD(df, 0);
uInt sourlo=DFWORD(df, 1);
if (CANONDPDOFF(sourhi, 8)
&& CANONDPDTWO(sourhi, sourlo, 30)
&& CANONDPDOFF(sourlo, 20)
&& CANONDPDOFF(sourlo, 10)
&& CANONDPDOFF(sourlo, 0)) return result;
#elif QUAD
uInt sourhi=DFWORD(df, 0);
uInt sourmh=DFWORD(df, 1);
uInt sourml=DFWORD(df, 2);
uInt sourlo=DFWORD(df, 3);
if (CANONDPDOFF(sourhi, 4)
&& CANONDPDTWO(sourhi, sourmh, 26)
&& CANONDPDOFF(sourmh, 16)
&& CANONDPDOFF(sourmh, 6)
&& CANONDPDTWO(sourmh, sourml, 28)
&& CANONDPDOFF(sourml, 18)
&& CANONDPDOFF(sourml, 8)
&& CANONDPDTWO(sourml, sourlo, 30)
&& CANONDPDOFF(sourlo, 20)
&& CANONDPDOFF(sourlo, 10)
&& CANONDPDOFF(sourlo, 0)) return result;
#endif
}
inword=DECWORDS-1; uoff=0; encode=DFWORD(result, inword);
for (n=DECLETS-1; n>=0; n--) { dpd=encode>>uoff;
uoff+=10;
if (uoff>32) { inword--;
encode=DFWORD(result, inword);
uoff-=32;
dpd|=encode<<(10-uoff); }
dpd&=0x3ff; if (dpd<0x16e) continue; canon=BIN2DPD[DPD2BIN[dpd]]; if (canon==dpd) continue; if (uoff>=10) { encode&=~(0x3ff<<(uoff-10)); encode|=canon<<(uoff-10); DFWORD(result, inword)=encode; continue;
}
precode=DFWORD(result, inword+1); precode&=0xffffffff>>(10-uoff); DFWORD(result, inword+1)=precode|(canon<<(32-(10-uoff)));
encode&=0xffffffff<<uoff; encode|=canon>>(10-uoff); DFWORD(result, inword)=encode; } return result;
}
#define DIVCOUNT 0
#define DIVBASE ((uInt)BILLION)
#define DIVOPLEN DECPMAX9
#define DIVACCLEN (DIVOPLEN*3)
static decFloat * decDivide(decFloat *result, const decFloat *dfl,
const decFloat *dfr, decContext *set, uInt op) {
decFloat quotient; bcdnum num; uInt acc[DIVACCLEN]; uInt div[DIVOPLEN]; uInt quo[DIVOPLEN+1]; uByte bcdacc[(DIVOPLEN+1)*9+2]; uInt *msua, *msud, *msuq; Int divunits, accunits; Int quodigits; uInt *lsua, *lsuq; Int length, multiplier; uInt carry, sign; uInt *ua, *ud, *uq; uByte *ub; uInt uiwork; uInt divtop; #if DIVCOUNT
static uInt maxcount=0; uInt divcount=0; #endif
num.sign=(DFWORD(dfl, 0)^DFWORD(dfr, 0)) & DECFLOAT_Sign;
if (DFISSPECIAL(dfl) || DFISSPECIAL(dfr)) { if (DFISNAN(dfl) || DFISNAN(dfr)) return decNaNs(result, dfl, dfr, set);
if (DFISINF(dfl)) {
if (DFISINF(dfr)) return decInvalid(result, set); if (op&(REMAINDER|REMNEAR)) return decInvalid(result, set); DFWORD(result, 0)=num.sign;
return decInfinity(result, result);
}
if (op&(REMAINDER|REMNEAR)) return decCanonical(result, dfl);
decFloatZero(result);
if (op==DIVIDEINT) DFWORD(result, 0)|=num.sign; else DFWORD(result, 0)=num.sign; return result;
}
if (DFISZERO(dfr)) { if (DFISZERO(dfl)) { decFloatZero(result);
DFWORD(result, 0)=DECFLOAT_qNaN;
set->status|=DEC_Division_undefined;
return result;
}
if (op&(REMAINDER|REMNEAR)) return decInvalid(result, set); set->status|=DEC_Division_by_zero;
DFWORD(result, 0)=num.sign;
return decInfinity(result, result); }
num.exponent=GETEXPUN(dfl)-GETEXPUN(dfr); if (DFISZERO(dfl)) { if (op&DIVIDEINT) {
decFloatZero(result);
DFWORD(result, 0)|=num.sign; return result;
}
if (!(op&DIVIDE)) { num.exponent=MINI(GETEXPUN(dfl), GETEXPUN(dfr));
num.sign=DFWORD(dfl, 0)&DECFLOAT_Sign;
}
bcdacc[0]=0;
num.msd=bcdacc; num.lsd=bcdacc; return decFinalize(result, &num, set); }
GETCOEFFBILL(dfl, acc+DIVACCLEN-DIVOPLEN);
GETCOEFFBILL(dfr, div);
acc[0]=0;
acc[1]=0;
acc[2]=0;
acc[3]=0;
#if DOUBLE
#if DIVOPLEN!=2
#error Unexpected Double DIVOPLEN
#endif
#elif QUAD
acc[4]=0;
acc[5]=0;
acc[6]=0;
acc[7]=0;
#if DIVOPLEN!=4
#error Unexpected Quad DIVOPLEN
#endif
#endif
msua=acc+DIVACCLEN-1; msuq=quo+DIVOPLEN;
for (msud=div+DIVOPLEN-1; *msud==0;) msud--;
divunits=(Int)(msud-div+1); lsua=msua-divunits+1; lsuq=msuq;
divtop=*msud<<2;
if (divunits>1) {
uInt *um=msud-1;
uInt d=*um;
if (d>=750000000) {divtop+=3; d-=750000000;}
else if (d>=500000000) {divtop+=2; d-=500000000;}
else if (d>=250000000) {divtop++; d-=250000000;}
if (d) divtop++;
else for (um--; um>=div; um--) if (*um) {
divtop++;
break;
}
}
#if DECTRACE
{Int i;
printf("----- div=");
for (i=divunits-1; i>=0; i--) printf("%09ld ", (LI)div[i]);
printf("\n");}
#endif
quodigits=0; for (;; lsua--) { #if DECCHECK
if (lsua<acc) {
printf("Acc underrun...\n");
break;
}
#endif
#if DECTRACE
printf("Outer: quodigits=%ld acc=", (LI)quodigits);
for (ua=msua; ua>=lsua; ua--) printf("%09ld ", (LI)*ua);
printf("\n");
#endif
*lsuq=0; for (;;) { for (; *msua==0 && msua>=lsua;) msua--;
accunits=(Int)(msua-lsua+1); if (accunits<divunits) {
if (accunits==0) msua++; break;
}
if (accunits==divunits) {
for (ud=msud, ua=msua; ud>div; ud--, ua--) if (*ud!=*ua) break;
if (*ud>*ua) break; if (*ud==*ua) { *lsuq+=1; msua=lsua; *msua=0; break;
}
#define DIVLO 1000000U
#define DIVHI (DIVBASE/DIVLO)
#if DECUSE64
if (divunits>1) {
uLong mul=(uLong)*msua * DIVBASE + *(msua-1);
uLong div=(uLong)*msud * DIVBASE + *(msud-1);
#if QUAD
if (divunits>2) div++;
#endif
mul/=div;
multiplier=(Int)mul;
}
else multiplier=*msua/(*msud);
#else
if (divunits>1 && *msua<DIVLO && *msud<DIVLO) {
multiplier=(*msua*DIVHI + *(msua-1)/DIVLO)
/(*msud*DIVHI + *(msud-1)/DIVLO +1);
}
else multiplier=(*msua<<2)/divtop;
#endif
}
else { #if DECUSE64
uLong mul;
if (divunits>1 && *msua<DIVLO && *msud<DIVLO) {
mul=((uLong)*msua * DIVHI * DIVBASE) + *(msua-1) * DIVHI
+ *(msua-2)/DIVLO;
mul/=(*msud*DIVHI + *(msud-1)/DIVLO +1);
}
else if (divunits==1) {
mul=(uLong)*msua * DIVBASE + *(msua-1);
mul/=*msud; }
else {
mul=(uLong)(*msua) * (uInt)(DIVBASE<<2)
+ (*(msua-1)<<2);
mul/=divtop; }
multiplier=(Int)mul;
#else
multiplier=*msua * ((DIVBASE<<2)/divtop);
#endif
}
if (multiplier==0) multiplier=1; *lsuq+=multiplier;
#if DIVCOUNT
divcount++;
#endif
#define DIVMAGIC 2305843009U
#define DIVSHIFTA 29
#define DIVSHIFTB 32
carry=0;
for (ud=div, ua=lsua; ud<=msud; ud++, ua++) {
uInt lo, hop;
#if DECUSE64
uLong sub=(uLong)multiplier*(*ud)+carry;
if (sub<DIVBASE) {
carry=0;
lo=(uInt)sub;
}
else {
hop=(uInt)(sub>>DIVSHIFTA);
carry=(uInt)(((uLong)hop*DIVMAGIC)>>DIVSHIFTB);
lo=(uInt)sub;
lo-=carry*DIVBASE; if (lo>=DIVBASE) {
lo-=DIVBASE; carry++;
}
}
#else
uInt hi;
LONGMUL32HI(hi, *ud, multiplier); lo=multiplier*(*ud); lo+=carry; carry=hi+(lo<carry); if (carry || lo>=DIVBASE) { hop=(carry<<3)+(lo>>DIVSHIFTA); LONGMUL32HI(carry, hop, DIVMAGIC); lo-=(carry*DIVBASE);
if (lo>=DIVBASE) {
lo-=DIVBASE;
carry++;
}
}
#endif
if (lo>*ua) { *ua+=DIVBASE;
carry++;
}
*ua-=lo;
} if (carry) *ua-=carry; }
#if DECTRACE
if (*lsuq || quodigits) printf("*lsuq=%09ld\n", (LI)*lsuq);
#endif
if (quodigits) {
quodigits+=9; lsuq--;
if (quodigits>DECPMAX+1) break; }
else if (*lsuq) { const uInt *pow;
for (pow=DECPOWERS; *lsuq>=*pow; pow++) quodigits++;
lsuq--;
}
if (*msua!=0) continue; if (lsua>acc+DIVACCLEN-DIVOPLEN) continue;
for (; msua>lsua && *msua==0;) msua--;
if (*msua==0 && msua==lsua) break;
}
lsuq++; if (*msua) *lsuq|=1;
#if DECTRACE
printf("DivQuo:");
for (uq=msuq; uq>=lsuq; uq--) printf(" %09ld", (LI)*uq);
printf("\n");
#endif
for (uq=msuq, ub=bcdacc+1; uq>=lsuq; uq--, ub+=9) {
uInt top, mid, rem; if (*uq==0) { UBFROMUI(ub, 0); UBFROMUI(ub+4, 0); *(ub+8)=0; continue;
}
#define divsplit9 1000000
#define divsplit6 1000
top=*uq/divsplit9;
rem=*uq%divsplit9;
mid=rem/divsplit6;
rem=rem%divsplit6;
UBFROMUI(ub, UBTOUI(&BIN2BCD8[top*4]));
UBFROMUI(ub+3, UBTOUI(&BIN2BCD8[mid*4]));
UBFROMUI(ub+6, UBTOUI(&BIN2BCD8[rem*4]));
} ub--;
num.msd=bcdacc+1+(msuq-lsuq+1)*9-quodigits;
num.lsd=ub;
if (lsua<acc+DIVACCLEN-DIVOPLEN) { num.exponent-=(Int)((acc+DIVACCLEN-DIVOPLEN-lsua)*9);
if (*msua==0) {
for (; *ub==0;) ub--; num.exponent+=(Int)(num.lsd-ub); num.lsd=ub;
}
}
#if DIVCOUNT
if (divcount>maxcount) { maxcount=divcount;
printf("DivNewMaxCount: %ld\n", (LI)maxcount);
}
#endif
if (op&DIVIDE) return decFinalize(result, &num, set);
length=(Int)(num.lsd-num.msd+1);
if (length+num.exponent>DECPMAX) { decFloatZero(result);
DFWORD(result, 0)=DECFLOAT_qNaN;
set->status|=DEC_Division_impossible;
return result;
}
if (num.exponent>=0) { for (ub=num.lsd+1; ub<=num.lsd+num.exponent; ub++) *ub=0;
num.lsd+=num.exponent;
}
else { Int drop=-num.exponent;
if (!(op&REMNEAR)) { num.lsd-=drop;
if (num.lsd<num.msd) { num.lsd=num.msd; *num.lsd=0; }
}
else { uByte *roundat; uByte reround; *(num.msd-1)=0; if (drop<length) roundat=num.lsd-drop+1;
else if (drop==length) roundat=num.msd;
else roundat=num.msd-1; reround=*roundat;
for (ub=roundat+1; ub<=num.lsd; ub++) {
if (*ub!=0) {
reround=DECSTICKYTAB[reround];
break;
}
} if (roundat>num.msd) num.lsd=roundat-1;
else {
num.msd--; num.lsd=num.msd; }
if (reround!=0) { uInt bump=0;
if (reround>5) bump=1; else if (reround==5) bump=*(num.lsd) & 0x01; if (bump!=0) { ub=num.lsd;
for (; UBTOUI(ub-3)==0x09090909; ub-=4) UBFROMUI(ub-3, 0);
for (; *ub==9; ub--) *ub=0; *ub+=1;
if (ub<num.msd) num.msd--; } } } } num.exponent=0;
if (op&DIVIDEINT) return decFinalize(result, &num, set);
decFinalize("ient, &num, set); DFWORD("ient, 0)^=DECFLOAT_Sign; sign=DFWORD(dfl, 0); decFloatFMA(result, "ient, dfr, dfl, set);
if (!DFISZERO(result)) return result;
DFWORD("ient, 0)=sign; return decFloatCopySign(result, result, "ient);
}
#define MULTBASE ((uInt)BILLION)
#define MULOPLEN DECPMAX9
#define MULACCLEN (MULOPLEN*2)
#define LEADZEROS (MULACCLEN*9 - DECPMAX*2)
#if DECEMAXD>9
#error Exponent may overflow when doubled for Multiply
#endif
#if MULACCLEN!=(MULACCLEN/4)*4
#error MULACCLEN is not a multiple of 4
#endif
static void decFiniteMultiply(bcdnum *num, uByte *bcdacc,
const decFloat *dfl, const decFloat *dfr) {
uInt bufl[MULOPLEN]; uInt bufr[MULOPLEN]; uInt *ui, *uj; uByte *ub; uInt uiwork;
#if DECUSE64
uLong accl[MULACCLEN]; uLong *pl; uInt acc[MULACCLEN]; #else
uInt acc[MULACCLEN*2]; #endif
uInt *pa;
num->sign=(DFWORD(dfl, 0)^DFWORD(dfr, 0)) & DECFLOAT_Sign;
num->exponent=GETEXPUN(dfl)+GETEXPUN(dfr);
GETCOEFFBILL(dfl, bufl);
GETCOEFFBILL(dfr, bufr);
#if DECTRACE && 0
printf("CoeffbL:");
for (ui=bufl+MULOPLEN-1; ui>=bufl; ui--) printf(" %08lx", (LI)*ui);
printf("\n");
printf("CoeffbR:");
for (uj=bufr+MULOPLEN-1; uj>=bufr; uj--) printf(" %08lx", (LI)*uj);
printf("\n");
#endif
#if DECUSE64
#if MULACCLEN==4
accl[0]=0; accl[1]=0; accl[2]=0; accl[3]=0;
#else
for (pl=accl; pl<accl+MULACCLEN; pl+=4) {
*pl=0; *(pl+1)=0; *(pl+2)=0; *(pl+3)=0; } #endif
for (ui=bufr; ui<bufr+MULOPLEN; ui++) { if (*ui==0) continue; pl=accl+(ui-bufr); for (uj=bufl; uj<bufl+MULOPLEN; uj++, pl++) { *pl+=((uLong)*ui)*(*uj);
} }
#define MULMAGIC 2305843009U
#if DOUBLE
#define MULSHIFTA 29
#define MULSHIFTB 32
#elif QUAD
#define MULSHIFTA 30
#define MULSHIFTB 31
#else
#error Unexpected type
#endif
#if DECTRACE
printf("MulAccl:");
for (pl=accl+MULACCLEN-1; pl>=accl; pl--)
printf(" %08lx:%08lx", (LI)(*pl>>32), (LI)(*pl&0xffffffff));
printf("\n");
#endif
for (pl=accl, pa=acc; pl<accl+MULACCLEN; pl++, pa++) { uInt lo, hop; uInt est; if (*pl>=MULTBASE) {
hop=(uInt)(*pl>>MULSHIFTA);
est=(uInt)(((uLong)hop*MULMAGIC)>>MULSHIFTB);
lo=(uInt)(*pl-((uLong)est*MULTBASE)); if (lo>=MULTBASE) {
lo-=MULTBASE; est++;
#if QUAD
if (lo>=MULTBASE) {
lo-=MULTBASE;
est++;
}
#endif
}
*pa=lo;
*(pl+1)+=est;
} else { *pa=(uInt)*pl; }
}
#else
for (pa=acc;; pa+=4) { *pa=0; *(pa+1)=0; *(pa+2)=0; *(pa+3)=0; if (pa==acc+MULACCLEN*2-4) break; }
for (ui=bufr;; ui++) { uInt hi, lo; pa=acc+(ui-bufr); for (uj=bufl;; uj++, pa++) { LONGMUL32HI(hi, *ui, *uj); lo=(*ui)*(*uj); *pa+=lo; *(pa+MULACCLEN)+=hi+(*pa<lo); if (uj==bufl+MULOPLEN-1) break;
}
if (ui==bufr+MULOPLEN-1) break;
}
#define MULMAGIC 2305843009U
#if DOUBLE
#define MULSHIFTA 29
#define MULSHIFTB 32
#elif QUAD
#define MULSHIFTA 30
#define MULSHIFTB 31
#else
#error Unexpected type
#endif
#if DECTRACE
printf("MulHiLo:");
for (pa=acc+MULACCLEN-1; pa>=acc; pa--)
printf(" %08lx:%08lx", (LI)*(pa+MULACCLEN), (LI)*pa);
printf("\n");
#endif
for (pa=acc;; pa++) { uInt hi, lo; uInt hop, estlo; #if QUAD
uInt esthi; #endif
lo=*pa;
hi=*(pa+MULACCLEN);
#if DOUBLE
hop=(hi<<3)+(lo>>MULSHIFTA); LONGMUL32HI(estlo, hop, MULMAGIC); lo-=(estlo*MULTBASE);
if (lo>=MULTBASE) {
lo-=MULTBASE;
estlo++;
}
#elif QUAD
hop=(hi<<2)+(lo>>MULSHIFTA); LONGMUL32HI(esthi, hop, MULMAGIC); estlo=hop*MULMAGIC; estlo=(esthi<<1)+(estlo>>MULSHIFTB); lo-=(estlo*MULTBASE); if (lo>=MULTBASE) {
lo-=MULTBASE;
estlo++;
}
if (lo>=MULTBASE) {
lo-=MULTBASE;
estlo++;
}
#else
#error Unexpected type
#endif
*pa=lo;
*(pa+1)+=estlo;
if (*(pa+1)<estlo) *(pa+1+MULACCLEN)+=1; if (pa==acc+MULACCLEN-2) break; } #endif
#if DECTRACE
printf("MultAcc:");
for (pa=acc+MULACCLEN-1; pa>=acc; pa--) printf(" %09ld", (LI)*pa);
printf("\n");
#endif
pa=acc+MULACCLEN-1;
if (*pa!=0) num->msd=bcdacc+LEADZEROS; else { num->msd=bcdacc; pa--; for (; *pa==0; pa--) if (pa==acc) break; }
for (ub=bcdacc;; pa--, ub+=9) {
if (*pa!=0) { uInt top, mid, rem; #define mulsplit9 1000000
#define mulsplit6 1000
top=*pa/mulsplit9;
rem=*pa%mulsplit9;
mid=rem/mulsplit6;
rem=rem%mulsplit6;
UBFROMUI(ub, UBTOUI(&BIN2BCD8[top*4]));
UBFROMUI(ub+3, UBTOUI(&BIN2BCD8[mid*4]));
UBFROMUI(ub+6, UBTOUI(&BIN2BCD8[rem*4]));
}
else { UBFROMUI(ub, 0); UBFROMUI(ub+4, 0); *(ub+8)=0; }
if (pa==acc) break;
}
num->lsd=ub+8;
#if DECTRACE
decShowNum(num, "postmult");
decFloatShow(dfl, "dfl");
decFloatShow(dfr, "dfr");
#endif
return;
}
decFloat * decFloatAbs(decFloat *result, const decFloat *df,
decContext *set) {
if (DFISNAN(df)) return decNaNs(result, df, NULL, set);
decCanonical(result, df); DFBYTE(result, 0)&=~0x80; return result;
}
#if QUAD
const Int DECTESTMSD[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, -32, -128,
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, -32, -128};
#else
extern const Int DECTESTMSD[64];
#endif
decFloat * decFloatAdd(decFloat *result,
const decFloat *dfl, const decFloat *dfr,
decContext *set) {
bcdnum num; Int bexpl, bexpr; uByte *ub, *us, *ut; uInt uiwork; #if QUAD
uShort uswork; #endif
uInt sourhil, sourhir; uInt diffsign; uInt carry; Int overlap; Int summ; uByte acc[4+2+DECPMAX*3+8];
uByte buf[4+2+DECPMAX*2];
uByte *umsd, *ulsd;
#if DECLITEND
#define CARRYPAT 0x01000000
#else
#define CARRYPAT 0x00000001
#endif
sourhil=DFWORD(dfl, 0); summ=DECTESTMSD[sourhil>>26]; bexpr=DECCOMBEXP[sourhil>>26]; bexpr+=GETECON(dfl);
sourhir=DFWORD(dfr, 0); summ+=DECTESTMSD[sourhir>>26]; bexpl=DECCOMBEXP[sourhir>>26];
bexpl+=GETECON(dfr);
diffsign=(sourhil^sourhir)&DECFLOAT_Sign;
if (summ<=8) { if (summ<0) { if (summ<-64) return decNaNs(result, dfl, dfr, set); if (summ==-64 && diffsign) return decInvalid(result, set);
if (DFISINF(dfl)) return decInfinity(result, dfl); return decInfinity(result, dfr); }
if (bexpr==bexpl && !diffsign) {
uInt tac[DECLETS+1]; uInt encode;
GETCOEFFTHOU(dfl, tac); ADDCOEFFTHOU(dfr, tac);
encode =BIN2DPD[tac[0]];
encode|=BIN2DPD[tac[1]]<<10;
encode|=BIN2DPD[tac[2]]<<20;
encode|=BIN2DPD[tac[3]]<<30;
DFWORD(result, (DECBYTES/4)-1)=encode;
encode =BIN2DPD[tac[3]]>>2;
encode|=BIN2DPD[tac[4]]<<8;
#if QUAD
encode|=BIN2DPD[tac[5]]<<18;
encode|=BIN2DPD[tac[6]]<<28;
DFWORD(result, 2)=encode;
encode =BIN2DPD[tac[6]]>>4;
encode|=BIN2DPD[tac[7]]<<6;
encode|=BIN2DPD[tac[8]]<<16;
encode|=BIN2DPD[tac[9]]<<26;
DFWORD(result, 1)=encode;
encode =BIN2DPD[tac[9]]>>6;
encode|=BIN2DPD[tac[10]]<<4;
#endif
encode|=sourhil & (ECONMASK | DECFLOAT_Sign);
tac[DECLETS]|=(bexpl>>DECECONL)<<4;
encode|=DECCOMBFROM[tac[DECLETS]]; DFWORD(result, 0)=encode;
return result;
} }
if (bexpl<=bexpr) {
Int bexpswap=bexpl;
bexpl=bexpr;
bexpr=bexpswap;
}
else {
const decFloat *dfswap=dfl;
dfl=dfr;
dfr=dfswap;
}
if (DFISZERO(dfl)) {
decCanonical(result, dfr); if (diffsign && DFISZERO(result)) {
DFWORD(result, 0)&=~DECFLOAT_Sign; if (set->round==DEC_ROUND_FLOOR) DFWORD(result, 0)|=DECFLOAT_Sign;
}
return result;
}
#if DOUBLE
#define COFF 4
#elif QUAD
UBFROMUS(acc+4, 0); #define COFF 6
#endif
GETCOEFF(dfl, acc+COFF); ulsd=acc+COFF+DECPMAX-1;
umsd=acc+4;
#if DECTRACE
{bcdnum tum;
tum.msd=umsd;
tum.lsd=ulsd;
tum.exponent=bexpl-DECBIAS;
tum.sign=DFWORD(dfl, 0) & DECFLOAT_Sign;
decShowNum(&tum, "dflx");}
#endif
carry=0; if (diffsign) {
carry=CARRYPAT; UBFROMUI(acc+ 4, 0x09090909-UBTOUI(acc+ 4));
UBFROMUI(acc+ 8, 0x09090909-UBTOUI(acc+ 8));
UBFROMUI(acc+12, 0x09090909-UBTOUI(acc+12));
UBFROMUI(acc+16, 0x09090909-UBTOUI(acc+16));
#if QUAD
UBFROMUI(acc+20, 0x09090909-UBTOUI(acc+20));
UBFROMUI(acc+24, 0x09090909-UBTOUI(acc+24));
UBFROMUI(acc+28, 0x09090909-UBTOUI(acc+28));
UBFROMUI(acc+32, 0x09090909-UBTOUI(acc+32));
UBFROMUI(acc+36, 0x09090909-UBTOUI(acc+36));
#endif
}
overlap=DECPMAX-(bexpl-bexpr);
#if DECTRACE
printf("exps: %ld %ld\n", (LI)(bexpl-DECBIAS), (LI)(bexpr-DECBIAS));
printf("Overlap=%ld carry=%08lx\n", (LI)overlap, (LI)carry);
#endif
if (overlap<=0) { uInt gap; if (carry) {
for (ub=ulsd; *ub==9; ub--) *ub=0;
*ub+=1;
carry=0; }
gap=-overlap;
if (gap>DECPMAX) {
bexpr+=gap-1;
gap=DECPMAX;
}
ub=ulsd+gap+1; ut=acc+COFF+DECPMAX; for (; ut<ub; ut+=4) UBFROMUI(ut, 0); if (overlap<-DECPMAX) { *ub=(uByte)(!DFISZERO(dfr)); }
else { GETCOEFF(dfr, ub); ub+=DECPMAX-1; }
ulsd=ub; }
else { if (overlap==DECPMAX) { ub=buf+COFF; #if QUAD
UBFROMUS(buf+4, 0); #endif
GETCOEFF(dfr, ub); }
else { ub=buf+COFF+DECPMAX-overlap; UBFROMUI(buf+4, 0); UBFROMUI(buf+8, 0);
if (ub>buf+12) {
ut=buf+12; for (; ut<ub; ut+=4) UBFROMUI(ut, 0); }
GETCOEFF(dfr, ub);
UBFROMUI(acc+COFF+DECPMAX, UBTOUI(buf+COFF+DECPMAX));
UBFROMUI(acc+COFF+DECPMAX+4, UBTOUI(buf+COFF+DECPMAX+4));
if (buf+COFF+DECPMAX+8<ub+DECPMAX) {
us=buf+COFF+DECPMAX+8; ut=acc+COFF+DECPMAX+8; for (; us<ub+DECPMAX; us+=4, ut+=4) UBFROMUI(ut, UBTOUI(us));
}
}
ulsd=acc+(ub-buf+DECPMAX-1);
ut=acc+COFF+DECPMAX-4; us=buf+COFF+DECPMAX-4;
#if !DECLITEND
for (; ut>=acc+4; ut-=4, us-=4) { carry+=UBTOUI(us); if (carry==0) continue; carry+=UBTOUI(ut); carry+=0x76f6f6f6; UBFROMUI(ut, (carry & 0x0f0f0f0f) - ((carry & 0x60606060)>>4));
carry>>=31; } #else
for (; ut>=acc+4; ut-=4, us-=4) { carry+=UBTOUI(us); if (carry==0) continue; carry+=UBTOUI(ut); carry+=0x76767676; carry+=(carry & 0x80000000)>>15;
carry+=(carry & 0x00800000)>>15;
carry+=(carry & 0x00008000)>>15;
carry-=(carry & 0x60606060)>>4; UBFROMUI(ut, carry & 0x0f0f0f0f); carry=(carry & 0x00000080)<<17;
} #endif
#if DECTRACE
{bcdnum tum;
printf("Add done, carry=%08lx, diffsign=%ld\n", (LI)carry, (LI)diffsign);
tum.msd=umsd; tum.lsd=ulsd;
tum.exponent=0;
tum.sign=0;
decShowNum(&tum, "dfadd");}
#endif
}
if (diffsign) { if (!carry) { num.sign=DFWORD(dfl, 0) & DECFLOAT_Sign;
#if !DECLITEND
*(ulsd+1)=0;
#endif
UBFROMUI(umsd, 0x09090909-UBTOUI(umsd));
UBFROMUI(umsd+4, 0x09090909-UBTOUI(umsd+4));
UBFROMUI(umsd+8, 0x09090909-UBTOUI(umsd+8));
UBFROMUI(umsd+12, 0x09090909-UBTOUI(umsd+12));
#if DOUBLE
#define BNEXT 16
#elif QUAD
UBFROMUI(umsd+16, 0x09090909-UBTOUI(umsd+16));
UBFROMUI(umsd+20, 0x09090909-UBTOUI(umsd+20));
UBFROMUI(umsd+24, 0x09090909-UBTOUI(umsd+24));
UBFROMUI(umsd+28, 0x09090909-UBTOUI(umsd+28));
UBFROMUI(umsd+32, 0x09090909-UBTOUI(umsd+32));
#define BNEXT 36
#endif
if (ulsd>=umsd+BNEXT) { UBFROMUI(umsd+BNEXT, 0x09090909-UBTOUI(umsd+BNEXT));
UBFROMUI(umsd+BNEXT+4, 0x09090909-UBTOUI(umsd+BNEXT+4));
#if DOUBLE
#define BNEXTY (BNEXT+8)
#elif QUAD
UBFROMUI(umsd+BNEXT+8, 0x09090909-UBTOUI(umsd+BNEXT+8));
UBFROMUI(umsd+BNEXT+12, 0x09090909-UBTOUI(umsd+BNEXT+12));
#define BNEXTY (BNEXT+16)
#endif
if (ulsd>=umsd+BNEXTY) { ut=umsd+BNEXTY; for (;;ut+=4) {
UBFROMUI(ut, 0x09090909-UBTOUI(ut)); if (ut>=ulsd-3) break; }
}
}
for (ub=ulsd; *ub==9; ub--) *ub=0;
*ub+=1;
}
else { num.sign=DFWORD(dfr, 0) & DECFLOAT_Sign;
if (ISCOEFFZERO(acc+COFF)) {
umsd=acc+COFF+DECPMAX-1; if (ulsd>umsd) { umsd++; for (; UBTOUI(umsd)==0 && umsd+3<ulsd;) umsd+=4;
for (; *umsd==0 && umsd<ulsd;) umsd++;
}
if (*umsd==0) { num.sign=0; if (set->round==DEC_ROUND_FLOOR) num.sign=DECFLOAT_Sign;
}
}
} }
else { num.sign=DFWORD(dfl, 0)&DECFLOAT_Sign;
#if DOUBLE
if (carry) { *(acc+3)=1; umsd=acc+3;
}
#endif
}
num.msd=umsd; num.lsd=ulsd; num.exponent=bexpr-DECBIAS;
#if DECTRACE
decFloatShow(dfl, "dfl");
decFloatShow(dfr, "dfr");
decShowNum(&num, "postadd");
#endif
return decFinalize(result, &num, set); }
decFloat * decFloatAnd(decFloat *result,
const decFloat *dfl, const decFloat *dfr,
decContext *set) {
if (!DFISUINT01(dfl) || !DFISUINT01(dfr)
|| !DFISCC01(dfl) || !DFISCC01(dfr)) return decInvalid(result, set);
#if DOUBLE
DFWORD(result, 0)=ZEROWORD
|((DFWORD(dfl, 0) & DFWORD(dfr, 0))&0x04009124);
DFWORD(result, 1)=(DFWORD(dfl, 1) & DFWORD(dfr, 1))&0x49124491;
#elif QUAD
DFWORD(result, 0)=ZEROWORD
|((DFWORD(dfl, 0) & DFWORD(dfr, 0))&0x04000912);
DFWORD(result, 1)=(DFWORD(dfl, 1) & DFWORD(dfr, 1))&0x44912449;
DFWORD(result, 2)=(DFWORD(dfl, 2) & DFWORD(dfr, 2))&0x12449124;
DFWORD(result, 3)=(DFWORD(dfl, 3) & DFWORD(dfr, 3))&0x49124491;
#endif
return result;
}
decFloat * decFloatCanonical(decFloat *result, const decFloat *df) {
return decCanonical(result, df);
}
enum decClass decFloatClass(const decFloat *df) {
Int exp; if (DFISSPECIAL(df)) {
if (DFISQNAN(df)) return DEC_CLASS_QNAN;
if (DFISSNAN(df)) return DEC_CLASS_SNAN;
if (DFISSIGNED(df)) return DEC_CLASS_NEG_INF;
return DEC_CLASS_POS_INF;
}
if (DFISZERO(df)) { if (DFISSIGNED(df)) return DEC_CLASS_NEG_ZERO;
return DEC_CLASS_POS_ZERO;
}
exp=GETEXPUN(df) +decFloatDigits(df)-1; if (exp>=DECEMIN) { if (DFISSIGNED(df)) return DEC_CLASS_NEG_NORMAL;
return DEC_CLASS_POS_NORMAL;
}
if (DFISSIGNED(df)) return DEC_CLASS_NEG_SUBNORMAL;
return DEC_CLASS_POS_SUBNORMAL;
}
const char *decFloatClassString(const decFloat *df) {
enum decClass eclass=decFloatClass(df);
if (eclass==DEC_CLASS_POS_NORMAL) return DEC_ClassString_PN;
if (eclass==DEC_CLASS_NEG_NORMAL) return DEC_ClassString_NN;
if (eclass==DEC_CLASS_POS_ZERO) return DEC_ClassString_PZ;
if (eclass==DEC_CLASS_NEG_ZERO) return DEC_ClassString_NZ;
if (eclass==DEC_CLASS_POS_SUBNORMAL) return DEC_ClassString_PS;
if (eclass==DEC_CLASS_NEG_SUBNORMAL) return DEC_ClassString_NS;
if (eclass==DEC_CLASS_POS_INF) return DEC_ClassString_PI;
if (eclass==DEC_CLASS_NEG_INF) return DEC_ClassString_NI;
if (eclass==DEC_CLASS_QNAN) return DEC_ClassString_QN;
if (eclass==DEC_CLASS_SNAN) return DEC_ClassString_SN;
return DEC_ClassString_UN; }
decFloat * decFloatCompare(decFloat *result,
const decFloat *dfl, const decFloat *dfr,
decContext *set) {
Int comp; if (DFISNAN(dfl) || DFISNAN(dfr)) return decNaNs(result, dfl, dfr, set);
comp=decNumCompare(dfl, dfr, 0);
decFloatZero(result);
if (comp==0) return result;
DFBYTE(result, DECBYTES-1)=0x01; if (comp<0) DFBYTE(result, 0)|=0x80; return result;
}
decFloat * decFloatCompareSignal(decFloat *result,
const decFloat *dfl, const decFloat *dfr,
decContext *set) {
Int comp; if (DFISNAN(dfl) || DFISNAN(dfr)) {
set->status|=DEC_Invalid_operation;
return decNaNs(result, dfl, dfr, set);
}
comp=decNumCompare(dfl, dfr, 0);
decFloatZero(result);
if (comp==0) return result;
DFBYTE(result, DECBYTES-1)=0x01; if (comp<0) DFBYTE(result, 0)|=0x80; return result;
}
decFloat * decFloatCompareTotal(decFloat *result,
const decFloat *dfl, const decFloat *dfr) {
Int comp; uInt uiwork; #if QUAD
uShort uswork; #endif
if (DFISNAN(dfl) || DFISNAN(dfr)) {
Int nanl, nanr; nanl=DFISSNAN(dfl)+DFISQNAN(dfl)*2; if (DFISSIGNED(dfl)) nanl=-nanl;
nanr=DFISSNAN(dfr)+DFISQNAN(dfr)*2;
if (DFISSIGNED(dfr)) nanr=-nanr;
if (nanl>nanr) comp=+1;
else if (nanl<nanr) comp=-1;
else { uByte bufl[DECPMAX+4]; uByte bufr[DECPMAX+4]; uByte *ub, *uc; Int sigl; sigl=(DFISSIGNED(dfl) ? -1 : +1);
#if QUAD
UBFROMUS(bufl, 0);
UBFROMUS(bufr, 0);
#endif
GETCOEFF(dfl, bufl+QUAD*2); GETCOEFF(dfr, bufr+QUAD*2); comp=0; for (ub=bufl, uc=bufr; ub<bufl+DECPMAX+QUAD*2; ub+=4, uc+=4) {
uInt ui=UBTOUI(ub);
if (ui==UBTOUI(uc)) continue; for (;; ub++, uc++) {
if (*ub==*uc) continue;
if (*ub>*uc) comp=sigl; else comp=-sigl; break;
}
}
} }
else {
comp=decNumCompare(dfl, dfr, 1); }
decFloatZero(result);
if (comp==0) return result;
DFBYTE(result, DECBYTES-1)=0x01; if (comp<0) DFBYTE(result, 0)|=0x80; return result;
}
decFloat * decFloatCompareTotalMag(decFloat *result,
const decFloat *dfl, const decFloat *dfr) {
decFloat a, b; if (DFISSIGNED(dfl)) {
decFloatCopyAbs(&a, dfl);
dfl=&a;
}
if (DFISSIGNED(dfr)) {
decFloatCopyAbs(&b, dfr);
dfr=&b;
}
return decFloatCompareTotal(result, dfl, dfr);
}
decFloat * decFloatCopy(decFloat *result, const decFloat *dfl) {
if (dfl!=result) *result=*dfl; return result;
}
decFloat * decFloatCopyAbs(decFloat *result, const decFloat *dfl) {
if (dfl!=result) *result=*dfl; DFBYTE(result, 0)&=~0x80; return result;
}
decFloat * decFloatCopyNegate(decFloat *result, const decFloat *dfl) {
if (dfl!=result) *result=*dfl; DFBYTE(result, 0)^=0x80; return result;
}
decFloat * decFloatCopySign(decFloat *result,
const decFloat *dfl, const decFloat *dfr) {
uByte sign=(uByte)(DFBYTE(dfr, 0)&0x80); if (dfl!=result) *result=*dfl; DFBYTE(result, 0)&=~0x80; DFBYTE(result, 0)=(uByte)(DFBYTE(result, 0)|sign); return result;
}
#define dpdlenchk(n, form) dpd=(form)&0x3ff; \
if (dpd) return (DECPMAX-1-3*(n))-(3-DPD2BCD8[dpd*4+3])
#define dpdlendun(n, form) dpd=(form)&0x3ff; \
if (dpd==0) return 1; \
return (DECPMAX-1-3*(n))-(3-DPD2BCD8[dpd*4+3])
uInt decFloatDigits(const decFloat *df) {
uInt dpd; uInt sourhi=DFWORD(df, 0); #if QUAD
uInt sourmh, sourml;
#endif
uInt sourlo;
if (DFISINF(df)) return 1;
if (!DFISNAN(df) && DECCOMBMSD[sourhi>>26]) return DECPMAX;
#if DOUBLE
if (sourhi&0x0003ffff) { dpdlenchk(0, sourhi>>8);
sourlo=DFWORD(df, 1);
dpdlendun(1, (sourhi<<2) | (sourlo>>30));
} sourlo=DFWORD(df, 1); if (sourlo&0xfff00000) { dpdlenchk(1, sourlo>>30); dpdlendun(2, sourlo>>20);
} dpdlenchk(3, sourlo>>10);
dpdlendun(4, sourlo);
#elif QUAD
if (sourhi&0x00003fff) { dpdlenchk(0, sourhi>>4);
sourmh=DFWORD(df, 1);
dpdlendun(1, ((sourhi)<<6) | (sourmh>>26));
} sourmh=DFWORD(df, 1);
if (sourmh) {
dpdlenchk(1, sourmh>>26);
dpdlenchk(2, sourmh>>16);
dpdlenchk(3, sourmh>>6);
sourml=DFWORD(df, 2);
dpdlendun(4, ((sourmh)<<4) | (sourml>>28));
} sourml=DFWORD(df, 2);
if (sourml) {
dpdlenchk(4, sourml>>28);
dpdlenchk(5, sourml>>18);
dpdlenchk(6, sourml>>8);
sourlo=DFWORD(df, 3);
dpdlendun(7, ((sourml)<<2) | (sourlo>>30));
} sourlo=DFWORD(df, 3);
if (sourlo&0xfff00000) { dpdlenchk(7, sourlo>>30); dpdlendun(8, sourlo>>20);
} dpdlenchk(9, sourlo>>10);
dpdlendun(10, sourlo);
#endif
}
decFloat * decFloatDivide(decFloat *result,
const decFloat *dfl, const decFloat *dfr,
decContext *set) {
return decDivide(result, dfl, dfr, set, DIVIDE);
}
decFloat * decFloatDivideInteger(decFloat *result,
const decFloat *dfl, const decFloat *dfr,
decContext *set) {
return decDivide(result, dfl, dfr, set, DIVIDEINT);
}
decFloat * decFloatFMA(decFloat *result, const decFloat *dfl,
const decFloat *dfr, const decFloat *dff,
decContext *set) {
#define FMALEN (ROUNDUP4(1+ (DECPMAX9*18+1) +DECPMAX+2))
uByte acc[FMALEN]; bcdnum mul; bcdnum fin; uByte coe[ROUNDUP4(DECPMAX)]; bcdnum *hi, *lo; uInt diffsign; uInt hipad; Int padding; uInt carry; uByte *ub, *uh, *ul; uInt uiwork;
if (DFISSPECIAL(dfl) || DFISSPECIAL(dfr) || DFISSPECIAL(dff)) {
decFloat proxy; if (DFISSNAN(dfl) || DFISSNAN(dfr)) return decNaNs(result, dfl, dfr, set);
if (DFISSNAN(dff)) return decNaNs(result, dff, NULL, set);
if (DFISNAN(dfl) || DFISNAN(dfr)) return decNaNs(result, dfl, dfr, set);
if (DFISNAN(dff)) return decNaNs(result, dff, NULL, set);
decFloatZero(&proxy);
if (DFISINF(dfl)) {
if (DFISZERO(dfr)) return decInvalid(result, set);
decInfinity(&proxy, &proxy);
}
else if (DFISINF(dfr)) {
if (DFISZERO(dfl)) return decInvalid(result, set);
decInfinity(&proxy, &proxy);
}
DFWORD(&proxy, 0)|=(DFWORD(dfl, 0)^DFWORD(dfr, 0))&DECFLOAT_Sign;
if (!DFISINF(dff)) return decFloatCopy(result, &proxy);
if (!DFISINF(&proxy)) return decInfinity(result, dff);
if ((DFWORD(dff, 0)&DECFLOAT_Sign)!=(DFWORD(&proxy, 0)&DECFLOAT_Sign))
return decInvalid(result, set);
return decFloatCopy(result, &proxy);
}
decFiniteMultiply(&mul, acc+1, dfl, dfr);
fin.exponent=GETEXPUN(dff); fin.sign=DFWORD(dff, 0)&DECFLOAT_Sign;
diffsign=mul.sign^fin.sign; fin.msd=coe;
fin.lsd=coe+DECPMAX-1;
GETCOEFF(dff, coe);
if (mul.exponent>=fin.exponent) {
hi=&mul;
lo=&fin;
}
else {
hi=&fin;
lo=&mul;
}
for (; UBTOUI(hi->msd)==0 && hi->msd+3<hi->lsd;) hi->msd+=4;
for (; *hi->msd==0 && hi->msd<hi->lsd;) hi->msd++;
for (; UBTOUI(lo->msd)==0 && lo->msd+3<lo->lsd;) lo->msd+=4;
for (; *lo->msd==0 && lo->msd<lo->lsd;) lo->msd++;
if (*hi->msd==0) { if (diffsign) {
if (*lo->msd==0) { lo->sign=0;
if (set->round==DEC_ROUND_FLOOR) lo->sign=DECFLOAT_Sign;
} } return decFinalize(result, lo, set); }
hipad=0;
carry=0;
if (diffsign) {
hipad=9;
carry=1;
for (uh=hi->msd; uh<hi->lsd-3; uh+=4) UBFROMUI(uh, 0x09090909-UBTOUI(uh));
for (; uh<=hi->lsd; uh++) *uh=(uByte)(0x09-*uh);
}
padding=hi->exponent-lo->exponent;
ub=acc+FMALEN-1; ul=lo->lsd;
if (padding!=0) {
Int hilen=(Int)(hi->lsd-hi->msd+1); Int lolen=(Int)(lo->lsd-lo->msd+1);
if (hilen+padding-lolen > DECPMAX+2) { Int newexp=MINI(hi->exponent, hi->exponent+hilen-DECPMAX)-3;
lo->lsd=lo->msd; lo->exponent=newexp; padding=hi->exponent-lo->exponent; ul=lo->lsd; }
#if DECCHECK
if (padding<=0) printf("FMA low padding: %ld\n", (LI)padding);
if (hilen+padding+1>FMALEN)
printf("FMA excess hilen+padding: %ld+%ld \n", (LI)hilen, (LI)padding);
#endif
for (; ul-3>=lo->msd && padding>3; padding-=4, ul-=4, ub-=4) {
UBFROMUI(ub-3, UBTOUI(ul-3)); }
for (; ul>=lo->msd && padding>0; padding--, ul--, ub--) *ub=*ul;
for (;padding>0; padding--, ub--) *ub=0; }
uh=hi->lsd;
for (;; ub--) {
if (uh<hi->msd || ul<lo->msd) break;
*ub=(uByte)(carry+(*uh--)+(*ul--));
carry=0;
if (*ub<10) continue;
*ub-=10;
carry=1;
}
if (ul<lo->msd) { for (;; ub--) {
if (uh<hi->msd) break;
*ub=(uByte)(carry+(*uh--)); carry=0;
if (*ub<10) continue;
*ub-=10;
carry=1;
} }
else { for (;; ub--) {
if (ul<lo->msd) break;
*ub=(uByte)(carry+hipad+(*ul--));
carry=0;
if (*ub<10) continue;
*ub-=10;
carry=1;
} }
lo->msd=ub+1;
lo->lsd=acc+FMALEN-1;
if (!diffsign) { if (carry) { *ub=1; lo->msd--; }
} else { if (!carry) { lo->sign=hi->sign; for (ul=lo->msd; ul<lo->lsd-3; ul+=4) UBFROMUI(ul, 0x09090909-UBTOUI(ul));
for (; ul<=lo->lsd; ul++) *ul=(uByte)(0x09-*ul); for (ul--; *ul==9; ul--) *ul=0;
*ul+=1;
} else { for (; UBTOUI(lo->msd)==0 && lo->msd+3<lo->lsd;) lo->msd+=4;
for (; *lo->msd==0 && lo->msd<lo->lsd;) lo->msd++;
if (*lo->msd==0) { lo->sign=0; if (set->round==DEC_ROUND_FLOOR) lo->sign=DECFLOAT_Sign;
}
} }
#if DECCHECK
if (lo->msd<acc) {
printf("FMA underrun by %ld \n", (LI)(acc-lo->msd));
}
#endif
return decFinalize(result, lo, set); }
decFloat * decFloatFromInt32(decFloat *result, Int n) {
uInt u=(uInt)n; uInt encode; DFWORD(result, 0)=ZEROWORD; #if QUAD
DFWORD(result, 1)=0;
DFWORD(result, 2)=0;
#endif
if (n<0) { u=(~u)+1;
DFWORD(result, 0)|=DECFLOAT_Sign;
}
encode=BIN2DPD[u%1000];
u/=1000;
encode|=BIN2DPD[u%1000]<<10;
u/=1000;
encode|=BIN2DPD[u%1000]<<20;
u/=1000; encode|=u<<30;
DFWORD(result, DECWORDS-1)=encode;
return result;
}
decFloat * decFloatFromUInt32(decFloat *result, uInt u) {
uInt encode; DFWORD(result, 0)=ZEROWORD; #if QUAD
DFWORD(result, 1)=0;
DFWORD(result, 2)=0;
#endif
encode=BIN2DPD[u%1000];
u/=1000;
encode|=BIN2DPD[u%1000]<<10;
u/=1000;
encode|=BIN2DPD[u%1000]<<20;
u/=1000; encode|=u<<30;
DFWORD(result, DECWORDS-1)=encode;
DFWORD(result, DECWORDS-2)|=u>>2; return result;
}
decFloat * decFloatInvert(decFloat *result, const decFloat *df,
decContext *set) {
uInt sourhi=DFWORD(df, 0);
if (!DFISUINT01(df) || !DFISCC01(df)) return decInvalid(result, set);
#if DOUBLE
DFWORD(result, 0)=ZEROWORD|((~sourhi)&0x04009124);
DFWORD(result, 1)=(~DFWORD(df, 1)) &0x49124491;
#elif QUAD
DFWORD(result, 0)=ZEROWORD|((~sourhi)&0x04000912);
DFWORD(result, 1)=(~DFWORD(df, 1)) &0x44912449;
DFWORD(result, 2)=(~DFWORD(df, 2)) &0x12449124;
DFWORD(result, 3)=(~DFWORD(df, 3)) &0x49124491;
#endif
return result;
}
uInt decFloatIsCanonical(const decFloat *df) {
if (DFISSPECIAL(df)) {
if (DFISINF(df)) {
if (DFWORD(df, 0)&ECONMASK) return 0; if (!DFISCCZERO(df)) return 0; return 1;
}
if (DFWORD(df, 0)&ECONNANMASK) return 0; if (DFISCCZERO(df)) return 1; }
{ #if DOUBLE
uInt sourhi=DFWORD(df, 0);
uInt sourlo=DFWORD(df, 1);
if (CANONDPDOFF(sourhi, 8)
&& CANONDPDTWO(sourhi, sourlo, 30)
&& CANONDPDOFF(sourlo, 20)
&& CANONDPDOFF(sourlo, 10)
&& CANONDPDOFF(sourlo, 0)) return 1;
#elif QUAD
uInt sourhi=DFWORD(df, 0);
uInt sourmh=DFWORD(df, 1);
uInt sourml=DFWORD(df, 2);
uInt sourlo=DFWORD(df, 3);
if (CANONDPDOFF(sourhi, 4)
&& CANONDPDTWO(sourhi, sourmh, 26)
&& CANONDPDOFF(sourmh, 16)
&& CANONDPDOFF(sourmh, 6)
&& CANONDPDTWO(sourmh, sourml, 28)
&& CANONDPDOFF(sourml, 18)
&& CANONDPDOFF(sourml, 8)
&& CANONDPDTWO(sourml, sourlo, 30)
&& CANONDPDOFF(sourlo, 20)
&& CANONDPDOFF(sourlo, 10)
&& CANONDPDOFF(sourlo, 0)) return 1;
#endif
} return 0; }
uInt decFloatIsFinite(const decFloat *df) {
return !DFISSPECIAL(df);
}
uInt decFloatIsInfinite(const decFloat *df) {
return DFISINF(df);
}
uInt decFloatIsInteger(const decFloat *df) {
return DFISINT(df);
}
uInt decFloatIsLogical(const decFloat *df) {
return DFISUINT01(df) & DFISCC01(df);
}
uInt decFloatIsNaN(const decFloat *df) {
return DFISNAN(df);
}
uInt decFloatIsNegative(const decFloat *df) {
return DFISSIGNED(df) && !DFISZERO(df) && !DFISNAN(df);
}
uInt decFloatIsNormal(const decFloat *df) {
Int exp; if (DFISSPECIAL(df)) return 0;
if (DFISZERO(df)) return 0;
exp=GETEXPUN(df) +decFloatDigits(df)-1; return (exp>=DECEMIN); }
uInt decFloatIsPositive(const decFloat *df) {
return !DFISSIGNED(df) && !DFISZERO(df) && !DFISNAN(df);
}
uInt decFloatIsSignaling(const decFloat *df) {
return DFISSNAN(df);
}
uInt decFloatIsSignalling(const decFloat *df) {
return DFISSNAN(df);
}
uInt decFloatIsSigned(const decFloat *df) {
return DFISSIGNED(df)!=0;
}
uInt decFloatIsSubnormal(const decFloat *df) {
if (DFISSPECIAL(df)) return 0;
if (decFloatIsNormal(df)) return 0;
if (DFISZERO(df)) return 0;
return 1; }
uInt decFloatIsZero(const decFloat *df) {
return DFISZERO(df);
}
decFloat * decFloatLogB(decFloat *result, const decFloat *df,
decContext *set) {
Int ae; if (DFISNAN(df)) return decNaNs(result, df, NULL, set);
if (DFISINF(df)) {
DFWORD(result, 0)=0; return decInfinity(result, result); }
if (DFISZERO(df)) {
set->status|=DEC_Division_by_zero; DFWORD(result, 0)=DECFLOAT_Sign; return decInfinity(result, result); }
ae=GETEXPUN(df) +decFloatDigits(df)-1; DFWORD(result, 0)=ZEROWORD; if (ae<0) {
DFWORD(result, 0)|=DECFLOAT_Sign; ae=-ae;
}
#if DOUBLE
DFWORD(result, 1)=BIN2DPD[ae]; #elif QUAD
DFWORD(result, 1)=0;
DFWORD(result, 2)=0;
DFWORD(result, 3)=(ae/1000)<<10; DFWORD(result, 3)|=BIN2DPD[ae%1000];
#endif
return result;
}
decFloat * decFloatMax(decFloat *result,
const decFloat *dfl, const decFloat *dfr,
decContext *set) {
Int comp;
if (DFISNAN(dfl)) {
if (DFISNAN(dfr) || DFISSNAN(dfl)) return decNaNs(result, dfl, dfr, set);
return decCanonical(result, dfr); }
if (DFISNAN(dfr)) {
if (DFISSNAN(dfr)) return decNaNs(result, dfl, dfr, set);
return decCanonical(result, dfl); }
comp=decNumCompare(dfl, dfr, 1);
if (comp>=0) return decCanonical(result, dfl);
return decCanonical(result, dfr);
}
decFloat * decFloatMaxMag(decFloat *result,
const decFloat *dfl, const decFloat *dfr,
decContext *set) {
Int comp;
decFloat absl, absr;
if (DFISNAN(dfl) || DFISNAN(dfr)) return decFloatMax(result, dfl, dfr, set);
decFloatCopyAbs(&absl, dfl);
decFloatCopyAbs(&absr, dfr);
comp=decNumCompare(&absl, &absr, 0);
if (comp>0) return decCanonical(result, dfl);
if (comp<0) return decCanonical(result, dfr);
return decFloatMax(result, dfl, dfr, set);
}
decFloat * decFloatMin(decFloat *result,
const decFloat *dfl, const decFloat *dfr,
decContext *set) {
Int comp;
if (DFISNAN(dfl)) {
if (DFISNAN(dfr) || DFISSNAN(dfl)) return decNaNs(result, dfl, dfr, set);
return decCanonical(result, dfr); }
if (DFISNAN(dfr)) {
if (DFISSNAN(dfr)) return decNaNs(result, dfl, dfr, set);
return decCanonical(result, dfl); }
comp=decNumCompare(dfl, dfr, 1);
if (comp<=0) return decCanonical(result, dfl);
return decCanonical(result, dfr);
}
decFloat * decFloatMinMag(decFloat *result,
const decFloat *dfl, const decFloat *dfr,
decContext *set) {
Int comp;
decFloat absl, absr;
if (DFISNAN(dfl) || DFISNAN(dfr)) return decFloatMin(result, dfl, dfr, set);
decFloatCopyAbs(&absl, dfl);
decFloatCopyAbs(&absr, dfr);
comp=decNumCompare(&absl, &absr, 0);
if (comp<0) return decCanonical(result, dfl);
if (comp>0) return decCanonical(result, dfr);
return decFloatMin(result, dfl, dfr, set);
}
decFloat * decFloatMinus(decFloat *result, const decFloat *df,
decContext *set) {
if (DFISNAN(df)) return decNaNs(result, df, NULL, set);
decCanonical(result, df); if (DFISZERO(df)) DFBYTE(result, 0)&=~0x80; else DFBYTE(result, 0)^=0x80; return result;
}
decFloat * decFloatMultiply(decFloat *result,
const decFloat *dfl, const decFloat *dfr,
decContext *set) {
bcdnum num; uByte bcdacc[DECPMAX9*18+1];
if (DFISSPECIAL(dfl) || DFISSPECIAL(dfr)) { if (DFISNAN(dfl) || DFISNAN(dfr)) return decNaNs(result, dfl, dfr, set);
if (DFISINF(dfl) && DFISZERO(dfr)) return decInvalid(result, set);
if (DFISINF(dfr) && DFISZERO(dfl)) return decInvalid(result, set);
DFWORD(result, 0)=DFWORD(dfl, 0)^DFWORD(dfr, 0); return decInfinity(result, result);
}
decFiniteMultiply(&num, bcdacc, dfl, dfr);
return decFinalize(result, &num, set); }
decFloat * decFloatNextMinus(decFloat *result, const decFloat *dfl,
decContext *set) {
decFloat delta; uInt savestat; enum rounding saveround;
if (DFISINF(dfl) && !DFISSIGNED(dfl)) {
DFSETNMAX(result);
return result; }
decFloatZero(&delta); DFWORD(&delta, DECWORDS-1)=1; DFWORD(&delta, 0)=DECFLOAT_Sign; saveround=set->round; set->round=DEC_ROUND_FLOOR; savestat=set->status; decFloatAdd(result, dfl, &delta, set);
if (DFISZERO(result)) DFWORD(result, 0)^=DECFLOAT_Sign; set->status&=DEC_Invalid_operation; set->status|=savestat; set->round=saveround; return result;
}
decFloat * decFloatNextPlus(decFloat *result, const decFloat *dfl,
decContext *set) {
uInt savestat; enum rounding saveround; decFloat delta;
if (DFISINF(dfl) && DFISSIGNED(dfl)) {
DFSETNMAX(result);
DFWORD(result, 0)|=DECFLOAT_Sign; return result; }
decFloatZero(&delta); DFWORD(&delta, DECWORDS-1)=1; DFWORD(&delta, 0)=0; saveround=set->round; set->round=DEC_ROUND_CEILING; savestat=set->status; decFloatAdd(result, dfl, &delta, set);
if (DFISZERO(result)) DFWORD(result, 0)^=DECFLOAT_Sign; set->status&=DEC_Invalid_operation; set->status|=savestat; set->round=saveround; return result;
}
decFloat * decFloatNextToward(decFloat *result,
const decFloat *dfl, const decFloat *dfr,
decContext *set) {
decFloat delta; decFloat pointone; uInt savestat; enum rounding saveround; uInt deltatop; Int comp;
if (DFISNAN(dfl) || DFISNAN(dfr)) return decNaNs(result, dfl, dfr, set);
comp=decNumCompare(dfl, dfr, 0);
if (comp==0) return decFloatCopySign(result, dfl, dfr);
if (comp<0) { if (DFISINF(dfl) && DFISSIGNED(dfl)) { DFSETNMAX(result);
DFWORD(result, 0)|=DECFLOAT_Sign;
return result;
}
saveround=set->round; set->round=DEC_ROUND_CEILING; deltatop=0; }
else { if (DFISINF(dfl) && !DFISSIGNED(dfl)) { DFSETNMAX(result);
return result;
}
saveround=set->round; set->round=DEC_ROUND_FLOOR; deltatop=DECFLOAT_Sign; }
savestat=set->status; decFloatZero(&delta); DFWORD(&delta, DECWORDS-1)=1; DFWORD(&delta, 0)=deltatop; decFloatFromString(&pointone, "1E-1", set); decFloatFMA(result, &delta, &pointone, dfl, set);
if (decFloatIsNormal(result)) set->status=savestat; set->round=saveround; return result;
}
decFloat * decFloatOr(decFloat *result,
const decFloat *dfl, const decFloat *dfr,
decContext *set) {
if (!DFISUINT01(dfl) || !DFISUINT01(dfr)
|| !DFISCC01(dfl) || !DFISCC01(dfr)) return decInvalid(result, set);
#if DOUBLE
DFWORD(result, 0)=ZEROWORD
|((DFWORD(dfl, 0) | DFWORD(dfr, 0))&0x04009124);
DFWORD(result, 1)=(DFWORD(dfl, 1) | DFWORD(dfr, 1))&0x49124491;
#elif QUAD
DFWORD(result, 0)=ZEROWORD
|((DFWORD(dfl, 0) | DFWORD(dfr, 0))&0x04000912);
DFWORD(result, 1)=(DFWORD(dfl, 1) | DFWORD(dfr, 1))&0x44912449;
DFWORD(result, 2)=(DFWORD(dfl, 2) | DFWORD(dfr, 2))&0x12449124;
DFWORD(result, 3)=(DFWORD(dfl, 3) | DFWORD(dfr, 3))&0x49124491;
#endif
return result;
}
decFloat * decFloatPlus(decFloat *result, const decFloat *df,
decContext *set) {
if (DFISNAN(df)) return decNaNs(result, df, NULL, set);
decCanonical(result, df); if (DFISZERO(df)) DFBYTE(result, 0)&=~0x80; return result;
}
decFloat * decFloatQuantize(decFloat *result,
const decFloat *dfl, const decFloat *dfr,
decContext *set) {
Int explb, exprb; uByte *ulsd; uByte *ub, *uc; Int drop; uInt dpd; uInt encode; uInt sourhil, sourhir; uInt uiwork; #if QUAD
uShort uswork; #endif
uByte buf[4+DECPMAX*3+2*QUAD]; #if DECTRACE
bcdnum num; #endif
sourhil=DFWORD(dfl, 0); explb=DECCOMBEXP[sourhil>>26]; sourhir=DFWORD(dfr, 0); exprb=DECCOMBEXP[sourhir>>26];
if (EXPISSPECIAL(explb | exprb)) { if (DFISNAN(dfl) || DFISNAN(dfr)) return decNaNs(result, dfl, dfr, set);
if (DFISINF(dfl)!=DFISINF(dfr)) return decInvalid(result, set);
return decInfinity(result, dfl);
}
explb+=GETECON(dfl); exprb+=GETECON(dfr);
drop=exprb-explb; if (drop==0) return decCanonical(result, dfl);
#define BUFOFF (buf+4+DECPMAX)
GETCOEFF(dfl, BUFOFF);
#if DECTRACE
num.msd=BUFOFF;
num.lsd=BUFOFF+DECPMAX-1;
num.exponent=explb-DECBIAS;
num.sign=sourhil & DECFLOAT_Sign;
decShowNum(&num, "dfl");
#endif
if (drop>0) { uByte *roundat; uByte reround;
UBFROMUI(BUFOFF-4, 0);
if (drop<DECPMAX) { roundat=BUFOFF+DECPMAX-drop;
reround=*roundat;
for (ub=roundat+1; ub<BUFOFF+DECPMAX; ub++) {
if (*ub!=0) { reround=DECSTICKYTAB[reround]; break; }
} ulsd=roundat-1; }
else { if (drop==DECPMAX) {
roundat=BUFOFF;
reround=*roundat;
}
else {
roundat=BUFOFF-1;
reround=0;
}
for (ub=roundat+1; ub<BUFOFF+DECPMAX; ub++) {
if (*ub!=0) { reround=DECSTICKYTAB[reround]; break; }
} *BUFOFF=0; ulsd=BUFOFF; }
if (reround!=0) { uInt bump=0;
set->status|=DEC_Inexact;
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 (!(sourhil&DECFLOAT_Sign) && reround>0) bump=1;
break;} case DEC_ROUND_FLOOR: {
if (sourhil&DECFLOAT_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 (; UBTOUI(ub-3)==0x09090909; ub-=4) UBFROMUI(ub-3, 0);
for (; *ub==9; ub--) *ub=0;
*ub+=1;
} }
if (drop>4) {
UBFROMUI(BUFOFF-8, 0); for (uc=BUFOFF-12; uc>ulsd-DECPMAX-3; uc-=4) UBFROMUI(uc, 0);
}
}
else { if (-drop>DECPMAX-1) { if (!ISCOEFFZERO(BUFOFF)) return decInvalid(result, set);
ulsd=BUFOFF+DECPMAX-1;
}
else { #if DECLITEND
static const uInt dmask[]={0, 0x000000ff, 0x0000ffff, 0x00ffffff};
#else
static const uInt dmask[]={0, 0xff000000, 0xffff0000, 0xffffff00};
#endif
for (uc=BUFOFF+DECPMAX;; uc+=4) {
UBFROMUI(uc, 0);
if (UBTOUI(uc-DECPMAX)!=0) { if (uc<=BUFOFF+DECPMAX+(-drop)-4)
return decInvalid(result, set);
if ((UBTOUI(uc-DECPMAX)&dmask[(-drop)%4])!=0)
return decInvalid(result, set);
break; }
if (uc>=BUFOFF+DECPMAX+(-drop)-4) break; }
ulsd=BUFOFF+DECPMAX+(-drop)-1;
} }
#if DECTRACE
num.msd=ulsd-DECPMAX+1;
num.lsd=ulsd;
num.exponent=explb-DECBIAS;
num.sign=sourhil & DECFLOAT_Sign;
decShowNum(&num, "res");
#endif
encode=((exprb>>DECECONL)<<4) + *(ulsd-DECPMAX+1); encode=DECCOMBFROM[encode]; encode|=sourhir & ECONMASK;
encode|=sourhil&DECFLOAT_Sign;
#define getDPD3q(dpd, n) ub=ulsd-(3*(n))-2; \
dpd=BCD2DPD[(*ub*256)+(*(ub+1)*16)+*(ub+2)];
#if DOUBLE
getDPD3q(dpd, 4); encode|=dpd<<8;
getDPD3q(dpd, 3); encode|=dpd>>2;
DFWORD(result, 0)=encode;
encode=dpd<<30;
getDPD3q(dpd, 2); encode|=dpd<<20;
getDPD3q(dpd, 1); encode|=dpd<<10;
getDPD3q(dpd, 0); encode|=dpd;
DFWORD(result, 1)=encode;
#elif QUAD
getDPD3q(dpd,10); encode|=dpd<<4;
getDPD3q(dpd, 9); encode|=dpd>>6;
DFWORD(result, 0)=encode;
encode=dpd<<26;
getDPD3q(dpd, 8); encode|=dpd<<16;
getDPD3q(dpd, 7); encode|=dpd<<6;
getDPD3q(dpd, 6); encode|=dpd>>4;
DFWORD(result, 1)=encode;
encode=dpd<<28;
getDPD3q(dpd, 5); encode|=dpd<<18;
getDPD3q(dpd, 4); encode|=dpd<<8;
getDPD3q(dpd, 3); encode|=dpd>>2;
DFWORD(result, 2)=encode;
encode=dpd<<30;
getDPD3q(dpd, 2); encode|=dpd<<20;
getDPD3q(dpd, 1); encode|=dpd<<10;
getDPD3q(dpd, 0); encode|=dpd;
DFWORD(result, 3)=encode;
#endif
return result;
}
decFloat * decFloatReduce(decFloat *result, const decFloat *df,
decContext *set) {
bcdnum num; uByte buf[DECPMAX], *ub; if (df!=result) *result=*df; if (DFISNAN(df)) return decNaNs(result, df, NULL, set); if (DFISINF(df)) return decInfinity(result, df); if (DFISZERO(df)) {
uInt sign=DFWORD(df, 0)&DECFLOAT_Sign;
decFloatZero(result);
DFWORD(result, 0)|=sign;
return result; }
GETCOEFF(df, buf);
ub=buf+DECPMAX-1; if (*ub) return result; for (ub--; *ub==0;) ub--; num.sign=DFWORD(df, 0)&DECFLOAT_Sign; num.exponent=GETEXPUN(df)+(Int)(buf+DECPMAX-1-ub); num.msd=buf;
num.lsd=ub;
return decFinalize(result, &num, set);
}
decFloat * decFloatRemainder(decFloat *result,
const decFloat *dfl, const decFloat *dfr,
decContext *set) {
return decDivide(result, dfl, dfr, set, REMAINDER);
}
decFloat * decFloatRemainderNear(decFloat *result,
const decFloat *dfl, const decFloat *dfr,
decContext *set) {
return decDivide(result, dfl, dfr, set, REMNEAR);
}
#define PHALF (ROUNDUP(DECPMAX/2, 4))
decFloat * decFloatRotate(decFloat *result,
const decFloat *dfl, const decFloat *dfr,
decContext *set) {
Int rotate; uByte buf[DECPMAX+PHALF]; uInt digits, savestat; bcdnum num; uByte *ub;
if (DFISNAN(dfl)||DFISNAN(dfr)) return decNaNs(result, dfl, dfr, set);
if (!DFISINT(dfr)) return decInvalid(result, set);
digits=decFloatDigits(dfr); if (digits>2) return decInvalid(result, set); rotate=DPD2BIN[DFWORD(dfr, DECWORDS-1)&0x3ff]; if (rotate>DECPMAX) return decInvalid(result, set); if (DFISINF(dfl)) return decInfinity(result, dfl); if (rotate==0 || rotate==DECPMAX) return decCanonical(result, dfl);
if (DFISSIGNED(dfr)) rotate=-rotate;
if (abs(rotate)>PHALF) {
if (rotate<0) rotate=DECPMAX+rotate;
else rotate=rotate-DECPMAX;
}
ub=buf;
if (rotate<0) ub+=PHALF; GETCOEFF(dfl, ub);
if (rotate<0) {
memcpy(buf, buf+DECPMAX, PHALF);
num.msd=buf+PHALF+rotate;
}
else {
memcpy(buf+DECPMAX, buf, PHALF);
num.msd=buf+rotate;
}
num.lsd=num.msd+DECPMAX-1;
num.sign=DFWORD(dfl, 0)&DECFLOAT_Sign;
num.exponent=GETEXPUN(dfl);
savestat=set->status; decFinalize(result, &num, set);
set->status=savestat; return result;
}
uInt decFloatSameQuantum(const decFloat *dfl, const decFloat *dfr) {
if (DFISSPECIAL(dfl) || DFISSPECIAL(dfr)) {
if (DFISNAN(dfl) && DFISNAN(dfr)) return 1;
if (DFISINF(dfl) && DFISINF(dfr)) return 1;
return 0; }
if (GETEXP(dfl)==GETEXP(dfr)) return 1; return 0;
}
#define SCALEBMAX 2*(DECEMAX+DECPMAX)
decFloat * decFloatScaleB(decFloat *result,
const decFloat *dfl, const decFloat *dfr,
decContext *set) {
uInt digits; Int expr;
if (DFISNAN(dfl)||DFISNAN(dfr)) return decNaNs(result, dfl, dfr, set);
if (!DFISINT(dfr)) return decInvalid(result, set);
digits=decFloatDigits(dfr);
#if DOUBLE
if (digits>3) return decInvalid(result, set); expr=DPD2BIN[DFWORD(dfr, 1)&0x3ff]; #elif QUAD
if (digits>5) return decInvalid(result, set); expr=DPD2BIN[DFWORD(dfr, 3)&0x3ff] +DPD2BIN[(DFWORD(dfr, 3)>>10)&0x3ff]*1000; #endif
if (expr>SCALEBMAX) return decInvalid(result, set); if (DFISINF(dfl)) return decInfinity(result, dfl); if (DFISSIGNED(dfr)) expr=-expr;
*result=*dfl; return decFloatSetExponent(result, set, GETEXPUN(result)+expr);
}
decFloat * decFloatShift(decFloat *result,
const decFloat *dfl, const decFloat *dfr,
decContext *set) {
Int shift; uByte buf[DECPMAX*2]; uInt digits, savestat; bcdnum num; uInt uiwork;
if (DFISNAN(dfl)||DFISNAN(dfr)) return decNaNs(result, dfl, dfr, set);
if (!DFISINT(dfr)) return decInvalid(result, set);
digits=decFloatDigits(dfr); if (digits>2) return decInvalid(result, set); shift=DPD2BIN[DFWORD(dfr, DECWORDS-1)&0x3ff]; if (shift>DECPMAX) return decInvalid(result, set);
if (DFISINF(dfl)) return decInfinity(result, dfl); if (shift==0) return decCanonical(result, dfl);
if (shift==DECPMAX) { uByte sign=(uByte)(DFBYTE(dfl, 0)&0x80); decFloatZero(result); DFBYTE(result, 0)=(uByte)(DFBYTE(result, 0)|sign); return result;
}
num.sign=DFWORD(dfl, 0)&DECFLOAT_Sign;
num.exponent=GETEXPUN(dfl);
num.msd=buf;
GETCOEFF(dfl, buf);
if (DFISSIGNED(dfr)) { num.lsd=buf+DECPMAX-shift-1;
}
else { UBFROMUI(buf+DECPMAX, 0); UBFROMUI(buf+DECPMAX+4, 0); if (shift>8) memset(buf+DECPMAX+8, 0, 8+QUAD*18); num.msd+=shift;
num.lsd=num.msd+DECPMAX-1;
}
savestat=set->status; decFinalize(result, &num, set);
set->status=savestat; return result;
}
decFloat * decFloatSubtract(decFloat *result,
const decFloat *dfl, const decFloat *dfr,
decContext *set) {
decFloat temp;
if (DFISNAN(dfr)) return decFloatAdd(result, dfl, dfr, set);
temp=*dfr; DFBYTE(&temp, 0)^=0x80; return decFloatAdd(result, dfl, &temp, set); }
uInt decFloatToUInt32(const decFloat *df, decContext *set,
enum rounding round) {
return decToInt32(df, set, round, 0, 1);}
uInt decFloatToUInt32Exact(const decFloat *df, decContext *set,
enum rounding round) {
return decToInt32(df, set, round, 1, 1);}
Int decFloatToInt32(const decFloat *df, decContext *set,
enum rounding round) {
return (Int)decToInt32(df, set, round, 0, 0);}
Int decFloatToInt32Exact(const decFloat *df, decContext *set,
enum rounding round) {
return (Int)decToInt32(df, set, round, 1, 0);}
decFloat * decFloatToIntegralValue(decFloat *result, const decFloat *df,
decContext *set, enum rounding round) {
return decToIntegral(result, df, set, round, 0);}
decFloat * decFloatToIntegralExact(decFloat *result, const decFloat *df,
decContext *set) {
return decToIntegral(result, df, set, set->round, 1);}
decFloat * decFloatXor(decFloat *result,
const decFloat *dfl, const decFloat *dfr,
decContext *set) {
if (!DFISUINT01(dfl) || !DFISUINT01(dfr)
|| !DFISCC01(dfl) || !DFISCC01(dfr)) return decInvalid(result, set);
#if DOUBLE
DFWORD(result, 0)=ZEROWORD
|((DFWORD(dfl, 0) ^ DFWORD(dfr, 0))&0x04009124);
DFWORD(result, 1)=(DFWORD(dfl, 1) ^ DFWORD(dfr, 1))&0x49124491;
#elif QUAD
DFWORD(result, 0)=ZEROWORD
|((DFWORD(dfl, 0) ^ DFWORD(dfr, 0))&0x04000912);
DFWORD(result, 1)=(DFWORD(dfl, 1) ^ DFWORD(dfr, 1))&0x44912449;
DFWORD(result, 2)=(DFWORD(dfl, 2) ^ DFWORD(dfr, 2))&0x12449124;
DFWORD(result, 3)=(DFWORD(dfl, 3) ^ DFWORD(dfr, 3))&0x49124491;
#endif
return result;
}
static decFloat *decInvalid(decFloat *result, decContext *set) {
decFloatZero(result);
DFWORD(result, 0)=DECFLOAT_qNaN;
set->status|=DEC_Invalid_operation;
return result;
}
static decFloat *decInfinity(decFloat *result, const decFloat *df) {
uInt sign=DFWORD(df, 0); decFloatZero(result); DFWORD(result, 0)=DECFLOAT_Inf | (sign & DECFLOAT_Sign);
return result;
}
static decFloat *decNaNs(decFloat *result,
const decFloat *dfl, const decFloat *dfr,
decContext *set) {
if (dfr!=NULL && DFISSNAN(dfr) && !DFISSNAN(dfl)) dfl=dfr; if (DFISSNAN(dfl)) {
decCanonical(result, dfl); DFWORD(result, 0)&=~(DECFLOAT_qNaN ^ DECFLOAT_sNaN); set->status|=DEC_Invalid_operation;
return result;
}
if (!DFISNAN(dfl)) dfl=dfr; return decCanonical(result, dfl); }
static Int decNumCompare(const decFloat *dfl, const decFloat *dfr, Flag tot) {
Int sigl, sigr; Int shift; uByte *ub, *uc; uInt uiwork; uByte bufl[DECPMAX*2+QUAD*2+4]; uByte bufr[DECPMAX*2+QUAD*2+4];
sigl=1;
if (DFISSIGNED(dfl)) {
if (!DFISSIGNED(dfr)) { if (DFISZERO(dfl) && DFISZERO(dfr) && !tot) return 0;
return -1; }
sigl=-1;
}
if (DFISSIGNED(dfr)) {
if (!DFISSIGNED(dfl)) { if (DFISZERO(dfl) && DFISZERO(dfr) && !tot) return 0;
return +1; }
}
sigr=-sigl;
if (DFISINF(dfl)) {
if (DFISINF(dfr)) return 0; return sigl; }
if (DFISINF(dfr)) return sigr;
shift=GETEXP(dfl)-GETEXP(dfr);
if (DFISZERO(dfl)) {
if (!DFISZERO(dfr)) return sigr; if (shift==0 || !tot) return 0;
if (shift>0) return sigl;
return sigr; }
else { if (DFISZERO(dfr)) return sigl; }
if (abs(shift)>=DECPMAX) { if (shift>0) return sigl;
return sigr; }
#if QUAD
UBFROMUI(bufl, 0);
UBFROMUI(bufr, 0);
#endif
GETCOEFF(dfl, bufl+QUAD*2); GETCOEFF(dfr, bufr+QUAD*2); if (shift==0) { for (ub=bufl, uc=bufr; ub<bufl+DECPMAX+QUAD*2; ub+=4, uc+=4) {
uInt ui=UBTOUI(ub);
if (ui==UBTOUI(uc)) continue; for (;; ub++, uc++) {
if (*ub>*uc) return sigl; if (*ub<*uc) return sigr; }
}
} else if (shift>0) { ub=bufl; UBFROMUI(bufl+DECPMAX+QUAD*2, 0); UBFROMUI(bufl+DECPMAX+QUAD*2+4, 0); if (shift>8) {
uByte *up; uByte *upend=bufl+DECPMAX+QUAD*2+shift;
for (up=bufl+DECPMAX+QUAD*2+8; up<upend; up+=4) UBFROMUI(up, 0);
for (;; ub+=4) {
if (UBTOUI(ub)!=0) return sigl;
if (ub+4>bufl+shift-4) break;
}
}
for (; ub<bufl+shift; ub++) if (*ub!=0) return sigl;
for (uc=bufr; ; uc+=4, ub+=4) {
uInt ui=UBTOUI(ub);
if (ui!=UBTOUI(uc)) { for (;; uc++, ub++) { if (*ub>*uc) return sigl; if (*ub<*uc) return sigr; }
} if (uc==bufr+QUAD*2+DECPMAX-4) break; }
}
else { uc=bufr; UBFROMUI(bufr+DECPMAX+QUAD*2, 0); UBFROMUI(bufr+DECPMAX+QUAD*2+4, 0); if (shift<-8) {
uByte *up; uByte *upend=bufr+DECPMAX+QUAD*2-shift;
for (up=bufr+DECPMAX+QUAD*2+8; up<upend; up+=4) UBFROMUI(up, 0);
for (;; uc+=4) {
if (UBTOUI(uc)!=0) return sigr;
if (uc+4>bufr-shift-4) break;
}
}
for (; uc<bufr-shift; uc++) if (*uc!=0) return sigr;
for (ub=bufl; ; ub+=4, uc+=4) {
uInt ui=UBTOUI(ub);
if (ui!=UBTOUI(uc)) { for (;; ub++, uc++) { if (*ub>*uc) return sigl; if (*ub<*uc) return sigr; }
} if (ub==bufl+QUAD*2+DECPMAX-4) break; }
}
if (!tot) return 0; if (shift>0) return sigl; if (shift<0) return sigr; return 0;
}
static uInt decToInt32(const decFloat *df, decContext *set,
enum rounding rmode, Flag exact, Flag unsign) {
Int exp; uInt sourhi, sourpen, sourlo; uInt hi, lo; decFloat zero, result; Int i;
sourhi=DFWORD(df, 0); exp=DECCOMBEXP[sourhi>>26]; if (EXPISSPECIAL(exp)) { set->status|=DEC_Invalid_operation; return 0;
}
if (GETEXPUN(df)==0) result=*df; else { enum rounding saveround; uInt savestatus; saveround=set->round; savestatus=set->status; set->round=rmode; decFloatZero(&zero); set->status=0; decFloatQuantize(&result, df, &zero, set); set->round=saveround; if (exact) set->status|=savestatus; else set->status=savestatus; }
#if DOUBLE
if ((DFWORD(&result, 0)&0x1c03ff00)!=0
|| (DFWORD(&result, 0)&0x60000000)==0x60000000) {
#elif QUAD
if ((DFWORD(&result, 2)&0xffffff00)!=0
|| DFWORD(&result, 1)!=0
|| (DFWORD(&result, 0)&0x1c003fff)!=0
|| (DFWORD(&result, 0)&0x60000000)==0x60000000) {
#endif
set->status|=DEC_Invalid_operation; return 0;
}
sourlo=DFWORD(&result, DECWORDS-1);
lo=DPD2BIN0[sourlo&0x3ff]
+DPD2BINK[(sourlo>>10)&0x3ff]
+DPD2BINM[(sourlo>>20)&0x3ff];
sourpen=DFWORD(&result, DECWORDS-2);
hi=DPD2BIN0[((sourpen<<2) | (sourlo>>30))&0x3ff];
if (unsign) {
if (hi>4 || (hi==4 && lo>294967295) || (hi+lo!=0 && DFISSIGNED(&result))) {
set->status|=DEC_Invalid_operation; return 0;
}
return hi*BILLION+lo;
}
if (hi>2 || (hi==2 && lo>147483647)) {
if (lo==147483648 && hi==2 && DFISSIGNED(&result)) return 0x80000000;
set->status|=DEC_Invalid_operation; return 0;
}
i=hi*BILLION+lo;
if (DFISSIGNED(&result)) i=-i;
return (uInt)i;
}
static decFloat * decToIntegral(decFloat *result, const decFloat *df,
decContext *set, enum rounding rmode,
Flag exact) {
Int exp; uInt sourhi; enum rounding saveround; uInt savestatus; decFloat zero;
sourhi=DFWORD(df, 0); exp=DECCOMBEXP[sourhi>>26];
if (EXPISSPECIAL(exp)) { if (DFISNAN(df)) return decNaNs(result, df, NULL, set);
return decInfinity(result, df);
}
exp+=GETECON(df)-DECBIAS;
if (exp>=0) return decCanonical(result, df);
saveround=set->round; savestatus=set->status; set->round=rmode; decFloatZero(&zero); decFloatQuantize(result, df, &zero, set); set->round=saveround; if (!exact) set->status=savestatus; return result;
}