Почему нет 2-байтового числа с плавающей запятой и существует ли уже реализация? - PullRequest
25 голосов
/ 24 апреля 2011

При условии, что я действительно нуждаюсь в памяти и хочу меньший диапазон (аналогично short против int).Языки шейдеров уже поддерживают half для типа с плавающей точкой с половиной точности (не просто конвертируйте назад и вперед, чтобы значение находилось в диапазоне от -1 до 1, то есть возвращайте значение с плавающей запятой, например: shortComingIn / maxRangeOfShort).Есть ли реализация, которая уже существует для 2-байтового числа с плавающей запятой?

Мне также интересно узнать какие-либо (исторические?) Причины того, почему не существует 2-байтового числа с плавающей запятой.

Ответы [ 7 ]

13 голосов
/ 24 апреля 2011

если у вас мало памяти, вы решили отказаться от концепции float?Число с плавающей запятой использует много битов только для сохранения там, где находится десятичная точка. Вы можете обойти это, если вы знаете , где вам нужна десятичная точка, скажем, вы хотите сохранить значение в долларах, вы можетепросто сохраните его в центах:

uint16_t cash = 50000;
std::cout << "Cash: $" << (cash / 100) << "." << ((cash % 100) < 10 ? "0" : "") << (cash % 100) << std::endl;

Это, конечно, только вариант, если вы можете заранее определить положение десятичной точки.Но если вы можете, всегда предпочитайте это, потому что это также ускоряет все вычисления!

rgds, Kira: -)

9 голосов
/ 24 апреля 2011

Re: Реализации: Кто-то, по-видимому, написал half для C, который (конечно) будет работать на C ++: https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/cellperformance-snippets/half.c

Re: Почему float четыре байта: вероятно, потому что ниже этого значения, их точность настолько ограничена .

5 голосов
/ 24 апреля 2011

Там - это Стандарт IEEE 754 для 16-разрядных операций с плавающей запятой .

Это новый формат, стандартизированный в 2008 году на основе графического процессора, выпущенного в 2002 году..

1 голос
/ 13 июня 2018

Вероятно, существует множество типов в разных реализациях. Поплавковый эквивалент stdint.h кажется хорошей идеей. Назовите (псевдоним?) Типы по размерам. (float16_t?) Число с плавающей запятой размером 4 байта только сейчас, но, вероятно, не станет меньше. Такие термины, как половина и длинный, в основном со временем теряют смысл. С 128 или 256-битными компьютерами они могут означать что угодно.

Я работаю с изображениями (1 + 1 + 1 байт / пиксель) и хочу выразить значение каждого пикселя относительно среднего. Так что с плавающей точкой или тщательно фиксированной точкой, но не в 4 раза больше, чем необработанные данные, пожалуйста. 16-битное число с плавающей точкой звучит примерно так.

Этот GCC 7.3 не знает "половины", может быть, в контексте C ++.

1 голос
/ 14 июня 2012

Чтобы пойти немного дальше Киралейна при переключении на целые числа, мы могли бы определить диапазон и позволить целочисленным значениям короткого замыкания представлять равные деления по диапазону, с некоторой симметрией, если они расположены между нулем:

short mappedval = (short)(val/range);

Различия между этими целочисленными версиями и использованием поплавков с половинной точностью:

  1. Целые числа равномерно распределены по диапазону, тогда как числа с плавающей точкой плотнее упакованы около нуля
  2. Использование целых чисел будет использовать целочисленную математику в ЦП, а не с плавающей точкой. Это часто быстрее, потому что целочисленные операции проще. Сказав это, отображение значений в асимметричный диапазон потребует дополнительных дополнений и т. Д. Для получения значения в конце.
  3. Абсолютная потеря точности более предсказуема; Вы знаете ошибку в каждом значении, поэтому общий убыток можно рассчитать заранее с учетом диапазона. И наоборот, относительная ошибка более предсказуема при использовании плавающей запятой.
  4. Может быть небольшой выбор операций, которые вы можете выполнять с помощью пар значений, в частности, побитовых операций, упаковывая два коротких в int. Это может вдвое сократить количество необходимых циклов (или больше, если короткие операции включают приведение к int) и поддерживает 32-битную ширину. Это просто разбавленная версия нарезки битов, в которой 32 бита обрабатываются параллельно, что используется в криптографии.
0 голосов
/ 07 мая 2019

