Декодирование необработанных байтов, полученных udp_receive, с помощью as(кодов)

#prolog #udp #ieee-754

#пролог #udp #ieee-754

Вопрос:

Я пытаюсь сам декодировать список необработанных байтов, полученных udp_received .

Два вопроса:

  1. Я не нашел никаких стандартных средств, таких как ByteBuffer в Java

  2. Есть ошибки в decodeDouble while decodeLong работает нормально.

Предпочтительнее использовать стандарт.

Работа со списком байтов является обязательной для интеграции уже построенной системы, разработанной на C / C и Java.

Вот код:

 decodeLong( [B0,B1,B2,B3,B4,B5,B6,B7|Remaining], Long, Remaining ) :-
    Long is (B0 << 56)
        /    (B1 << 48)
        /    (B2 << 40)
        /    (B3 << 32)
        /    (B4 << 24)
        /    (B5 << 16)
        /    (B6 <<  8)
        /    (B7 <<  0).

decodeDouble( [B0,B1,B2,B3,B4,B5,B6,B7|Remaining], Double, Remaining ) :-
    ((B0 >> 7) > 0 -> Sign = -1 ; Sign =  1),
    Fraction is ((B1 / 0x0F) << 48)
        /        ( B2          << 40)
        /        ( B3          << 32)
        /        ( B4          << 24)
        /        ( B5          << 16)
        /        ( B6          <<  8)
        /        ( B7          <<  0),
    Exponent is ((B0 / 0x7F) / ((B1 / 0xE0) >> 5)),
    ExponentBias is 2^( 11 - 1) - 1, % double: 11 bits for Exponent
    format( "Sign    : ~w~n", [Sign]),
    format( "Fraction: ~w~n", [Fraction]),
    format( "Exponent: ~w~n", [Exponent]),
    Double is Sign*Fraction*2^(Exponent-ExponentBias). % see IEEE 754

test :-
    RawBytes = [-1, -1, -1, -1, -1, -1, -1, -123, -64, 94, -36, -52, -52, -52, -52, -51],
    decodeLong( RawBytes, Long, Remaining0 ),
    format( "decodeLong produces: ~w, Remaining: ~w~n", [Long, Remaining0]),
    Long      = -123,
    decodeDouble( Remaining0, Double, Remaining1 ),
    format( "decodeDouble produces: ~w, Remaining: ~w~n", [Double, Remaining1]),
    Double     = -123.45,
    Remaining1 = []. % all bytes has been consumed
  

Выполнение:

 ?- test.
decodeLong produces: -123, Remaining: [-64,94,-36,-52,-52,-52,-52,-51]
Sign    : 1
Fraction: -51
Exponent: 66
decodeDouble produces: -4.186627537324344e-287, Remaining: []
false.
  

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

1. Нет необходимости делать это : [B0|[B1|[B2|Remaining]]] . Это точно так же, как [B0,B1,B2|Remaining] . Попробуйте: ?- [X,Y|Z] = [a,b,c,d,e].

2. Хорошо, я предпочитаю ваше предложение, ясно!

Ответ №1:

Я считаю, что вам будет лучше использовать машинный код для преобразования байтов в double .

Есть несколько крайних случаев, о которых вам нужно позаботиться в противном случае, и изобретать велосипед здесь не имеет особого смысла.

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

Вот исправление для вашего кода декодирования. На данный момент он работает только с обычными числами (как в вашем примере):

 decodeDouble( [B0,B1,B2,B3,B4,B5,B6,B7|Remaining], Double, Remaining ) :-
    ((B0 mod 256 >> 7) > 0 -> Sign = -1 ; Sign =  1),
    Fraction is ((B1 / 0x0F) mod 256 << 48)
        /        ( B2 mod 256         << 40)
        /        ( B3 mod 256         << 32)
        /        ( B4 mod 256         << 24)
        /        ( B5 mod 256         << 16)
        /        ( B6 mod 256         <<  8)
        /        ( B7 mod 256         <<  0),
    Significand is 1.0   Fraction / 2^52,
    Exponent is (((B0 / 0x7F mod 256) << 4) / ((B1 / 0xF0 mod 256) >> 4)),
    ExponentBias is 2^( 11 - 1) - 1, % double: 11 bits for Exponent
    format( "Sign    : ~w~n", [Sign]),
    format( "Fraction: ~w~n", [Fraction]),
    format( "Significand: ~w~n", [Significand]),
    format( "Exponent: ~w~n", [Exponent]),
    Double is Sign*Significand*2^(Exponent-ExponentBias). % see IEEE 754
  

тестовый запуск:

 ?- test.
decodeLong produces: -123, Remaining: [-64,94,-36,-52,-52,-52,-52,-51]
Sign    : -1
Fraction: 4183421841362125
Significand: 1.92890625
Exponent: 1029
decodeDouble produces: -123.45, Remaining: []
true.
  

У вас было несколько ошибок. Вы начинаете с «байтов» в диапазоне [-128, 127]. Я переместил его в диапазон [0,255], чтобы применить двоичные операции.
Вы также получили некоторые сдвиги на 1, вычисление значения было неправильным (забыли неявное 1 и сделать дробь фактической дробью)

Вы можете легко улучшить процедуру для работы с денормальными числами. Вам также необходимо будет позаботиться о специальных значениях varios, предоставляемых стандартом

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

1. Спасибо за ваши советы. Я написал небольшую библиотеку DatagramSocket на C, которая успешно загружается моими скриптами Prolog.