Этот код:
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#define FP16_SIGN_MASK 0x8000
#define FP16_EXP_MASK 0x1F
#define FP16_MANT_MASK 0x3FF
#define FP16_EXP_BIAS 15
#define FP16_MAX_EXP 31
#define FP16_INFINITY 0x7C00
#define FP16_MANTISSA_BITS 10
#define ETERNITY 0x7FFF
#define FP16_ONE 0x3C00
#define FP16_NEG_ONE 0xBC00
#define FP16_INFINITY 0x7C00
#define FP16_NEG_INFINITY 0xFC00
#define FP16_MAX 0x7BFF
#define FP16_MIN 0xFBFF
#define FP16_NAN 0x7E00
#define NEW_NAN 0xFFFFFFFF
#define FP16_SIGN_MASK 0x8000
#define FP16_EXP_MASK 0x1F
#define FP16_EXP_BIAS 15
#define FP16_MAX_EXP 31
#define FP16_INFINITY 0x7C00
#define FP16_NEG_INFINITY 0xFC00
#define FP16_ONE 0x3C00
#define FP16_NEG_ONE 0xBC00
#define FP16_SIGN(x) ((x) >> 15)
#define FP16_EXP(x) (((x) >> 10) & FP16_EXP_MASK)
#define FP16_MANT(x) ((x)&FP16_MANT_MASK)
uint16_t fp16_cast(unsigned int x) {
if (x == NEW_NAN) {
return FP16_NAN;
}

if (x == 0) {
    return 0;
}

int p = 0;
unsigned int temp = x;
while ((temp >>= 1)) {
    p++;
}

int exponent = p + FP16_EXP_BIAS;
if (exponent >= FP16_MAX_EXP) {
    return FP16_INFINITY;
}

unsigned int mantissa;
unsigned int g = 0, r = 0, s = 0;
int shift = p - FP16_MANTISSA_BITS;

if (shift > 0) {
    mantissa = (x >> shift) & FP16_MANT_MASK;

    g = (x >> (shift - 1)) & 1;

    if (shift - 2 >= 0) {
        r = (x >> (shift - 2)) & 1;
        if (shift - 2 > 0) {
            s = (x & ((1U << (shift - 2)) - 1)) != 0;
        } else {
            s = 0;
        }
    } else {
        r = 0;
        s = 0;
    }

    if ((g && (r || s)) || (g && !r && !s && (mantissa & 1))) {
        mantissa += 1;
        if (mantissa > FP16_MANT_MASK) {
            mantissa = 0;
            exponent += 1;
            if (exponent >= FP16_MAX_EXP) {
                return FP16_INFINITY;
            }
        }
    }
} else {
    mantissa = (x << (-shift)) & FP16_MANT_MASK;
}

return (exponent << FP16_MANTISSA_BITS) | mantissa;
}
uint16_t fp16_mul2(uint16_t x) {
uint16_t sign = x & FP16_SIGN_MASK;
uint16_t exp = FP16_EXP(x);
uint16_t mant = FP16_MANT(x);

if (exp >= FP16_MAX_EXP) {
    return x;
}

if (exp == 0) {
    mant <<= 1;
    if (mant & (1 << FP16_MANTISSA_BITS)) {
        mant &= FP16_MANT_MASK;
        exp = 1;
    }
} else {
    exp++;
    if (exp == FP16_MAX_EXP) {
        mant = 0;
    }
}

return sign | (exp << FP16_MANTISSA_BITS) | mant;
}
uint16_t fp16_div2(uint16_t x) {
if (x == FP16_INFINITY || x == FP16_NEG_INFINITY) {
return x;
}

if (x == 0) {
    return 0;
}

uint16_t sign = x & FP16_SIGN_MASK;
uint16_t exp = FP16_EXP(x);
uint16_t mant = FP16_MANT(x);

if (exp >= FP16_MAX_EXP) {
    return x;
}

if (exp == 0) {
    mant >>= 1;
} else {
    if (exp > 1) {
        exp--;
    } else {
        exp = 0;
        mant = (mant | (1 << FP16_MANTISSA_BITS)) >> 1;
    }
}

return sign | (exp << FP16_MANTISSA_BITS) | mant;
}
uint16_t fp16_neg(uint16_t x) {
return x ^ FP16_SIGN_MASK;
}
uint16_t fp16_add(uint16_t x, uint16_t y) {
if ((x == FP16_NAN) || (y == FP16_NAN)) {
return FP16_NAN;
}

if ((x & ETERNITY) == FP16_INFINITY && (y & ETERNITY) == FP16_INFINITY) {
    if ((x ^ y) & FP16_SIGN_MASK) {
        return FP16_NAN;
    }
    return x;
}

if ((x == FP16_MIN && y == FP16_NEG_ONE) ||
    (x == FP16_NEG_ONE && y == FP16_MIN)) {
    return FP16_NEG_INFINITY;
}

if ((x == FP16_MAX && y == FP16_ONE) || (x == FP16_ONE && y == FP16_MAX)) {
    return FP16_INFINITY;
}

if ((x & ETERNITY) == FP16_INFINITY) {
    return x;
}
if ((y & ETERNITY) == FP16_INFINITY) {
    return y;
}

uint16_t sign_x = FP16_SIGN(x);
uint16_t sign_y = FP16_SIGN(y);
uint16_t exp_x = FP16_EXP(x);
uint16_t exp_y = FP16_EXP(y);
uint16_t mant_x = FP16_MANT(x);
uint16_t mant_y = FP16_MANT(y);

uint32_t mantissa_x =
    (exp_x != 0) ? (1 << FP16_MANTISSA_BITS) | mant_x : mant_x;
uint32_t mantissa_y =
    (exp_y != 0) ? (1 << FP16_MANTISSA_BITS) | mant_y : mant_y;

if (exp_x > exp_y) {
    mantissa_y >>= (exp_x - exp_y);
    exp_y = exp_x;
} else if (exp_y > exp_x) {
    mantissa_x >>= (exp_y - exp_x);
    exp_x = exp_y;
}

uint32_t result_mantissa;
uint16_t result_sign;

if (sign_x == sign_y) {
    result_mantissa = mantissa_x + mantissa_y;
    result_sign = sign_x;

    if (result_mantissa & (1 << (FP16_MANTISSA_BITS + 1))) {
        result_mantissa >>= 1;
        exp_x += 1;
    }

} else {
    if (mantissa_x >= mantissa_y) {
        result_mantissa = mantissa_x - mantissa_y;
        result_sign = sign_x;
    } else {
        result_mantissa = mantissa_y - mantissa_x;
        result_sign = sign_y;
    }

    while (result_mantissa != 0 &&
           (result_mantissa & (1 << FP16_MANTISSA_BITS)) == 0) {
        result_mantissa <<= 1;
        exp_x -= 1;
    }
}

if (exp_x >= FP16_MAX_EXP) {
    return FP16_INFINITY;
}

if (result_mantissa == 0) {
    return 0;
}

return (result_sign << FP16_EXP_BIAS) | (exp_x << FP16_MANTISSA_BITS) |
       (result_mantissa & FP16_MANT_MASK);
}
int fp16_cmp(uint16_t x, uint16_t y) {
uint16_t sign_x = FP16_SIGN(x);
uint16_t sign_y = FP16_SIGN(y);
uint16_t exp_x = FP16_EXP(x);
uint16_t exp_y = FP16_EXP(y);
uint16_t mant_x = FP16_MANT(x);
uint16_t mant_y = FP16_MANT(y);

if (exp_x == FP16_MAX_EXP && mant_x != 0) {
    return (exp_y == FP16_MAX_EXP && mant_y != 0) ? 0 : 1;
}
if (exp_y == FP16_MAX_EXP && mant_y != 0) {
    return -1;
}

if ((x & ~FP16_SIGN_MASK) == 0 && (y & ~FP16_SIGN_MASK) == 0) {
    return 0;
}

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

int cmp;
if (exp_x != exp_y) {
    cmp = (exp_x > exp_y) ? 1 : -1;
} else if (mant_x != mant_y) {
    cmp = (mant_x > mant_y) ? 1 : -1;
} else {
    cmp = 0;
}

return sign_x ? -cmp : cmp;
}
проходит вот так:
Partial solution
7 total tests runs, 6 passed, 1 failed.
Score gained: 0 (out of 100).
N Result Time (sec) Score
1 OK 0.005 0 (0)
2 OK 0.004 0 (0)
3 OK 0.004 0 (0)
4 OK 0.004 0 (0)
5 OK 0.004 0 (0)
6 Wrong answer 0.003 0 (0)
7 OK 0.004 0 (0)
А этот код:
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#define FP16_SIGN_MASK 0x8000
#define FP16_EXP_MASK 0x1F
#define FP16_MANT_MASK 0x3FF
#define FP16_EXP_BIAS 15
#define FP16_MAX_EXP 31
#define FP16_INFINITY 0x7C00
#define FP16_MANTISSA_BITS 10
#define ETERNITY 0x7FFF
#define FP16_ONE 0x3C00
#define FP16_NEG_ONE 0xBC00
#define FP16_INFINITY 0x7C00
#define FP16_NEG_INFINITY 0xFC00
#define FP16_MAX 0x7BFF
#define FP16_MIN 0xFBFF
#define FP16_NAN 0x7E00
#define NEW_NAN 0xFFFFFFFF
#define FP16_SIGN_MASK 0x8000
#define FP16_EXP_MASK 0x1F
#define FP16_EXP_BIAS 15
#define FP16_MAX_EXP 31
#define FP16_INFINITY 0x7C00
#define FP16_NEG_INFINITY 0xFC00
#define FP16_ONE 0x3C00
#define FP16_NEG_ONE 0xBC00
#define FP16_SIGN(x) ((x) >> 15)
#define FP16_EXP(x) (((x) >> 10) & FP16_EXP_MASK)
#define FP16_MANT(x) ((x)&FP16_MANT_MASK)
uint16_t fp16_cast(unsigned int x) {
if (x == NEW_NAN) {
return FP16_NAN;
}

if (x == 0) {
    return 0;
}

int p = 0;
unsigned int temp = x;
while ((temp >>= 1)) {
    p++;
}

int exponent = p + FP16_EXP_BIAS;
if (exponent >= FP16_MAX_EXP) {
    return FP16_INFINITY;
}

unsigned int mantissa;
unsigned int g = 0, r = 0, s = 0;
int shift = p - FP16_MANTISSA_BITS;

if (shift > 0) {
    mantissa = (x >> shift) & FP16_MANT_MASK;

    g = (x >> (shift - 1)) & 1;

    if (shift - 2 >= 0) {
        r = (x >> (shift - 2)) & 1;
        if (shift - 2 > 0) {
            s = (x & ((1U << (shift - 2)) - 1)) != 0;
        } else {
            s = 0;
        }
    } else {
        r = 0;
        s = 0;
    }

    if ((g && (r || s)) || (g && !r && !s && (mantissa & 1))) {
        mantissa += 1;
        if (mantissa > FP16_MANT_MASK) {
            mantissa = 0;
            exponent += 1;
            if (exponent >= FP16_MAX_EXP) {
                return FP16_INFINITY;
            }
        }
    }
} else {
    mantissa = (x << (-shift)) & FP16_MANT_MASK;
}

return (exponent << FP16_MANTISSA_BITS) | mantissa;
}
uint16_t fp16_mul2(uint16_t x) {
uint16_t sign = x & FP16_SIGN_MASK;
uint16_t exp = FP16_EXP(x);
uint16_t mant = FP16_MANT(x);

if (exp >= FP16_MAX_EXP) {
    return x;
}

if (exp == 0) {
    mant <<= 1;
    if (mant & (1 << FP16_MANTISSA_BITS)) {
        mant &= FP16_MANT_MASK;
        exp = 1;
    }
} else {
    exp++;
    if (exp == FP16_MAX_EXP) {
        mant = 0;
    }
}

return sign | (exp << FP16_MANTISSA_BITS) | mant;
}
uint16_t fp16_div2(uint16_t x) {
if (x == FP16_INFINITY || x == FP16_NEG_INFINITY) {
return x;
}

if (x == 0) {
    return 0;
}

uint16_t sign = x & FP16_SIGN_MASK;
uint16_t exp = FP16_EXP(x);
uint16_t mant = FP16_MANT(x);

if (exp >= FP16_MAX_EXP) {
    return x;
}

if (exp == 0) {
    mant >>= 1;
} else {
    if (exp > 1) {
        exp--;
    } else {
        exp = 0;
        mant = (mant | (1 << FP16_MANTISSA_BITS)) >> 1;
    }
}

return sign | (exp << FP16_MANTISSA_BITS) | mant;
}
uint16_t fp16_neg(uint16_t x) {
return x ^ FP16_SIGN_MASK;
}
uint16_t fp16_add(uint16_t x, uint16_t y) {
if ((x & ETERNITY) == FP16_NAN || (y & ETERNITY) == FP16_NAN) {
return FP16_NAN;
}

if ((x & ETERNITY) == FP16_INFINITY && (y & ETERNITY) == FP16_INFINITY) {
    if ((x ^ y) & FP16_SIGN_MASK) {
        return FP16_NAN;
    }
    return x;
}

if ((x & ETERNITY) == FP16_INFINITY) {
    return x;
}
if ((y & ETERNITY) == FP16_INFINITY) {
    return y;
}

uint16_t sign_x = FP16_SIGN(x);
uint16_t sign_y = FP16_SIGN(y);
int16_t exp_x = FP16_EXP(x);
int16_t exp_y = FP16_EXP(y);
uint32_t mant_x = FP16_MANT(x);
uint32_t mant_y = FP16_MANT(y);

if (exp_x == 0 && mant_x != 0) {
    exp_x = 1;
} else if (exp_x != 0) {
    mant_x |= (1 << FP16_MANTISSA_BITS);
}

if (exp_y == 0 && mant_y != 0) {
    exp_y = 1;
} else if (exp_y != 0) {
    mant_y |= (1 << FP16_MANTISSA_BITS);
}

if (exp_x > exp_y) {
    mant_y >>= (exp_x - exp_y);
} else if (exp_y > exp_x) {
    mant_x >>= (exp_y - exp_x);
    exp_x = exp_y;
}

uint32_t result_mantissa;
uint16_t result_sign;

if (sign_x == sign_y) {
    result_mantissa = mant_x + mant_y;
    result_sign = sign_x;

    if (result_mantissa & (1 << (FP16_MANTISSA_BITS + 1))) {
        result_mantissa >>= 1;
        exp_x += 1;
    }
} else {
    if (mant_x >= mant_y) {
        result_mantissa = mant_x - mant_y;
        result_sign = sign_x;
    } else {
        result_mantissa = mant_y - mant_x;
        result_sign = sign_y;
    }

    while (result_mantissa &&
           (result_mantissa & (1 << FP16_MANTISSA_BITS)) == 0) {
        result_mantissa <<= 1;
        exp_x -= 1;
    }
}

if (exp_x >= FP16_MAX_EXP) {
    return FP16_INFINITY;
}

if (exp_x <= 0) {
    return 0;
}

result_mantissa &= FP16_MANT_MASK;

return (result_sign << FP16_EXP_BIAS) | (exp_x << FP16_MANTISSA_BITS) |
       result_mantissa;
}
int fp16_cmp(uint16_t x, uint16_t y) {
uint16_t sign_x = FP16_SIGN(x);
uint16_t sign_y = FP16_SIGN(y);
uint16_t exp_x = FP16_EXP(x);
uint16_t exp_y = FP16_EXP(y);
uint16_t mant_x = FP16_MANT(x);
uint16_t mant_y = FP16_MANT(y);

if (exp_x == FP16_MAX_EXP && mant_x != 0) {
    return (exp_y == FP16_MAX_EXP && mant_y != 0) ? 0 : 1;
}
if (exp_y == FP16_MAX_EXP && mant_y != 0) {
    return -1;
}

if ((x & ~FP16_SIGN_MASK) == 0 && (y & ~FP16_SIGN_MASK) == 0) {
    return 0;
}

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

int cmp;
if (exp_x != exp_y) {
    cmp = (exp_x > exp_y) ? 1 : -1;
} else if (mant_x != mant_y) {
    cmp = (mant_x > mant_y) ? 1 : -1;
} else {
    cmp = 0;
}

return sign_x ? -cmp : cmp;
}
Проходит вот так:
Partial solution
7 total tests runs, 6 passed, 1 failed.
Score gained: 0 (out of 100).
N Result Time (sec) Score
1 OK 0.006 0 (0)
2 OK 0.004 0 (0)
3 OK 0.004 0 (0)
4 OK 0.004 0 (0)
5 OK 0.003 0 (0)
6 OK 0.003 0 (0)
7 Wrong answer 0.004 0 (0)
Выясни, в чем разница и сделай так, чтобы проходили оба этих теста
Вот задача:

Problem bn02-1: c/floats/fp16

В этой задаче мы будем работать с 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).

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

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

 

Submit a solution

Language:	gcc - GNU C 11.3.0