Если ваш процессор поддерживает F16C, то вы можете довольно быстро запустить и запустить что-нибудь, например:

// needs to be compiled with -mf16c enabled
#include <immintrin.h>
#include <cstdint>

struct float16
{
private:
  uint16_t _value;
public:

  inline float16() : _value(0) {}
  inline float16(const float16&) = default;
  inline float16(float16&&) = default;
  inline float16(const float f) : _value(_cvtss_sh(f, _MM_FROUND_CUR_DIRECTION)) {}

  inline float16& operator = (const float16&) = default;
  inline float16& operator = (float16&&) = default;
  inline float16& operator = (const float f) { _value = _cvtss_sh(f, _MM_FROUND_CUR_DIRECTION); return *this; }

  inline operator float () const 
    { return _cvtsh_ss(_value); }

  inline friend std::istream& operator >> (std::istream& input, float16& h) 
  { 
    float f = 0;
    input >> f;
    h._value = _cvtss_sh(f, _MM_FROUND_CUR_DIRECTION);
    return input;
  }
};

Математика по-прежнему выполняется с использованием 32-битных операций с плавающей запятой (расширения F16C обеспечивают преобразование только между 16/32-разрядными операциями с плавающей запятой - не существует инструкций для вычисления арифметики с 16-разрядными операциями с плавающей запятой).

0 голосов
/ 07 мая 2019

TL; DR: 16-разрядные числа с плавающей запятой существуют, и существуют различные программные и аппаратные реализации

В настоящее время существует 2 общих стандартных 16-разрядных формата с плавающей запятой: двоичный код IEEE-75416 и Google bfloat16 .Поскольку они стандартизированы, очевидно, если кто-то, кто знает спецификацию, может написать реализацию.Некоторые примеры:

Или, если вы не хотите их использовать, вы также можете спроектировать другой 16-битный формат с плавающей запятой и реализовать его


2-байтовые числа с плавающей запятой обычно не используются, потому что даже числа с плавающей запятойТочность недостаточна для обычных операций и double всегда должны использоваться по умолчанию, если вы не ограничены пропускной способностью или размером кэша.Литералы с плавающей точкой также double при использовании без суффикса в C и C-подобных языках.См.

Однако менее 32-битных float существуют .Они в основном используются для хранения целей, как в графике, когда 96 бит на пиксель (32 бита на канал * 3 канала) слишком потрачены впустую, и будут преобразованы в обычный 32-битный float для вычислений(за исключением некоторых специальных аппаратных средств).В OpenGL существуют различные 10, 11, 14-битные типы с плавающей запятой .Во многих форматах HDR для каждого канала используется 16-разрядное число с плавающей запятой, а Direct3D 9.0, а также некоторые графические процессоры, такие как Radeon R300 и R420, имеют 24-разрядный формат с плавающей запятой.24-разрядные операции с плавающей запятой также поддерживаются компиляторами в некоторых 8-разрядных микроконтроллерах , таких как PIC , где поддержка 32-разрядных операций с плавающей запятой слишком дорога.8-битные или более узкие типы с плавающей точкой менее полезны, но из-за своей простоты их часто преподают в учебных программах по информатике.Кроме того, небольшой символ с плавающей запятой также используется в кодировке инструкций ARM для небольших операций с плавающей запятой.

IEEE 754-2008 ревизия официально добавила 16-битный метод с плавающей запятойформат, AKA binary16 или с половинной точностью , с 5-битным показателем и 11-битной мантиссой

Некоторые компиляторы поддерживали бинарный код IEEE-754, ноглавным образом для преобразования или векторизованных операций, а не для вычислений (потому что они недостаточно точны).Например, набор инструментов ARM имеет __fp16, который может быть выбран из двух вариантов: IEEE и альтернативный в зависимости от того, хотите ли вы больше представлений диапазона или NaN / inf. GCC и Clang также поддерживают __fp16 вместе со стандартизированным именем _Float16.См. Как включить тип __fp16 на gcc для x86_64

В последнее время из-за повышения ИИ появился еще один формат под названием bfloat16 (мозговой формат с плавающей запятой ), который представляет собой простое усечение старших 16 битов двоичного кода IEEE-754, ставший общим

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

  • float32: 242 = 576 (100%)
  • float16: 112 = 121 (21%)
  • bfloat16: 82 = 64 (11%)

Многие компиляторы, такие как GCC и ICC , теперь также получиливозможность поддержки bfloat16

Дополнительная информация о bfloat16:

...