Link to home
Start Free TrialLog in
Avatar of CoolJFN
CoolJFN

asked on

How do I convert the comp_t data type to a float in C, given its encoding?

I need to convert the Linux C comp_t data type to a float, or something else I can print out. The description of this type is

/*
 *  comp_t is a 16-bit "floating" point number with a 3-bit base 8
 *  exponent and a 13-bit fraction. See linux/kernel/acct.c for the
 *  specific encoding system used.
 */

typedef __u16   comp_t;

I have looked up the encoding function, but still do not know how I can decode it (i.e., convert to a standard data type):

  224 /*
  225  *  encode an unsigned long into a comp_t
  226  *
  227  *  This routine has been adopted from the encode_comp_t() function in
  228  *  the kern_acct.c file of the FreeBSD operating system. The encoding
  229  *  is a 13-bit fraction with a 3-bit (base 8) exponent.
  230  */
  231
  232 #define MANTSIZE        13                      /* 13 bit mantissa. */
  233 #define EXPSIZE         3                       /* Base 8 (3 bit) exponent. */
  234 #define MAXFRACT        ((1 << MANTSIZE) - 1)   /* Maximum fractional value. */
  235
  236 static comp_t encode_comp_t(unsigned long value)
  237 {
  238         int exp, rnd;
  239
  240         exp = rnd = 0;
  241         while (value > MAXFRACT) {
  242                 rnd = value & (1 << (EXPSIZE - 1));     /* Round up? */
  243                 value >>= EXPSIZE;      /* Base 8 exponent == 3 bit shift. */
  244                 exp++;
  245         }
  246
  247         /*
  248          * If we need to round up, do it (and handle overflow correctly).
  249          */
  250         if (rnd && (++value > MAXFRACT)) {
  251                 value >>= EXPSIZE;
  252                 exp++;
  253         }
  254
  255         /*
  256          * Clean it up and polish it off.
  257          */
  258         exp <<= MANTSIZE;               /* Shift the exponent into place */
  259         exp += value;                   /* and add on the mantissa. */
  260         return exp;
  261 }

What would be a function to convert it back? THANKS!
Avatar of nikhiledu
nikhiledu

A possible solution is to extract the fractional components for the mantissa and the exponent from the bits encoded in the comp_t value supplied and to create a double number from these fractional components. This algorithm is coded in the function comp_t_to_double() as given below.


/* This function converts from comp_t to double value for exponent base 10. */
double comp_t_to_double(comp_t value)
{
	double dval = 0;
	int exp = 0;
 
	/*
	* Get the fraction components.
	*/
	exp = value >> MANTSIZE;        /* Get the exponent (first 3 bits). */
	dval = (value & MAXFRACT);        /* Get the mantissa (last 13 bits). */
 
	for(int i=0; i < exp; i++) {
		dval /= 10;
	}
 
	return dval;
}

Open in new window

Avatar of Infinity08
>> What would be a function to convert it back?

Right from the docs :

        comp_t c;
        unsigned long v = (c & 0x1fff) << (((c >> 13) & 0x7) * 3);

converts the comp_t value c to an unsigned long value v.
ASKER CERTIFIED SOLUTION
Avatar of Infinity08
Infinity08
Flag of Belgium image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial