Объясни подробно, как код:
#include <stdint.h>

// Helper macros to extract sign, exponent, and mantissa
#define FP16_SIGN(x)    ((x) >> 15)
#define FP16_EXP(x)     (((x) >> 10) & 0x1F)
#define FP16_MANT(x)    ((x) & 0x3FF)

// Function to cast a 32-bit unsigned integer to FP16
uint16_t fp16_cast(unsigned int x) {
    if (x == 0) {
        return 0;
    }

    // Find the position of the highest set bit
    int p = 0;
    unsigned int temp = x;
    while ((temp >>= 1)) {
        p++;
    }

    int exponent = p + 15;

    if (exponent >= 31) {
        // Overflow, represent as infinity
        return 0x7C00;
    }

    // Calculate mantissa
    unsigned int mantissa;
    if (p > 10) {
        mantissa = (x >> (p - 10)) & 0x3FF;
    } else {
        mantissa = (x << (10 - p)) & 0x3FF;
    }

    return (exponent << 10) | mantissa;
}

// Function to multiply FP16 by 2
uint16_t fp16_mul2(uint16_t x) {
    uint16_t sign = x & 0x8000;
    uint16_t exp = (x >> 10) & 0x1F;
    uint16_t mant = x & 0x3FF;

    if (exp == 0x1F) {
        // Infinity or NaN
        return x;
    }

    if (exp == 0) {
        // Subnormal number, shift mantissa left
        mant <<= 1;
        if (mant & 0x400) {
            // Normalize the number
            mant &= 0x3FF;
            exp = 1;
        }
    } else {
        exp += 1;
        if (exp == 0x1F) {
            // Overflow to infinity
            mant = 0;
        }
    }

    return sign | (exp << 10) | mant;
}

// Function to divide FP16 by 2
uint16_t fp16_div2(uint16_t x) {
    uint16_t sign = x & 0x8000;
    uint16_t exp = (x >> 10) & 0x1F;
    uint16_t mant = x & 0x3FF;

    if (exp == 0x1F) {
        // Infinity or NaN
        return x;
    }

    if (exp == 0) {
        // Subnormal number, shift mantissa right
        mant >>= 1;
    } else {
        if (exp > 1) {
            exp -= 1;
        } else {
            // Transition to subnormal
            exp = 0;
            mant = (mant | 0x400) >> 1;
        }
    }

    return sign | (exp << 10) | mant;
}

// Function to negate an FP16 number
uint16_t fp16_neg(uint16_t x) {
    return x ^ 0x8000;
}

// Function to add two FP16 numbers
uint16_t fp16_add(uint16_t x, uint16_t y) {
    // Extract components of x
    uint16_t sign_x = FP16_SIGN(x);
    uint16_t exp_x = FP16_EXP(x);
    uint16_t mant_x = FP16_MANT(x);

    // Extract components of y
    uint16_t sign_y = FP16_SIGN(y);
    uint16_t exp_y = FP16_EXP(y);
    uint16_t mant_y = FP16_MANT(y);

    // Handle special cases: NaN
    if (exp_x == 0x1F) {
        if (mant_x != 0) return x; // x is NaN
        if (exp_y == 0x1F && mant_y != 0) return y; // y is NaN
        return x; // x is infinity
    }
    if (exp_y == 0x1F) {
        if (mant_y != 0) return y; // y is NaN
        return y; // y is infinity
    }

    // Normalize mantissas (add implicit leading 1 if normalized)
    uint32_t mantissa_x = (exp_x != 0) ? (1 << 10) | mant_x : mant_x;
    uint32_t mantissa_y = (exp_y != 0) ? (1 << 10) | mant_y : mant_y;

    // Align exponents
    if (exp_x > exp_y) {
        int delta = exp_x - exp_y;
        if (delta > 13) {
            mantissa_y = 0;
            exp_y = exp_x;
        } else {
            mantissa_y >>= delta;
            exp_y = exp_x;
        }
    } else if (exp_y > exp_x) {
        int delta = exp_y - exp_x;
        if (delta > 13) {
            mantissa_x = 0;
            exp_x = exp_y;
        } else {
            mantissa_x >>= delta;
            exp_x = exp_y;
        }
    }

    // Now exp_x == exp_y
    uint16_t result_sign;
    uint32_t result_mantissa;

    if (sign_x == sign_y) {
        // Same sign: add mantissas
        result_mantissa = mantissa_x + mantissa_y;
        result_sign = sign_x;
        if (result_mantissa & (1 << 11)) {
            // Carry out, normalize
            result_mantissa >>= 1;
            exp_x += 1;
            if (exp_x == 0x1F) {
                // Overflow to infinity
                return (result_sign << 15) | (0x1F << 10);
            }
        }
    } else {
        // Different signs: subtract mantissas
        if (mantissa_x > mantissa_y) {
            result_mantissa = mantissa_x - mantissa_y;
            result_sign = sign_x;
        } else if (mantissa_y > mantissa_x) {
            result_mantissa = mantissa_y - mantissa_x;
            result_sign = sign_y;
        } else {
            // Result is zero
            return 0;
        }

        // Normalize the result
        while ((result_mantissa & (1 << 10)) == 0 && exp_x > 0) {
            result_mantissa <<= 1;
            exp_x -= 1;
        }
    }

    // Handle subnormal results
    if (exp_x == 0) {
        // Subnormal, no implicit leading 1
    } else {
        // Remove implicit leading 1 for normalized numbers
        result_mantissa &= 0x3FF;
    }

    // Handle exponent overflow
    if (exp_x >= 0x1F) {
        return (result_sign << 15) | (0x1F << 10);
    }

    return (result_sign << 15) | (exp_x << 10) | (result_mantissa & 0x3FF);
}

// Function to compare two FP16 numbers
int fp16_cmp(uint16_t x, uint16_t y) {
    // Extract signs
    uint16_t sign_x = FP16_SIGN(x);
    uint16_t sign_y = FP16_SIGN(y);

    if (sign_x != sign_y) {
        return sign_x ? -1 : 1;
    }

    // If signs are the same, compare magnitudes
    if (x == y) {
        return 0;
    }

    if (sign_x == 0) {
        // Positive numbers
        return (x > y) ? 1 : -1;
    } else {
        // Negative numbers
        return (x > y) ? -1 : 1;
    }
}

Решает задачу:

В этой задаче мы будем работать с 16-битным представлением вещественных чисел, известным как FP16 или half precision — число половинной точности стандарта соответствующего numpy.float16. В таком представлении 1 бит знака, 5 бит экспоненты (которая хранится с bias 15) и 10 бит дробной части мантиссы. Хранить такие числа мы будем в переменных типа uint16_t.

Напишите следующие функции для работы с числами:

uint16_t fp16_cast(unsigned int x) - преобразующее обычное беззнаковое 32 битное число в число с плавающей точкой

uint16_t fp16_mul2(uint16_t x) - умножающее fp16 на 2

uint16_t fp16_div2(uint16_t x) - делящее fp16 на 2

uint16_t fp16_neg(uint16_t x) - меняющее знак числа

uint16_t fp16_add(uint16_t x, uint16_t y) - складывающее произвольные числа fp16

int fp16_cmp(uint16_t x, uint16_t y) - возвращающее -1 (x < y) 0 (x == y) или 1 (x > y).

В данной задаче пользоваться любыми нецелочисленными типами запрещено

Удобный сайт для просмотра битовой записи