2012-05-02 1 views
5

Да, я знаю стандарт полуточности IEEE-754, и да, я знаю о работе, выполненной в этой области. Проще говоря, я пытаюсь сохранить простой номер с плавающей запятой (например, 52.1, или 1.25) всего за 2 байта.Как сохранить число с плавающей запятой в 2 байта?

Я пробовал некоторые реализации в Java и в C#, но они разрушают входное значение, декодируя другое число. Вы подаете в 32.1 и после кодирования-декодирования вы получаете 32.0985.

Есть ли способ сохранить числа с плавающей запятой всего в 16 бит, не разрушая входное значение?

Большое спасибо.

+5

Бинарные плавающие точки не могут кодировать '32.1' – CodesInChaos

+2

Какой диапазон чисел вам нужен для кодирования и сколько значительных цифр у них есть? Рассмотрим десятичные фиксированные или плавающие точки. – CodesInChaos

+0

Можете ли вы сохранить его как 'unsigned short', с некоторыми битами, которые используются для экспоненциальной части? Затем вы вручную конвертировали бы обратно из этого формата в обычную единую точность 'float'. – Matthew

ответ

5

Вы можете хранить три цифры в BCD и использовать оставшиеся четыре бита для десятичной точки позиции:

52.1 = 521 * 10^-1 => 0x1521 
1.25 = 125 * 10^-2 => 0x2125 

Это даст вам диапазон от 0.0000000000000001 до 999.Конечно, Вы можете добавить смещение для десятичной точки, чтобы получить, например, диапазон 0,0000000001 к 999000000.


Простая реализация четырех бит используется для десятичной точки размещения, а остальные для значения. Без каких-либо проверок ошибок и не проверяется полностью. (Может иметь точные проблемы с некоторыми значениями при использовании != для сравнения двойников.)

public static short Encode(double value) { 
    int cnt = 0; 
    while (value != Math.Floor(value)) { 
    value *= 10.0; 
    cnt++; 
    } 
    return (short)((cnt << 12) + (int)value); 
} 

public static double Decode(short value) { 
    int cnt = value >> 12; 
    double result = value & 0xfff; 
    while (cnt > 0) { 
    result /= 10.0; 
    cnt--; 
    } 
    return result; 
} 

Пример:

Console.WriteLine(Encode(52.1)); 
Console.WriteLine(Decode(4617)); 

Выход:

4617 
52.1 
+0

@Geotarget: вы могли бы сжать 4 цифры в два байта, но тогда у вас осталось только два бита, чтобы описать, где находится десятичная точка. Для чисел с меньшим количеством цифр вы просто заполняете нулями, т. Е. '1.5' совпадает с' 001.5' или '1.500'. – Guffa

+0

Можете ли вы показать примеры функций float для двоичного кодирования/декодирования? Извините, но я не совсем понимаю, что такое hapenning. –

+0

@Geotarget: Я добавил простую реализацию выше. – Guffa

3

Проблема в том, что вы не можете точно представить 32.1 в любой двоичный тип с плавающей точкой.

В единственной точности самое близкое представляемое значение - 32.099998. В полуточности это, по-видимому, 32.0985.

Вы можете рассмотреть десятичный тип с плавающей запятой, но это решение не уникально для полуточности.

+0

Значение половинной точности использует 11 бит для значения (ведущий бит 1 неявный). В интервале [32,64] 6 из этих битов используются для целочисленной части, оставляя 5 бит для дробной части. Таким образом, в этой области [32,64] представляемые значения представляют собой в точности совпадения 1/(2 ** 5) = 1/32. Самый близкий к '32.1' будет 32 + 3/32 (a.k.a. 1027/32), который равен' 32.09375'. Так что ваш «по-видимому» не является правильным, в конце концов. Я не знаю, откуда у этого искателя. Для значения с половинной точностью вы обычно выводите только 3 десятичные цифры, поэтому '' 32.1 "' будет обычной точностью. –

1

Из ваших примеров вы хотите сохранить 3 цифры и десятичную точку. Вы можете просто кодировать ваш «алфавит» из 11 символов в 4-битный код и хранить 4 х 4 бита в 2 байта.

Держу пари, что теперь вы «объясните», что ваш запрос не удовлетворен этим подходом!

+0

Да, что-то вроде двоичного кодированного десятичного кода будет работать нормально – Kell

6

У C# нет встроенных функций для этого, но вы можете попробовать подход с фиксированной точкой.

Пример 8,8 с фиксированной точкой (8 перед тем запятой, 8 после того, как):

float value = 123.45; 
ushort fixedIntValue = (ushort)(value * 256); 

Таким образом, число сохраняется следующим образом: XXXXXXXX, XXXXXXXX

и вы можете получить всплывают снова с помощью этого:

float value = fixedIntValue/256f; 
+1

Это также имеет ограниченную точность. 52.1 становится 52.09765625. – Guffa

+0

Ну, у вас не может быть всего. Если вы хотите больше, вы можете либо попробовать 6,10 фиксированной точки, либо использовать 4 байта. – bytecode77

+1

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

5

вы уверены, что нужен такой микро-оптимизации, по сравнению с простым использованием float или double?

Вам будет лучше обслуживать хранение short и понимание того, что, например, он делится на 100, чтобы сделать фактический номер? (Например, ваши примеры из 52.1 и 1.25 могут быть сохранены как 5210 и 125). Я думаю, что это может быть лучшим решением для вас.

Если вы используете фактическое число с плавающей запятой, вы можете взять декодированное число и округлить его до x значащих цифр (из вашего примера 3), который обычно должен вернуть вам тот же номер, который вы запустили с (обратите внимание, что да, это намеренно неопределенно - вы не можете гарантировать получение оригинала, если вы не сохранили оригинал).

2

Есть 4,278,190,080 32-разрядное с плавающей точкой значения, не считая NaN и бесконечности. Есть 65 536 значений для 16 бит в двух байтах. Ясно, что невозможно однозначно кодировать все значения с плавающей запятой в двух байтах.

Которые вы хотите кодировать?

Даже при одном значении знака и экспоненты (например, все значения с плавающей запятой от 4 до 8, не считая 8), имеется 8,388,608 значений с плавающей запятой, поэтому вы даже не можете кодировать их в два байта.

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

Смежные вопросы