> conversion of a denorm float -> double is busted on the alpha. > > from the attached program , the iteration at I=-126 fails to properly > convert the first denormal float number into a corresponding double > ( the double is not denormal ). The exponent for the double should have > been 896 ( 1 less than the previous iteration ( at i=-125), and frac=0. > /gat > > does anyone know if the sparc, or ppc fails also ? > > alpha results: > I=-126 prev=2.3509887016446e-38, d=1.1754943508223e-38 > Value: f=800000, s=(0,0), exp=(1,1), frac=(0,0) > V\=2.0 f=400000, s=(0,0), exp=(0,0), frac=(4194304,400000) > Conversion: f=8000000000000, s=(0,0), exp=(0,0), > frac=(2251799813685248,8000000000000) > reverted: f=0, s=(0,0), exp=(0,0), frac=(0,0) > Conversion failed > > i386 results: > I=-126 prev=2.3509887016446e-38, d=1.1754943508223e-38 > Value: f=800000, s=(0,0), exp=(1,1), frac=(0,0) > V\=2.0 f=400000, s=(0,0), exp=(0,0), frac=(4194304,400000) > Conversion: f=0, s=(0,0), exp=(896,380), frac=(0,0) > reverted: f=400000, s=(0,0), exp=(0,0), frac=(4194304,400000) > >
#include <stdio.h> union _FP_UNION_D { double flt; long l; struct { unsigned long long frac : 64-12; unsigned exp : 11 ; unsigned sign : 1; } bits __attribute__((packed)); } ud; union _FP_UNION_S { float flt; int i; struct { unsigned int frac : 32-9; unsigned exp : 8 ; unsigned sign : 1; } bits __attribute__((packed)); } uf; int main() { int errout; #if defined(__alpha__) && 0 unsigned long fpcr; asm( "excb; mf_fpcr %0" : "=f"(fpcr)); printf(" fpcr = %p\n", fpcr ); #if 1 fpcr |= (1L << 47); /* DNOD Not avail in 21264(a) */ fpcr &= ~(1L << 48 ); /* DNZ idenormal Operands to Zero */ fpcr |= (1L << 49); /* DNOD Not avail in 21264(a) */ fpcr &= ~(1L << 60 ); /* UNDZ underflow to zero OFF */ fpcr |= (1L << 61); /* UNFD underflow disable ON */ /* fpcr |= (1L << 62); UNFD */ asm volatile ( "mt_fpcr %0 ; excb" : : "f"(fpcr)); #endif asm( "excb; mf_fpcr %0" : "=f"(fpcr)); printf(" fpcr = %p\n", fpcr ); #endif underflow(); } void printF( float, char *); void printD( double, char *); int underflow() { int dsb=32-9, dme=-126; int expLimit = dme - dsb + 1; float divisor = 2.0; float d = 1.0, e; float prev=0; int i; double conversion; for (i=0; i>=expLimit; i--) { printf("I=%d\t prev=%16.14g, d=%16.14g\n",i, prev, d); printF( d, "Value:\t"); prev = d; if ((d /= divisor) >= prev) { printf("Oops. growing larger ? \n"); return; } else if (d == 0) break; conversion = d; /* double <= float */ e = conversion; /* float <= double */ printF( d, "V\\=2.0\t"); printD( conversion, "Conversion:"); printF( e, "reverted:"); if ( d != e ){ /* Still same ? */ printf(" Conversion failed \n"); break; } }; printf("i = %d, expLimit= %d\n",i,expLimit); if (i > expLimit) printf("Oops, didnt do all denormal numbers\n"); return; } void printF( float d, char *msg ) { uf.flt = d; printf("%s\tf=%x, s=(%d,%x), exp=(%d,%x), frac=(%d,%x)\n", msg, uf.i, uf.bits.sign, uf.bits.sign, uf.bits.exp, uf.bits.exp, uf.bits.frac, uf.bits.frac ); } void printD( double d, char *msg) { ud.flt = d; printf("%s\tf=%lx, s=(%d,%x), exp=(%d,%x), frac=(%ld,%lx)\n", msg, ud.l, ud.bits.sign, ud.bits.sign, ud.bits.exp, ud.bits.exp, ud.bits.frac, ud.bits.frac ); }