ahmedgu - 1 year ago 124
C Question

# Floating point representation (using bitwise operators)

This is a solution to a problem to print the representation of a floating point (i.e : x = (−1)^sign · (1.m 22 m 21 m 20 . . . m 0 ) · 2^(e −bias) ) and I haven't understood some things in it :
1) The use of the union, why ?
3) the use of & in here :

``````  uint32_t exponent = ( t.bits >> MANTISSA_WIDTH ) & EXPONENT_MASK;
uint32_t mantissa = ( t.bits  &  MANTISSA_MASK );
``````

Here's the code :

``````#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>

#define ABSOLUTE_WIDTH 31
#define MANTISSA_WIDTH 23
#define EXPONENT_WIDTH 8
#define EXPONENT_BIAS 127

union float_bits {
float f;
uint32_t bits;
};

void print_float( FILE *output, float f ) {
union float_bits t; t.f = f;

uint32_t sign_bit = ( t.bits >> ABSOLUTE_WIDTH );
uint32_t exponent = ( t.bits >> MANTISSA_WIDTH ) & EXPONENT_MASK;
uint32_t mantissa = ( t.bits  &  MANTISSA_MASK );

if( sign_bit != 0 ) {
fprintf( output, "-" );
}

if( exponent > 2 * EXPONENT_BIAS ) {
fprintf( output, "Inf\n" ); /* Infinity */
return;
} else if( exponent == 0 ) {
fprintf( output, "0." ); /* Zero or Denormal */
exponent = ( mantissa != 0 ) ? exponent + 1 : exponent;
} else {
fprintf( output, "1." ); /* Usual */
}

for( int k = MANTISSA_WIDTH - 1; k >= 0; --k ) {
fprintf( output, "%d", ( mantissa >> k ) & 1 );
}

if( exponent != 0 || mantissa != 0 ) {
fprintf( output, " * 2^%d\n", (int) ( exponent - EXPONENT_BIAS ) );
}
}

int main() {
FILE *input  = fopen( "floating.in",  "r" ),
*output = fopen( "floating.out", "w" );

size_t N; float f;
fscanf( input, "%zu", &N );

for( size_t i = 0; i < N; ++i ) {
fscanf( input, "%f", &f );
print_float( output, f );
}

fclose( input );
fclose( output );
return 0;
}
``````

1) The use of the union, why ?

The bit operators are available for integral types only. You cannot convert the floating point number to an integer for obvious reasons. But a union locates the memory of the components overlapping. So by writing into the floating point component and then reading the integral component returns a integral representation of the floating point number. To make that clear: This is not the integral value of the floating point number. Using it as an integral number in calculations will give unexpected results. But you can access the bits of the integral number as it would be the bits of the floating point number.

Floating point numbers are represented by a number of bits specifying the mantissa (the digit string) and by an exponent part representing the "location" of the digits. After "conversion" of the floating point number into an integral type, this two parts are mixed in the integral value. `MANTISSA_MASK` and `EXPONENT_MASK` (you have a typo in your Q) masks out that parts. `MANTISSA_BITS` moves the exponent to the right place.

3) the use of `&` in here:

It is the bit and operator that masks out the bits.

Let's have an – completely virtual – example:

From your code you have 23 bits of mantissa and 8 bits of exponent. One bit of the 32 bits is reserved for the sign. Let's have a number:

``````00000001000010011010011010101010
``````

Having 1 sign bit, 8 exponent bits and 23 mantissa bits you can read it like this

``````0 00100010 00010011010011010101010
s exponent --------mantissa-------
``````

To get the mantissa you use a mask that only has the mantissa bits set:

``````0 00000000 11111111111111111111111
``````

When you bit-and it, only bits that are 1 in both operands are 1, every other bit is 0:

``````0 00100010 00010011010011010101010 A
0 00000000 11111111111111111111111 B
- -------- -----------------------
0 00000000 00010011010011010101010 A&B
``````

The mantissa is isolated from the exponent (and now a real integer value representing the mantissa.

To get the exponent, you first shift right the whole word so that the exponent starts from bit 0 (right most):

``````0 00100010 00010011010011010101010
00000000000000000000000 0 00100010 >> 23 (mantissa bist)
``````

To isolate the exponent from the sign bit, you have to bit-and it again:

``````00000000000000000000000 0 00100010 A
00000000000000000000000 0 11111111 B
------------------------------------
00000000000000000000000 0 00100010 A&B
``````

Et voíla.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download