среда, 19 октября 2011 г.

Модуль перевода из формата с плавающей точкой IEEE-754 (IEC-60559)

При работе с со стандартизированным железом, будь-то поток данных с прибора по RS-232 или процессора DSP, данные чаще всего представлены в виде беззнаковых целых чисел или чисел с плавающей точкой (4 байта в формате IEEE-754). Стандарт IEEE 754, используемый без лишнего уже 30 лет,  четко определяет представление IEEE754-чисел в виде знака, степени и мантиссы. Стандартное представление имеет левоприжатую мантиссу и степень, указывающую двоичный показатель степени крайне левого разряда мантиссы.



К примеру, имеем последовательность байт (HEX): 43 0A F1 20. Представим ее для наглядности в двоичном представлении:
0100 0011 0000 1010 1111 1010 0010 0000
Отсюда:
  1. Знак числа S (см. первую картинку) = 0.
  2. Смещенная экспонента E = (BIN) 10000110 = (DEC) 134.
  3. Мантисса = (BIN) 00010101111101000100000 = (DEC) 719392.
Преобразованное число F для 32-х битного формата одинарной точности:
F = (-1)^S * (2^(E-127)) * (1 + (M/2^23)).
Подставим исходные данные:
F = (-1)^S * (2^(E-127)) * (1 + (M/2^23)) =  (-1)^0 * (2^(134-127)) * (1 + (719392/2^23)) ~ 138.987.
Делюсь готовым модулем конвертации с 4-мя вариантами преобразования из IEEE-754 в DOUBLE:
function getbit(data, num: longword): byte;
begin
  if (data and (1 shl num)) > 0 then result := 1
  else result := 0
end;
function get_data(reg: longword; min, max: integer): longword;
var i: integer;
begin
  result := 0;
  for i := min to max do
    result := (getbit(reg, i) shl (i - min)) or result
end;
 function ieee754(b0, b1, b2, b3: byte): double;
  var slv: longword;
      znak: byte;
      se: byte;
      m: longword;
      //bb0, bb1, bb2, bb3: byte;
  begin
   {bb0:= $20;
   bb1:= $fa;
   bb2:= $0a;
   bb3:= $43;
    }
   slv:= (((b3 shl 8) + b2) shl 16) +
           (b1 shl 8) + b0;
   znak:= getbit(slv, 31);
   se  := get_datal(slv, 23, 30);
   m   := get_datal(slv, 0, 22);
   result:= (power(-1, znak))*
            (power(2, se-127))*
            (1 + (m/power(2, 23)));  //138.977
  end;

  function ieee754_2(b0, b1, b2, b3: byte): double;
  type ieee = array [0..3] of byte;
  var d: single;
  begin
    ieee(d)[0]:= b0;
    ieee(d)[1]:= b1;
    ieee(d)[2]:= b2;
    ieee(d)[3]:= b3;
    result:= d
  end;
  function ieee754_3(b0, b1, b2, b3: byte): double;
  var p : integer;
      ps: psingle;
      s : single;
  begin
    p:= (((b3 shl 8) + b2) shl 16) + (b1 shl 8) + b0;
    ps:= @p;
    s:= ps^;
    result:= s
  end;
  function ieee754_4(b: integer): double; 
     var m: single;
 begin
   MoveMemory(@m, @b, 4);
   result:= m
  end; 
Обратное преобразование из FLOAT в IEEEE754? Ноу проблем:
  function doubletoieee754(b: double): dword;
  var int:Integer;
        f: single;
  begin
   f:= b;
   MoveMemory(@int, @f, 4);
   result:= int
  end; 

Комментариев нет:

Отправить комментарий

В комментариях уважайте собеседника, внимательно читайте посты и не додумывайте. Просьбы и предложения из разряда: «можно ваш Skype/Viber/телефон», «напишите мне в vk/FB», а также другие им подобные — игнорируются. Выход новых версий ПО, внешняя ссылка, переставшая работать с течением времени и т.п. не является основанием для претензий. Желающие спокойно подискутировать и высказаться — Welcome. Желающие спонсировать блог — Donate. Нарушение этих простых правил ведет к бану и удалению комментариев без предупреждения.