How do I properly convert a 64-bit binary string / Convert directly from bin or hex to uint64

63 vues (au cours des 30 derniers jours)
I have a matlab function that reads in serial data and breaks it apart into component signals.
Each serial data packet is 64 bits.
Update: The data originates from a data capture which stores it as hex string of up to 16 characters.
Each packet is broken up into an arbitrary number of variables with an arbitrary number of bits. Often, they are bytes, but sometimes they are "odd" numbers of bits. Because of this, I have to analyze these packets bit-wise, first converting from Hex to Bin(update), then extract the necessary bits, then re-order them, in order to get the correct data. That is, when I convert the raw data into binary strings, the Matlab indicies 1-64 correspond to bits 63->0 in the serial data.
This is usually OK in most cases, but one particular variable actually uses ALL 64 bits.
The problem that arises from this, is if my 64-bit integer is greater than 2^53 (flintmax), then it will not get converted correctly. MATLAB gives me a warning about this. This is because both hex2dec and bin2dec convert to type double. There's no direct conversion from bin->hex or from bin->int that I'm aware of.
All of the variables are integer based (update: that is all of the serial data represented in Hex, ultimately represent integer numbers). How do I properly convert the 64 bit string (update: which could be as 16 character hex string or char vector, 64 character binary string or char vector, or logical as I can derive all of those from the input) into the corresponding 64-bit integer?
(If I have to, I can create a conversion function that converts the string / char to logical, and uses an array of 64 uint64 constants (2^0, 2^1, ... 2^63) and multiplies them by the logical mask - but is there something built-in with less steps (and better efficiency) that I can use?
For example:
An input could be:
'F3 00 79 00 00 1E FF FF'
Which could also be represented with binary:
'1111001100000000011110010000000000000000000111101111111111111111'
Ultimately it should be a uint64 value of:
17510128392125480959
Using the built-in MATLAB functions, I get a warning and an incorrect answer:
uint64( hex2dec('F3007900001EFFFF') )
Warning: Hexadecimal numbers representing integers greater than or equal to flintmax might not be represented exactly as double-precision floating-point values.
ans = uint64 17510128392125480960
Or, alternately:
uint64( bin2dec('1111001100000000011110010000000000000000000111101111111111111111') )
Warning: Binary numbers representing integers greater than or equal to flintmax might not be represented exactly as double-precision floating-point values.
ans = uint64 17510128392125480960
As you can see, they both result in an answer of 17510128392125480960 which is 1 off from the desired answer.

Réponses (2)

Walter Roberson
Walter Roberson le 23 Jan 2023
F3str = 'F3007900001EFFFF'
F3str = 'F3007900001EFFFF'
F3 = swapbytes(typecast(uint8(sscanf(F3str, '%02x')), 'uint64'))
F3 = uint64 17510128392125480959
%crosscheck
dec2hex(F3)
ans = 'F3007900001EFFFF'
isequal(dec2hex(F3), F3str)
ans = logical
1
  1 commentaire
Walter Roberson
Walter Roberson le 23 Jan 2023
If needed, you can add automatic padding into the code
F3str = 'F300900001EFFFF' %shorter
F3str = 'F300900001EFFFF'
F3 = swapbytes(typecast(uint8(sscanf([repmat('0', 1, 16-length(F3str)), F3str], '%02x')), 'uint64'))
F3 = uint64 1094384605057712127
%crosscheck
dec2hex(F3, 16)
ans = '0F300900001EFFFF'
isequal(dec2hex(F3), F3str)
ans = logical
1

Connectez-vous pour commenter.


Jan
Jan le 17 Jan 2023
Modifié(e) : Jan le 17 Jan 2023
The question explains with many details, where the numbers are coming from. It would be more useful to post a set aof available input data as Matlab code. So what do you call "integer based" and "64-bit string"? Which format does the input have?
Assuming that a "64 bit string" ist a char vector:
in = char('0' + randi([0,1], 1, 64))
in = '0111101000001110011001111100010011000001101100010111000000000001'
format long
out = BinToUINT64(in)
out = uint64
8795081217062039553
function out = BinToUINT64(in)
d = uint64(in - '0'); % Vector of doubles containing the bits
out = sum(d .* bitshift(uint64(1), 63:-1:0), 'native');
% Or more flexible:
% out = sum(d .* bitshift(uint64(1), numel(in)-1:-1:0), 'native');
end
% Alternatively:
function out = BinToUINT64(in)
v = bitshift(uint64(1), numel(in)-1:-1:0);
out = sum(v(in == '1'), 'native');
end
  1 commentaire
Captain Karnage
Captain Karnage le 23 Jan 2023
I came up with my own solution, but it's more code and probably less efficient. I'll check out your solution and compare.

Connectez-vous pour commenter.

Produits


Version

R2022b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by