#include #include "mcc.h" #include "ieeefp.h" static int shift_in(unsigned char *bits, int bytes, unsigned int a, int shf) { int i; for (i=bytes-1;i>=0;i--) { a = (bits[i] << shf) | a; bits[i] = a & 0xff; a >>= 8; } return(a); } /* * Ideally, I would like to round-to-even in exactly-halfway cases. * But doing that demands keeping the entire significand around. * Perhaps someday. */ static void floating_round(unsigned char *mant, int bytes, int rpt, int *exp) { int x; int a; x = bytes - 1 - (rpt >> 3); if (x > 0) bzero(&mant[0],x*sizeof(*mant)); mant[x] &= 0xff << (7 - (rpt & 7)); a = 0x80 >> (rpt & 7); if (mant[x] & a) { while (a && (x < bytes)) { a += mant[x]; mant[x] = a & 0xff; a >>= 8; x ++; } if (a) { if (a != 1) panic(); a = 0x100; for (x=bytes-1;x>=0;x--) { a |= mant[x]; mant[x] = a >> 1; a = (a & 1) << 8; } exp[0] ++; } } } static void shift_mant_right(unsigned char *mant, int nbytes, int bits) { unsigned char *f; unsigned char *t; int b; int n; int i; unsigned int a; t = mant; f = t + (bits >> 3); b = bits & 7; n = nbytes - (bits >> 3) - 1; a = *f++ >> b; for (i=n;i>0;i--) { a |= *f++ << (8-b); *t++ = a & 0xff; a >>= 8; } *t++ = a; for (i=t-mant;i",F)J'u?2" F>"!79,d%1N:>7R1X;7%Vpn;^"&]UXWs6o`fu?BqPu5#+5IR&;dBMeNHBnKKW"]5QCdt1hZt 7l81KAdj?Do-;5bS"!O60]CdU8SenXYH3F3 q&4SL7-JD"%l@:'#c!C+6XH`$#)b3,>&;.2[m3s#aF\D9G.n5((:jYKZ'g+LAfnL2'EfT;h= q[49W%A72Z@V2Uhd0Mp0X*,cU,.S4$Q!rG`2fmk'*G/7Q^V:E,o`rM<2gaOSN=&-cmjh'op_CI2Z>R^p;W;-=h3ua[Lr>p$C;R]_^*J4L=ATE0r[L)B5P(,rH/88.NOtBhkjNY,$Ib.+*!FUd$)3W1TRd3)?_caJfLXd&937Y_Do=WXIrHHlfu1QG n>+%Z"C>:[SLuX)`l,^#d>U46$n."4kcW&A^*M@NU\,s]Q+U*#lq\Xi'ETM.'.7W3,#Bsdj3 EH-57m_6QAB2ZP$*J0\:j:'2MWO:1Xi[oSRhOJ?48GT<,IY.7g12`A'^Vf%Ei`#6*5'93YQZ -VmpbmBPYHY#[OR<^T,1Qc"s'9%)[lJP_boBh8fW!,DE.+D_Q.2BSrK)bn!?8_q0=(s3O!bm =2cAmq#0HZ-$Y(23i','$7>O=:=+QiVS9ZP^D&&-nm#!m'4@*,2VA;[p(1U*?G_GZ*Ta0/]+d`Q>:d>@/-X_LX"Q*rs+.&e,O6mH:cl>SOL'#5d\[OXC[@f4-h7pQPYU3:Ca(-;8mc=X4*Uf@bpBY$F1$BYWm=2 d;!X:q5P'GikacEdZi/!*F]]ohN^f1[3C,ud\K"RR_Z"9R._@5,&uG'/LDW7V9I8drOg3[gt -GgJ9E?t.uelpQK=5]+Z"MNriiN"I#FY#(^/8\n) 2`N@Xn,$k\;T\`U$5.9C/$bI#79h$`>X-UGR&iE8*r%=+%oXa1aBj-aLU/lL>*bHp.NZ\MKp -rnABr\!8hE1nFh2_Cs. xbtoa End N 1167 48f E e1 S 21233 R 3855a023 */ /* * IEEE floats are 32 bits, doubles 64: * * seeeeeee emmmmmmm mmmmmmmm mmmmmmmm * seeeeeee eeeemmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm * * An eeee field of (~0)>>1 corresponds to an exponent of zero, ie, to * a value of 1.mmmm...mmmm. eeee ~0 is used for infinities and NaNs; * eeee 0 is used for zero (mmmm==0) or denormals (mmmm!=0). * * float range: * .14013e-44 (min denormal) * .117549e-37 (min normal) * .340282e+39 (max) * double range: * .494066e-323 (min denormal) * .222507e-307 (min normal) * .898847e+308 (max) * * Constants are always nonnegative. What looks like a negative * constant is actually unary minus applied to a positive constant. * (This has implications for the type when the conceptual constant is * the most negative integer in a two's-complement system.) * * For hex constants, we just take the top bits of the mantissa, round, * and construct the number. We do need to compensate for the * mantissa being in hex but the exponent being a power of 2, not 16. * * For decimal constants, */ int float_cvt_ieee(TOKEN *t, int base, const unsigned char *digits, int ndigits, int dotloc, int exp, const char **whynot) { unsigned char mant[8]; // 64 bits, always enough for IEEE int i; do <"zero"> { do <"toobig"> { if (ndigits < 1) break <"zero">; switch (base) { default: panic(); break; case 10: // exp is a power of 10 exp += dotloc; // value is now 0.mmmmm x 10^exp if (exp < ((t->u.cst.type == CST_FLOAT)?-44:-323)) { // warn about underflowing to zero? break <"zero">; } if (exp > ((t->u.cst.type == CST_FLOAT)?39:308)) break <"toobig">; break; case 16: // exp is a power of 2 exp += dotloc * 4; bzero(&mant[0],8); for (i=0;i<16;i++) { if (shift_in(&mant[0],8,(i 1.mmmm switch (t->u.cst.type) { default: panic(); break; case CST_FLOAT: floating_round(&mant[0],8,24,&exp); exp += 127; if (exp > 254) break <"toobig">; if (exp < 1) { if (1-exp > 24) { // warn about underflowing to zero? break <"zero">; } shift_mant_right(&mant[0],8,1-exp); exp = 0; } t->u.cst.val[0] = mant[5]; t->u.cst.val[1] = mant[6]; t->u.cst.val[2] = (mant[7] & 0x7f) | ((exp & 1) << 7); t->u.cst.val[3] = exp >> 1; return(1); break; case CST_DOUBLE: case CST_LDOUBLE: floating_round(&mant[0],8,53,&exp); exp += 1023; if (exp > 2046) break <"toobig">; if (exp < 1) { if (1-exp > 53) { // warn about underflowing to zero? break <"zero">; } shift_mant_right(&mant[0],8,1-exp); exp = 0; } t->u.cst.val[0] = (mant[1] >> 3) | ((mant[2] & 7) << 5); t->u.cst.val[1] = (mant[2] >> 3) | ((mant[3] & 7) << 5); t->u.cst.val[2] = (mant[3] >> 3) | ((mant[4] & 7) << 5); t->u.cst.val[3] = (mant[4] >> 3) | ((mant[5] & 7) << 5); t->u.cst.val[4] = (mant[5] >> 3) | ((mant[6] & 7) << 5); t->u.cst.val[5] = (mant[6] >> 3) | ((mant[7] & 7) << 5); t->u.cst.val[6] = ((mant[7] >> 3) & 0x0f) | ((exp & 15) << 4); t->u.cst.val[7] = exp >> 4; return(1); break; } break; } } while (0); *whynot = (t->u.cst.type == CST_FLOAT) ? "magnitude too large for float" : "magnitude too large for double"; return(0); } while (0); bzero(&t->u.cst.val[0],sizeof(t->u.cst.val)); return(1); }