В Unreal, каковы различия между float в C ++ и FFloat32?

17

Я пытался изучить некоторые более глубокие аспекты UE4 и, читая множество примеров кодов, а также исходную базу движка, я заметил, что иногда люди (и сам исходный код) используют стандартный floatпримитив C ++ , но иногда используют пользовательскую реализацию UE4 FFloat32,

Тогда мне стало любопытно: при программировании игры на Unreal, в чем различия между этими двумя вариантами и, возможно, в каких основных случаях нужно отбросить стандартный примитив C ++ в пользу реализации движка?

Ким Шуттер
источник
1
Мне было бы интересно прочитать примеры, которые вы нашли, которые на самом деле используют FFloat32.
@JoshPetrie Некоторые из них были в автономном режиме, пара была в сети. Как только у меня будет время дома, я буду искать их, чтобы поделиться
Ким Шуттер

Ответы:

17

floatХорошо, C ++ с плавающей точкой. FFloat32является структурой, которая представляет число с плавающей точкой, а также (через объединение) разложенные битовые поля для частей знака, мантиссы и экспоненты этого числа с плавающей точкой.

Как правило, вы никогда не должны использовать, FFloat32за исключением случаев, когда:

  • вы используете какой-то API, который ожидает FFloat32(это очень редко) или
  • вам нужно сделать какую-нибудь низкоуровневую битовую хакерскую операцию со значением с плавающей запятой (в наши дни это тоже довольно редко)

Это не значит, что FFloat32это плохо , по сути, это просто , что это на самом деле не предложить вам все , что вы бы необходимо для общего назначения с плавающей точкой использования.

Он встречается реже, чем обычный старый float, что оказывает незначительное влияние на читаемость (другие могут сразу не узнать, для чего он нужен). Кроме того, он не конвертируется в неявно, floatпоэтому вы будете something.FloatValueмного печатать , что тоже не так уж сложно, но может стать утомительным.

Наконец, его использование объединений и битовых полей непереносимо и определяется реализацией (см. Ниже). Это не ваша проблема, задачей Epic является обеспечение того, чтобы тип был структурирован так, чтобы его можно было использовать для всех поддерживаемых реализаций, но это потенциальный источник ошибок, если они не могут обнаружить проблему с реализацией типа, когда новый компилятор версия выпущена или добавлена ​​в список поддерживаемых компиляторов.

Поэтому, если вам не нужно играть с отдельными битами в представлении с плавающей запятой, вам, вероятно, следует просто избегать FFloat32(его двоюродный брат FFloat16, возможно, будет иметь немного больше полезности, поскольку не существует стандартного 16-битного типа C ++ с плавающей запятой).

Раньше было обычным манипулировать числами с плавающей точкой через целочисленные представления их компонентов для « скорости ». Современные компьютеры устраняют большую часть этой потребности для многих платформ, и различные методы штамповки типов , которые могут быть использованы для такого рода вещей, на самом деле могут нанести ущерб производительности или корректности в любом случае.

Следует отметить, что поиск в репозитории Unreal GitHub обнаруживает очень мало случаев использования этого FFloat32типа. Все они находятся в определении самого FFloat32себя или в определении FFloat16.


В частности, FFloat32делает две вещи, которые стандарт C ++ вызывает. Это:

  • позволяет вам действовать так, как если бы более одного члена профсоюза были активны одновременно; от вас ожидается запись в члены с плавающей запятой и чтение из одного из целочисленных членов (9.5.1, [class.union])
  • ожидает, что распределение битовых полей в объединении совпадает с распределением битов значения IEEE с плавающей запятой; однако распределение и выравнивание элементов битового поля в типе класса определяется реализацией (9.6.1, [class.bit])

источник
Unreal не написан в стандарте C ++, он написан для конкретных компиляторов, для которых он написан, поэтому, пока они делают ожидаемую вещь, стандарт не имеет значения.
user253751
Я ожидал бы, что эти битовые поля будут достаточно переносимыми даже в стандарте C / C ++, так как они определены стандартом IEEE, и любой компилятор, использующий другую компоновку float, получит не соответствующую стандарту IEEE 754 (и проблемы совместимости со многими существующими программами) ).
Дмитрий Григорьев
3
Проблема (педантичная) заключается в том, что порядок записи этих битовых полей может соответствовать стандарту IEEE, но компилятор C ++ может переупорядочивать или переупорядочивать их. Это только небольшая сноска, поскольку работа с этим является задачей Epic; они должны отслеживать каждую новую версию компилятора, чтобы убедиться, что тип работает правильно.
@JoshPetrie Точка занята, спасибо за разъяснения.
Дмитрий Григорьев
1
@JustinLardinois Но FFloat32 содержит floatчлен в объединении, так что если floatон на самом деле больше 32 бит, то общий размер FFloat32будет таким же, поскольку объединение должно быть достаточно большим, чтобы вместить самого большого члена. В случаях, когда значения с плавающей запятой превышают четыре байта, Epic придется также модифицировать части битового поля объединения, чтобы решить эту проблему, иначе они не будут отображать полное значение с плавающей запятой.