Ошибка строгого сглаживания для преобразования fp16 в fp32

У меня есть функция конвертации fp16 в fp32

static float fp16_to_fp32(const short in){
    signed int t1, t2, t3;
    float out = 0;

    t1 = (in & 0x7fff) << 13 + 0x38000000;
    t2 = (in & 0x8000) << 16;
    t3 = in & 0x7c00;
    
    t1 = (t3==0 ? 0 : t1);
    t1 |= t2;

    *((unsigned int*)&out) = t1;
    
    return out;
}

ошибка: разыменование указателя с типизированным каламбуром нарушит правила строгого псевдонима [-Werror=strict-aliasing] в ((unsigned int)&out) = t1;< /эм>

Как я могу это решить? (не могу изменить тип аргумента in )


person Its me    schedule 20.04.2021    source источник
comment
Для C разрешено делать каламбур через союзы. В противном случае вы можете использовать char указатели или массивы в качестве промежуточного шага (например,   -  person Some programmer dude    schedule 20.04.2021
comment
@NateEldredge Почему sizeof(short)?   -  person MikeCAT    schedule 20.04.2021
comment
@MikeCAT: Извините, я смотрел на in вместо t1. В любом случае ваш ответ охватывает все.   -  person Nate Eldredge    schedule 20.04.2021
comment
Если это для современных процессоров x86, вас также могут заинтересовать _cvtsh_ss и связанные с ними встроенные функции.   -  person harold    schedule 20.04.2021
comment
Основная ошибка: + имеет более высокий приоритет, чем ‹‹. Я сомневаюсь, что вы хотите сдвинуть 13 + 0x38000000 бит влево... приличный компилятор скажет вам об этом.   -  person Lundin    schedule 20.04.2021
comment
Также не могу воспроизвести ошибку на gcc. Какой компилятор, порт и параметры вы используете?   -  person Lundin    schedule 20.04.2021


Ответы (3)


Вы можете использовать memcpy() для копирования данных.

Также обратите внимание, что оператор + имеет более высокий приоритет, чем оператор <<, поэтому строка t1 = (in & 0x7fff) << 13 + 0x38000000; не будет работать должным образом.

#include <string.h> /* for memcpy() */

static float fp16_to_fp32(const short in){
    signed int t1, t2, t3;
    float out = 0;

    t1 = ((in & 0x7fff) << 13) + 0x38000000; /* add parenthesis */
    t2 = (in & 0x8000) << 16;
    t3 = in & 0x7c00;
    
    t1 = (t3==0 ? 0 : t1);
    t1 |= t2;

    memcpy(&out, &t1, sizeof(out)); /* use memcpy() for copying */
    
    return out;
}
person MikeCAT    schedule 20.04.2021
comment
Спасибо, это сработало :) Я забыл круглые скобки, когда писал код здесь, на платформе. - person Its me; 20.04.2021

Вы можете использовать каламбур через union, чтобы избежать строгого псевдонима:

union type_punner
{
  unsigned int i;
  float f;
} out = {.i = t1};
return out.f;

Это предполагает, что int и float имеют одинаковый размер, поэтому это не очень переносимый код.

Вы также можете скомпилировать с -fno-strict-aliasing.

person Lundin    schedule 20.04.2021

Попробуйте объявить out указателем с плавающей запятой, а затем верните *out

person syzztem    schedule 20.04.2021
comment
Это также нарушит строгое использование псевдонимов, если вы собираетесь сделать что-то вроде out = (float *)&t1. - person Nate Eldredge; 20.04.2021