From: Fabien P. <fab...@re...> - 2002-05-22 14:43:31
|
Bonjour, Voil=E0 une premi=E8re version de librairie flottante pour le gbdk, =E9vi= demment elle est bugg=E9e, mais je pense qu'en testant les fonctions une = par une, il doit =EAtre possible de valider et d=E9bugguer chaque fonction. Sont not=E9es //FAP les modifs par rapport =E0 la version d'origine sdcc = o=F9 j'ai piqu=E9 le code pour que gbdk puisse compiler. //ok c'est quand j'ai test=E9 et que pour moi c'est bon. Avis aux amateurs, pour d=E9bugguer, tester, je suis =E0 votre dispositio= n pour toute question sur ce code. Il faudrait valider que les calculs sur les long sont valides, sinon on a= urait plus vite fait de tout r=E9=E9crire de 0. A+ Fabien le code : ------------------------------------------------- #include <stdio.h> /* the following deal with IEEE single-precision numbers */ #define EXCESS 126 #define SIGNBIT ((unsigned long)0x80000000) #define HIDDEN (unsigned long)(1 << 23) #define SIGN(fp) ((fp >> (8*sizeof(fp)-1)) & 1) #define EXP(fp) (((fp) >> 23) & (unsigned int) 0x00FF) #define MANT(fp) (((fp) & (unsigned long)0x007FFFFF) | HIDDEN) #define PACK(s,e,m) ((s) | ((e) << 23) | (m)) #define ULONG_MAX 0xffffffff #define DEFAULT_FLOAT_PRECISION 6 union float_long { float f; long l; }; char output_ptr[150] ; static int charsOutputted =3D 0; static void output_char( char c ) { output_ptr[charsOutputted++] =3D c; } // compare two floats // lower than <=3D //FAP char fslt (float a1, float a2) { volatile union float_long fl1, fl2; fl1.f =3D a1; fl2.f =3D a2; if (SIGN (fl1.l) && SIGN (fl2.l)) { fl1.l ^=3D SIGNBIT; fl2.l ^=3D SIGNBIT; } if (fl1.l < fl2.l) return (1); return (0); } /* convert float to unsigned long */ unsigned long fs2ulong (float a1) { volatile union float_long fl1; volatile int exp; volatile long l; fl1.f =3D a1; if (!fl1.l || SIGN(fl1.l)) return (0); if (fslt(ULONG_MAX,a1)) return ULONG_MAX; exp =3D EXP (fl1.l) - EXCESS - 24; l =3D MANT (fl1.l); l >>=3D -exp; return l; } /* add two floats */ float fsadd (float a1, float a2) { volatile long mant1, mant2; volatile union float_long fl1, fl2; volatile int exp1, exp2; volatile long sign =3D 0; fl1.f =3D a1; fl2.f =3D a2; /* check for zero args */ if (!fl1.l) return (fl2.f); if (!fl2.l) return (fl1.f); exp1 =3D EXP (fl1.l); exp2 =3D EXP (fl2.l); if (exp1 > exp2 + 25) return (fl1.f); // return (fl1.l); //FAP if (exp2 > exp1 + 25) return (fl2.f); // return (fl2.l); //FAP /* do everything in excess precision so's we can round later */ mant1 =3D MANT (fl1.l) << 6; mant2 =3D MANT (fl2.l) << 6; if (SIGN (fl1.l)) mant1 =3D -mant1; if (SIGN (fl2.l)) mant2 =3D -mant2; if (exp1 > exp2) { mant2 >>=3D exp1 - exp2; } else { mant1 >>=3D exp2 - exp1; exp1 =3D exp2; } mant1 +=3D mant2; if (mant1 < 0) { mant1 =3D -mant1; sign =3D SIGNBIT; } else if (!mant1) return (0); /* normalize up */ while (!(mant1 & (unsigned long) 0xE0000000)) { mant1 <<=3D 1; exp1--; } /* normalize down? */ if (mant1 & (unsigned long)(1 << 30)) { mant1 >>=3D 1 ; exp1++; } /* round to even */ mant1 +=3D (mant1 & (unsigned long)0x40) ? (unsigned long) 0x20 : (unsi= gned long) 0x1F; /* normalize down? */ if (mant1 & (unsigned long)(1 << 30)) { mant1 >>=3D 1; exp1++; } /* lose extra precision */ mant1 >>=3D 6; /* turn off hidden bit */ mant1 &=3D ~HIDDEN; /* pack up and go home */ fl1.l =3D PACK (sign, (unsigned long) exp1, mant1); return (fl1.f); } /* subtract two floats */ float fssub (float a1, float a2) { volatile union float_long fl1, fl2; fl1.f =3D a1; fl2.f =3D a2; /* check for zero args */ if (!fl2.l) return (fl1.f); if (!fl1.l) { //return (-fl2.f); //FAP fl2.l ^=3D SIGNBIT; //FAP return (fl2.f); //FAP } /* twiddle sign bit and add */ fl2.l ^=3D SIGNBIT; return fsadd(fl1.f, fl2.f); //return fl1.f + fl2.f;//FAP } float ulong2fs (unsigned long a ) { int exp =3D 24 + EXCESS; volatile union float_long fl; if (!a) { return 0.0; } while (a < HIDDEN) { a <<=3D 1; exp--; } a &=3D ~HIDDEN ; /* pack up and go home */ fl.l =3D PACK(0,(unsigned long)exp, a); return (fl.f); } /* convert signed long to float */ float slong2fs (signed long sl) { volatile union float_long fl; if (sl<0) { // return -ulong2fs(-sl); //FAP fl.f =3D ulong2fs(-sl);//FAP fl.l ^=3D SIGNBIT;//FAP return fl.f;//FAP } else return ulong2fs(sl); } /* multiply two floats */ float fsmul (float a1, float a2) { volatile union float_long fl1, fl2; volatile unsigned long result; volatile int exp; char sign; fl1.f =3D a1; fl2.f =3D a2; if (!fl1.l || !fl2.l) return (0); /* compute sign and exponent */ sign =3D SIGN (fl1.l) ^ SIGN (fl2.l); exp =3D EXP (fl1.l) - EXCESS; exp +=3D EXP (fl2.l); fl1.l =3D MANT (fl1.l); fl2.l =3D MANT (fl2.l); /* the multiply is done as one 16x16 multiply and two 16x8 multiples */= result =3D (fl1.l >> 8) * (fl2.l >> 8); result +=3D ((fl1.l & (unsigned long) 0xFF) * (fl2.l >> 8)) >> 8; result +=3D ((fl2.l & (unsigned long) 0xFF) * (fl1.l >> 8)) >> 8; if (result & (unsigned long)0x80000000) { /* round */ result +=3D 0x80; result >>=3D 8; } else { /* round */ result +=3D 0x40; result >>=3D 7; exp--; } result &=3D ~HIDDEN; /* pack up and go home */ fl1.l =3D PACK (sign ? ((unsigned long) 0x80000000) : 0 , (unsigned lon= g)exp, result); return (fl1.f); } static void output_float (float f, unsigned char reqWidth, signed char reqDecimals, unsigned char left, unsigned char zero, unsigned char sign, unsigned= char space) { unsigned char minWidth, i; char negative=3D0; long integerPart; float decimalPart; char fpBuffer[128]; char fpBI=3D0, fpBD; volatile union float_long tmp; tmp.f =3D f; // save the sign if (SIGN (tmp.l)) { // if (f<0) { //FAP negative=3D1; tmp.l ^=3D SIGNBIT; // f=3D-f; //FAP } // split the float integerPart =3D fs2ulong(tmp.f);// integerPart =3D f; //FAP decimalPart =3D fssub(tmp.f, slong2fs(integerPart)); // decimalPart =3D= tmp.f - integerPart; //FAP // fill the buffer with the integerPart (in reversed order!) while (integerPart) { char i =3D integerPart%10; fpBuffer[fpBI++]=3D'0' + integerPart%10; integerPart /=3D 10; } if (!fpBI) { // we need at least a 0 fpBuffer[fpBI++]=3D'0'; } // display some decimals as default if (reqDecimals=3D=3D-1) reqDecimals=3DDEFAULT_FLOAT_PRECISION; // fill buffer with the decimalPart (in normal order) fpBD=3DfpBI; if (i=3DreqDecimals ) { // that's an assignment do { decimalPart =3D fsmul(decimalPart, 10.0);//decimalPart *=3D 10.0; /= /FAP // truncate the float integerPart=3Dfs2ulong(decimalPart); // integerPart=3DdecimalPart; = //FAP fpBuffer[fpBD++]=3D'0' + integerPart; decimalPart=3Dfssub(decimalPart,ulong2fs(integerPart)); //decimalPa= rt-=3DintegerPart; //FAP } while (--i); } minWidth=3DfpBI; // we need at least these minWidth+=3DreqDecimals?reqDecimals+1:0; // maybe these if (negative || sign || space) minWidth++; // and maybe even this :) if (!left && reqWidth>i) { if (zero) { if (negative) output_char('-'); else if (sign) output_char('+'); else if (space) output_char(' '); while (reqWidth-->minWidth) output_char ('0'); } else { while (reqWidth-->minWidth) output_char (' '); if (negative) output_char('-'); else if (sign) output_char('+'); else if (space) output_char (' '); } } else { if (negative) output_char('-'); else if (sign) output_char('+'); else if (space) output_char(' '); } // output the integer part i=3DfpBI-1; do { output_char (fpBuffer[i]); } while (i--); // ouput the decimal part if (reqDecimals) { output_char ('.'); i=3DfpBI; while (reqDecimals--) output_char (fpBuffer[i++]); } if (left && reqWidth>minWidth) { while (reqWidth-->minWidth) output_char(' '); } output_char(0); charsOutputted =3D 0; } // compare two floats // greater than >=3D //FAP char fsgt (float a1, float a2) { volatile union float_long fl1, fl2; fl1.f =3D a1; fl2.f =3D a2; if (SIGN (fl1.l) && SIGN (fl2.l)) { fl1.l ^=3D SIGNBIT; fl2.l ^=3D SIGNBIT; } if (fl1.l > fl2.l) return (1); return (0); } /* compare two floats */ char fsneq (float a1, float a2) { volatile union float_long fl1, fl2; fl1.f =3D a1; fl2.f =3D a2; if (SIGN (fl1.l) && SIGN (fl2.l)) { fl1.l ^=3D SIGNBIT; fl2.l ^=3D SIGNBIT; } if (fl1.l =3D=3D fl2.l) return (0); return (1); } /* compare two floats */ char fseq (float a1, float a2) //ok { volatile union float_long fl1, fl2; fl1.f =3D a1; fl2.f =3D a2; if (SIGN (fl1.l) && SIGN (fl2.l)) { fl1.l ^=3D SIGNBIT; fl2.l ^=3D SIGNBIT; } if (fl1.l =3D=3D fl2.l) return (1); return (0); } void main() { float a =3D -0.03; //ok float b =3D 0.02; //ok float c; c =3D fsadd(a,b); if (fsgt(-0.03, -0.02)) printf("ok\n"); output_float (a, 0, -1, 0, 0, 1, 1); printf("%s\n", output_ptr); output_float (b, 0, -1, 0, 0, 1, 1); printf("%s\n", output_ptr); output_float (c, 0, -1, 0, 0, 1, 1); printf("%s\n", output_ptr); } ------------------------------------------------- le makefile.bat ------------------------------------------------- =2E.\..\bin\lcc -Wa-l -Wl-m -Wl-j -c -o float_gbdk.o float_gbdk.c =2E.\..\bin\lcc -Wa-l -Wl-m -Wl-j -o float_gbdk.gb float_gbdk.o ------------------------------------------------- |