Эффективный способ хранения поплавка с фиксированным диапазоном
Я собираю (большой) массив float, каждый float занимает 4 байта.
Есть ли способ, учитывая тот факт, что мои числа с плавающей запятой расположены в диапазоне от 0 до 255, хранить каждое число с плавающей запятой менее чем в 4 байтах?
Я могу сделать любое количество вычислений на весь массив.
Я использую C.
3 ответа
Абсолютный диапазон ваших данных на самом деле не имеет большого значения, вам нужна точность. Если вы можете уйти, например, с 6 цифрами точности, вам потребуется столько памяти, сколько потребуется для хранения целых чисел от 1 до 1000000, а это 20 бит. Итак, предположим, что вы можете сделать следующее:
1) Переместите ваши данные так, чтобы наименьший элемент имел значение 0. Т.е. вычтите одно значение из каждого элемента. Запишите этот сдвиг.
2) Масштабируйте (умножайте) свои данные на достаточно большое число, чтобы после усечения до целого числа вы не теряли нужной точности.
3) Теперь это может быть сложно, если вы не можете упаковать свои данные в удобные 8- или 16-битные блоки - упаковать данные в последовательные целые числа без знака. Каждому из ваших значений данных в этом примере нужны 20 битов, поэтому значение 1 занимает первые 20 битов целого числа 1, значение 2 занимает оставшиеся 12 битов целого числа 1 и первые 8 битов целого числа 2 и так далее. В этом гипотетическом случае вы экономите ~ 40%.
4) Теперь "расшифровка". Распакуйте значения (вы сохранили количество битов в каждом из них), отмените масштаб и отмените сдвиг.
Таким образом, это будет сделано, и, возможно, будет быстрее и компактнее, чем стандартные алгоритмы сжатия, так как они не позволяют делать предположения о том, сколько точности вам нужно, но вы есть.
Сколько точности вам нужно?
Вы можете хранить каждый float в 2 байта, представляя его как unsigned short
(в диапазоне от 0 до 65 535) и деление всех значений на 2^8
когда вам нужно фактическое значение. По сути, это то же самое, что использование формата с фиксированной запятой вместо плавающей запятой.
Ваша точность ограничена 1.0 / (2^8) = 0.00390625
когда вы делаете это, однако.
Например, вы можете хранить целые числа (с плавающей запятой.0) в одном байте, но для другого числа с плавающей запятой требуется больше байтов.
Вы также можете использовать фиксированную точку, если вы не беспокоитесь о точности...