Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Алгоритмы > Необычный перевод числа с плавающей точкой


Автор: NullModemUser 15.8.2014, 13:34
Здравствуйте!

Работая с протоколом одной железяки, наткнулся на поле, что хранит температуру. Хранит оно в формате числа с плавающей точкой.
Но не как в IEEE-754.

Автор, в документе протокола приводит следующее описание с примером (привожу как в документе, БЕЗ опечаток, 1 к 1):

Цитата

Sf3 - 4 байта

1 байт - порядок. Значение порядка кратно 2, если младший бит равен 1, то число отрицательное, если значение порядка 0, то число равно нулю.

3 байт - старший байт мантиссы. Если старший бит равен 0, то результат выключен.

2,1 байты. Соответственно средний и мл. байты мантиссы.

Примеры чисел:

1    - 80h 00 00 80h
2    - 82h 00 00 80h
4    - 84h 00 00 80h
-4   - 85h 00 00 80h
0,5 - 7Eh 00 00 80h
Выкл - 86h 00 00 7Fh


Помогите, пожалуйста, разобраться. Как перевести, скажем температуру 27,33 в данный формат представления числа. И наоборот.

Заранее спасибо! 

Автор: AVA12 15.8.2014, 14:32
Да, в принципе, все понятно. Формат, в целом, похож на число одинарной точности (single), только лишний бит мантиссы откусил часть экспоненты. Плюс смещение экспоненты другое. Ну и поля переставлены.

Будем работать с числом в новом формате, как с 32-битным целым, порядок байтов - LE (aka "интеловский"). В таком случае между новым форматом и single будут следующие соответствия:
Код
new     single  comment
31      -       1 - корректное число, 0 - "выкл"
30..8   22..0   мантисса
7..1    30..23  экспонента (без знака, со смещением);
                для перевода new -> single нужно прибавить 63, если наоборот, то вычесть
0       31      знак числа

Автор: AVA12 15.8.2014, 15:49
На всякий случай о представлении нуля: если все биты и мантиссы, и экспоненты - нулевые, то при переводе в другой формат соответствующие биты должны остаться нулевыми. Как быть с денормализованными числами и нечислами - непонятно, но, раз уж железка хранит значения температуры, то такие случаи вряд ли встретятся smile

Автор: NullModemUser 15.8.2014, 16:26
AVA12, огромное спасибо! Но можете еще помочь...
Смотрите.

Мы имеем число-константу 1.000258.
Железяка нам его выдает в виде: ED 03 71 82h

С экспонентой в принципе понятно, но мантисса у него вообще иная выходит, чем у идентичного сингла.

Распишите пожалуйста, как Вы его переводите в single... 

Автор: AVA12 15.8.2014, 17:11
А ты уверен, что это именно 1.000258? Если верить описанию формата, ED 03 71 82 должно представлять -18358002335612930. А с другим порядком байт - чуть больше 3.7

Автор: NullModemUser 20.8.2014, 09:53
AVA12, спасибо за за помощь! Таки да, ошибся я с числом, криво разобрал наснифанный пакет.

В итоге привожу Дельфячный код (переложить на С++ или т.п. элементарно, написано крайне просто):

Код

function SpecSingleToSingle(InValue: DWord): Single;
CONST
  OFFBITMASK = $ffffff7f;
  SIGNBITMASK = $01000000;
  EXPONENTMASK = $fe000000;
  EXPONENTCORRECTIONCONST = ($3f000000 shr 1);
  MANTISSBYTE1MASK = $0000007f;
  MANTISSBYTE2MASK = $0000ff00;
  MANTISSBYTE3MASK = $00ff0000;

var PreResult: DWord;
     sign, exponent, mantiss: DWord;
begin
  InValue := InValue AND OFFBITMASK;

  sign := ((InValue AND SIGNBITMASK) shl 7);

  exponent := (((InValue AND EXPONENTMASK) shr 2) + EXPONENTCORRECTIONCONST);

  mantiss := (((InValue AND MANTISSBYTE1MASK) shl 16) OR
               ((InValue AND MANTISSBYTE3MASK) shr 16) OR
               (InValue AND MANTISSBYTE2MASK));

  PreResult := 0 OR sign OR exponent OR mantiss;

  Result := Single(PSingle(PreResult));
end;

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)