sinyaw@sinyaw.UUCP (04/06/87)
Ever need to know what is the value of the exponetial field of the floating point variable? Or the matissa? This is a handy function to extract them for you. It works for 680x0 and 80x86 machines (Sun OS 3.2 and Xenix). The byte ordering is decided at run time. There is no need to make different versions for different machines. (I know this doesn't make sense since you have to recompile for each machine anyway. But I just like runtime switching, OK.) For Vax users, compile with -DVAX instead of -DIEEE. See header comments. It works for 4 bytes float only. If you need to check for 8 bytes floating point value, do it yourself. I am interested in how this function works on different systems. Please mail me the results of your testing. It is only one small file. I see no point doing shar. Sin-Yaw Wang, sinyaw@sun --------------------------- CUT HERE -------------------------- /* * frange.c 1.1 of 4/6/87 by Sin-Yaw Wang, Sun MicroSystems. * @(#)frange.c 1.1 */ /* * This is a handy utility to get you the exponential and the matissa * fields of a 4 bytes floating point variable in IEEE format. It knows * what is byte swapping, but assumes float uses the same swaapping scheme * as long. It has been tested on Sun and IBM PC/AT (Xenix). The Vax * version needs to be done with conditional compilation. Please try it * on your local machine and tell me if it works. If you need to modify * it, please mail me your changes. * * Sin-Yaw Wang, sinyaw@sun * * Compilation instructions: * For Sun and PC/AT * cc -O -o frange -DIEEE -DTEST filename.c * For Vax * cc -O -o frange -DVAX -DTEST filename.c * * Don't define TEST if you don't need a "main()" */ #include <stdio.h> #define DONTKNOW 4 #define REGULAR 3 #define SWAP 0 int byteorder; #ifdef IEEE /* macro to compute byte sequence at run time */ #define FIRSTBYTE (byteorder ^ 3) #define SECONDBYTE (byteorder ^ 2) #define THIRDBYTE (byteorder ^ 1) #define FOURTHBYTE (byteorder & 3) #define FBIAS 127 /* IEEE standard */ #endif #ifdef VAX /* what a funny byte sequence */ /* * I should come up with a run time switching scheme instead of doing this * at compile time. */ #define FIRSTBYTE (byteorder ^ 1) #define SECONDBYTE (byteorder & 3) #define THIRDBYTE (byteorder ^ 3) #define FOURTHBYTE (byteorder ^ 2) #define FBIAS 129 /* this is strange */ #endif #ifdef TEST #define VALUE 0.0 #define ENDV 10.0 #define INC (1.0/6.0) main() { float f; int exp; float mat; for (f = VALUE; f < ENDV; f += INC) if (frange(f, &exp, &mat) >= 0) printf("%15.10f = %15.13f * 2 exp %3d\n", f, mat, exp); else { printf("unknown floating format\n"); return; } } #endif int frange(value, exp, mat) double value; /* compiler convert all float to * double */ int *exp; float *mat; /* but not float pointers */ { float f; /* 4 bytes */ float matissa(); int e; float m; byteorder = order(); /* should be called at initialization */ if (byteorder == DONTKNOW) return -1; f = (float) value; /* make sure it is a 4 byte value */ e = exponent((char *) &f); /* is it portable? I don't know */ m = matissa((char *) &f); if (e) /* should check for both zero and all * ones */ { e -= FBIAS; m += 1.0; /* de-normalized if e is zero */ } *exp = e; *mat = m; return 0; } int exponent(f) char *f; { unsigned int e1, e2; int e; /* * the lowest 7 bits of the first byte and the highest bit of the * second byte make up the exponetial part. But which one is the * "first byte"... * * another idea e = (((short *) f)[0] & 0x7f80) >> 7; */ e1 = f[FIRSTBYTE] & 0x7f; e2 = f[SECONDBYTE] & 0x80; e = (e1 << 1) | (e2 >> 7); return e; /* exponential value (based 2) */ } float matissa(f) char *f; { register int loop = 24; /* loop counter */ unsigned long m1, m2; /* 32 bits */ long m; /* matissa bit pattern */ float mat; /* matisaa value */ m1 = f[SECONDBYTE] & 0x7f; /* lowset 7 bits of the second byte */ m1 <<= 16; m2 = f[THIRDBYTE] & 0xff; /* every bits of the third byte */ m2 = m2 << 8 | (f[FOURTHBYTE] & 0xff); /* and the fourth byte */ m = m1 | m2; /* the bit pattern of the matissa */ mat = 0.0; if (m) while (--loop) { mat /= 2.0; mat += (float) (m & 1) / 2.0; m >>= 1; } return mat; } static int order() /* * kind of naive to assume 4 byte float has the same seqence of 4 byte * integer. Fortuately, this is true for most of the machines. * Unfortunately it is false for VAX, a popular computer. */ { static long swap_test; static char *i; swap_test = 0x0102; /* assign first 2 bytes */ swap_test <<= 16; /* shift over 16 bits */ swap_test |= 0x0408; /* assign last 2 bytes */ i = (char *) &swap_test; if ((i[0] & 0x08) && (i[1] & 0x04) && (i[2] & 0x02) && (i[3] & 0x01)) return SWAP; else if ((i[0] & 0x01) && (i[1] & 0x02) && (i[2] & 0x04) && (i[3] & 0x08)) return REGULAR; else return DONTKNOW; }