2.97 Float i2f

★★★★

Problem:

Following the bit-level floating-point coding rules, implement the function with the following prototype:

/* Compute (float) i */
float_bits float_i2f(int i);

For argument i, this function computes the bit-level representation of (float) i.

Test your function by evaluating it for all 2^32 values of argument f and comparing the result to what would be obtained using your machine's floating-point operations.

Code:

#include <stdio.h>
#include <assert.h>
#include <limits.h>

typedef unsigned float_bits;

/* Get bit length for integer i. Return 32 when i is negative. */
int bits_length(int i) {
    if ((i & INT_MIN) != 0) {
        return 32;
    }

    int length = 0;
    unsigned u = (unsigned)i;
    while(u >= (1 << length)) {
        length++;
    }
    return length;
}

/* Generage mask for length len. e.g. 3->0x7 */
unsigned generate_mask(int len) {
    return (unsigned)-1 >> (32-len);
}

float_bits float_i2f(int i) {
    unsigned sign, exp, frac, exp_frac;
    unsigned bias = 0x7F;

    /* i = 0 */
    if (i == 0) {
        sign = 0;
        exp = 0;
        frac = 0;
        return sign << 31 | exp << 23 | frac;
    }

    /* i = INT_MIN */
    if (i == INT_MIN) {
        sign = 1;
        exp = 31 + bias;
        frac = 0;
        return sign << 31 | exp << 23 | frac;
    }

    sign = 0;
    /* i is negative */
    if (i < 0) {
        sign = 1;
        i = -i;
    }

    int length = bits_length(i);
    int flength = length - 1;
    unsigned mask = generate_mask(flength);
    unsigned f = i & mask;
    exp = bias + length - 1;

    if (flength <= 23) {
        /* no overflow */
        frac = f << (23 - flength);
        exp_frac = exp << 23 | frac;
    } else {
        /* overflow */
        int offset = flength - 23;
        frac = f >> offset;
        exp_frac = exp << 23 | frac;
        int round_mid = 1 << (offset - 1);
        int round_part = f & generate_mask(offset);

        /* round to even */
        if (round_part < round_mid) {

        } else if (round_part > round_mid) {
            exp_frac += 1;
        } else {
            if ((frac & 0x1) == 1) {
                exp_frac += 1;
            }
        }
    }
    return sign << 31 | exp_frac;
}

int main() {
    /* Test bits_length */
    assert(bits_length(-1) == 32);
    assert(bits_length(INT_MIN) == 32);
    assert(bits_length(0) == 0);
    assert(bits_length(3) == 2);
    assert(bits_length(23) == 5);

    /* Test generate_mask */
    assert(generate_mask(3) == 0x7);
    assert(generate_mask(9) == 0x1FF);
    assert(generate_mask(31) == 0x7FFFFFFF);

    /* Test float_i2f */
    assert(float_i2f(0) == 0x0);
    assert(float_i2f(INT_MIN) == 0xCF000000);
    assert(float_i2f(0x00359141) == 0x4A564504);
    assert(float_i2f(-98765) == 0xC7C0E680);
    return 0;
}

Last updated