#prolog #udp #ieee-754
#пролог #udp #ieee-754
Вопрос:
Я пытаюсь сам декодировать список необработанных байтов, полученных udp_received
.
Два вопроса:
-
Я не нашел никаких стандартных средств, таких как ByteBuffer в Java
-
Есть ошибки в
decodeDouble
whiledecodeLong
работает нормально.
Предпочтительнее использовать стандарт.
Работа со списком байтов является обязательной для интеграции уже построенной системы, разработанной на 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.