Сохраните максимальное число float16 в float32 - PullRequest
0 голосов
/ 11 июля 2019

Как сохранить число с плавающей точкой16 (https://en.wikipedia.org/wiki/Half-precision_floating-point_format) максимальное число в формате float32 (https://en.wikipedia.org/wiki/Single-precision_floating-point_format) формат?

Я хочу иметь функцию, которая могла бы конвертировать 0x7bff в 65504. 0x7bff - это максимальное значение, представляемое с половиной точности с плавающей запятой:

0 11110 1111111111 -> decimal value: 65504 

Я хочу, чтобы 0x7bff представлял действительные биты в моей программе.

float fp16_max = bit_cast(0x7bff); 
# want "std::cout << fp16_max" to be 65504

Я пытался реализовать такую ​​функцию, но, похоже, она не работала:

float bit_cast (uint32_t fp16_bits) {
    float i;
    memcpy(&i, &fp16_bits, 4);
    return i; 
}    
float test = bit_cast(0x7bff);
# print out test: 4.44814e-41

Ответы [ 3 ]

2 голосов
/ 11 июля 2019
#include <cmath>
#include <cstdio>


/*  Decode the IEEE-754 binary16 encoding into a floating-point value.
    Details of NaNs are not handled.
*/
static float InterpretAsBinary16(unsigned Bits)
{
    //  Extract the fields from the binary16 encoding.
    unsigned SignCode        = Bits >> 15;
    unsigned ExponentCode    = Bits >> 10 & 0x1f;
    unsigned SignificandCode = Bits       & 0x3ff;

    //  Interpret the sign bit.
    float Sign = SignCode ? -1 : +1;

    //  Partition into cases based on exponent code.

    float Significand, Exponent;

    //  An exponent code of all ones denotes infinity or a NaN.
    if (ExponentCode == 0x1f)
        return Sign * (SignificandCode == 0 ? INFINITY : NAN);

    //  An exponent code of all zeros denotes zero or a subnormal.
    else if (ExponentCode == 0)
    {
        /*  Subnormal significands have a leading zero, and the exponent is the
            same as if the exponent code were 1.
        */
        Significand = 0 + SignificandCode * 0x1p-10;
        Exponent    = 1 - 0xf;
    }

    //  Other exponent codes denote normal numbers.
    else
    {
        /*  Normal significands have a leading one, and the exponent is biased
            by 0xf.
        */
        Significand = 1 + SignificandCode * 0x1p-10;
        Exponent    = ExponentCode - 0xf;
    }

    //  Combine the sign, significand, and exponent, and return the result.
    return Sign * std::ldexp(Significand, Exponent);
}


int main(void)
{
    unsigned Bits = 0x7bff;
    std::printf(
        "Interpreting the bits 0x%x as an IEEE-754 binary16 yields %.99g.\n",
        Bits,
        InterpretAsBinary16(Bits));
}
1 голос
/ 11 июля 2019

Как сохранить максимальное число float16 в формате float32?

65504

Вы можете просто преобразовать целое число в число с плавающей точкой:

float half_max = 65504;

Если вы хотите вычислить значение, вы можете использовать ldexpf:

float half_max = (2 - ldexpf(1, -10)) * ldexpf(1, 15)

Или, как правило, для любого числа с плавающей запятой IEEE:

// in case of half float
int bits = 16;
int man_bits = 10;

// the calculation
int exp_bits = bits - man_bits - 1;
int exp_max = (1 << (exp_bits - 1)) - 1;
long double max = (2 - ldexp(1, -1 * man_bits)) * ldexp(1, exp_max);

Преобразование битов 0x7bff не работает, потому что 0x7bff - это представление в формате binary16 (в некотором порядке байтов), а не в формате binary32. Вы не можете разыгрывать конфликтующие представления.

1 голос
/ 11 июля 2019

По самой декларации float fp16_max ваше значение уже является 32-разрядным числом с плавающей запятой;не надо здесь кастовать.Полагаю, вы можете просто:

float i = fp16_max;

Предполагается, что ваша «волшебная» функция bit_cast уже вернула 32-битное значение с плавающей точкой.Поскольку вы не показали нам, что bit-cast делает или действительно возвращает, я предполагаю, что оно действительно возвращает правильное значение float.

...