Converting floating-point hexadecimal (string input) to decimal

I am trying to convert a base-16 string input to a base-10 output. I have a current code, using the hex2dec function. However, it won't convert a hex input with a floating point. Is there any way I can do so? For example. input '2B.3A' should return output 43.2265625
I would also like to convert base 10 inputs to base 16, so if anyone has any links for such files, it would be a great help. Thank you for your time
%Input must be a string
function y = hex2double(n)
n = strtrim(n);
c=0;
i=1;
if isempty(find(n=='.', 1))
y = hex2dec(n);
else
j = find(n=='.');
intp=n(1:j-1);
floatp=n(j+1:end);
%if find 0 in the beginning of the fraction part
%-divide by [place-value needed] times (1+ number of 0's), add floating part to integer part
%after that:
%floatp=floatp/(10*(1+c));
%this is where things get out of hand
y = hex2double(intp)+hex2dec(floatp);
end

 Réponse acceptée

Stephen23
Stephen23 le 17 Avr 2020
Modifié(e) : Stephen23 le 18 Avr 2020
>> str = '2B.3A';
>> out = sscanf(str,'%lx.'); % use NUMEL(OUT) to detect integer or fractional
>> dcp = numel(str)-strfind(str,'.');
>> out = out(1) + out(2) ./ pow2(4*dcp)
out =
43.2265625
A more challenging example:
>> str = '3.243F6A8885A2F7A'; % π
>> out = sscanf(str,'%lx.');
>> dcp = numel(str)-strfind(str,'.');
>> out = out(1) + out(2) ./ pow2(4*dcp)
out =
3.14159265358979
Note that more than 16 integer digits or 16 fractional digits will not be correctly parsed by this method, and the output precision is limited by the double type anyway.
For the reverse conversion the usual method is:
  1. scale the fractional part by 16,
  2. convert the integer part to hexadecimal,
  3. repeat from step one until you run out of digits or reach some precision limit.
You will find plenty of examples of this method on the internet.
Alternatively, if you don't mind a few trailing zeros, it can be done in one step:
>> num = 43.2265625;
>> str = sprintf('%X.%016X',fix(num),mod(num,1)*pow2(64))
str = 2B.3A00000000000000
Or a more challenging example:
>> num = pi
num = 3.141592653589793
>> str = sprintf('%X.%016X',fix(num),mod(num,1)*pow2(64))
str = 3.243F6A8885A30000

7 commentaires

Whenever I try to input the first code I either get an error or I'll only get the answer as a integer without the part after the decimal. Can you please suggest anything I'm missing?
The base 10 to 16 conversion works though, thank you!
Stephen23
Stephen23 le 20 Avr 2020
Modifié(e) : Stephen23 le 20 Avr 2020
"Can you please suggest anything I'm missing?"
You are missing these:
  • showing the exact code that you are trying
  • showing the test data that you used
  • showing the complete error message (this means all of the red text)
Sadly my magic crystal ball is at the workshop today after catching fire during some intense usage yesterday, and so now we have to rely on much more mundane ways of debugging your code, e.g. you actually giving enough information for me to be able to help you.
I simply copy pasted and tested the first section of code with no indents/comments:
str = '2B.3A';
out = sscanf(str,'%lx.');
dcp = numel(str)-strfind(str,'.');
out = out(1) + out(2) ./ pow2(4*dcp)
The error says:
Index exceeds the number of array elements (1)
Error in line 4: out = out(1) + out(2) ./ pow2(4*dcp)
Stephen23
Stephen23 le 20 Avr 2020
Modifié(e) : Stephen23 le 20 Avr 2020
The code you gave in your last comment works without error when I run it:
>> str = '2B.3A';
>> out = sscanf(str,'%lx.');
>> dcp = numel(str)-strfind(str,'.');
>> out = out(1) + out(2) ./ pow2(4*dcp)
out = 43.227
Most likely you are trying it with a different input string than the one you are showing, one which does not include a fractional value (I think I clearly asked you to provide the actual test data that you are using).
Note this comment that I wrote in my answer:
% use NUMEL(OUT) to detect integer or fractional
If you want to test for integers then you would need to follow that comment (or use strfind, or think of some other way to detect integers, it really does not matter that much how you do it).
out = sscanf(...)
if numel(out)>1
dcp = ...
out = ...
end
I used no test data other than what was already provided. I've copied your code again and now I I receive out = 43 with blue text utint64.
I've already found a solution to my original question (it's not nearly as efficient but I could share it), but I'd still like to hear why I received a different output. Thanks for the help
"I receive out = 43 with blue text utint64"
Ah, that would explain it. On earlier MATLAB versions (like 2012b that I am using) sscanf returns a double for that format specifier, but apparently at some point TMW upgraded sscanf and it now returns an integer type. You can probably get it working with either of these:
out = sscanf(str,'%x.'); % remove 'l' -> returns double
out = double(sscanf(str,'%lx.')); % wrap in DOUBLE
Try both of them and then pick whichever one suits your needs best.
Alright, thank you! I'll upload my own response sometime as well, just in case anyone finds it helpful

Connectez-vous pour commenter.

Plus de réponses (0)

Produits

Version

R2019b

Question posée :

YC
le 17 Avr 2020

Commenté :

YC
le 22 Avr 2020

Community Treasure Hunt

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

Start Hunting!

Translated by