Leader

Saturday 23 May 2015

Converting hexadecimal to decimal

See also: Base conversion of positional number systems for other conversion functions.

Download
hex2dec2.m

Hexadecimal numbers
"Normal" decimal numbers use a base 10 system, most likely because humans have 10 fingers. Hexidecimal is a base 16 number system (presumably because computer programmers have 16 fingers), so whereas the decimal number system has 10 numbers (0-9), hexadecimal has 16 (0-9, and A, B, C, D, E and F).

Like decimal (and binary) hexidecimal is a positional number system, where a numbers position determines its value. This means that calculating the value of a hexidecimal number is exactly the same process as calculating the value of a decimal number. Observe:

Consider the decimal value 2345. The value is obvious. It's 2345. But it can be broken down into the sum of 2000 + 300 + 40 + 5. And each of these values depends on the number of zeros, which is determined by position. Positions start from 0 and count up right to left, so the 2 in 2345 is in position 3, the 3 is in position 2, the 4 is in position 1 and the 5 in position 0. Mathematically this means the value of the 2 is 2*10^3 = 2000, of the 3 is 3*10^2 = 300, and so on. Overall the total value of the number is:

(2*10^3) + (3*10^2) + (4*10^1) + (5*10^0) = 2345.

For hexadecimal numbers, exactly the same process applies, except using a base of 16. The only caveat being that the letters, if there are any, need to be replaced with their equivalent decimal numbers first. So what's the value of the hex number 2345 (notice that for hex values without letters, it's not immediately obvious it's a hex number - so it should be written as either 0x2345 or 234516 to avoid this ambiguity).

0x2345 (hex) = (2*16^3) + (3*16^2) + (4*16^1) + (5*16^0) = 9026 (decimal).

If there are letters in the hex number, for example: 0xF34B, these need to be converted to decimal values first, which is simple: A=10, B=11, C=12, D=13, E=14, F=15. So,

0xF34B = (F*16^3) + (3*16^2) + (4*16^1) + (B*16^0) , or
0xF34B = (15*16^3) + (3*16^2) + (4*16^1) + (11*16^0) = 62283

This process is simple to implement in Matlab, and is very similar to the process to convert decimal values to binary (see dec2bin2). The only complication is the handling of the letters; in Matlab hexadecimal numbers must be strings, because they contain letters. This means that isn't not possible to directly perform mathematical operations on them, such as the above conversion, but Matlab has a number of convenient features for dealing with strings that we'll exploit.

Overall, this function will convert the hexadecimal input to decimal numbers, work out the value of each based on its position, the calculate the sum of all these values to give the final decimal value. It provides an alternative to Matlab's hex2dec function.




Code run-through
function dec =  hex2dec2(hex)

hex2dec2 takes one input (hex) and returns one output (dec). The value of hex doesn't need to be a string unless there's a letter in it.

% Make sure input is a string
hex = num2str(hex);

The function will treat the input hex as a string, even if it was a purely numerical value that was entered. So the first line converts the input to a string - this won't do anything if hex already contains a string.

hex = strrep(hex, '0x', '');

The next step performs a bit of housekeeping. As mentioned above, hexidecimal numbers can be written in three ways, eg 23FC = 0x23FC = 23FC16. The first way isn't good practice because if there are no letters in the hex value, it looks exactly the same as a decimal number. hex2dec2 will work with values in the first two forms, but not the third (ie. not 23FC16). This line uses strrep ("string replace") to look through the string in hex and find any part of it that matches '0x',  then, if found, replaces it with nothing (''). We' can't do the same thing to remove  the characters '16' from the end because '16' could appear elsewhere in the number (including at the end) and be part of the number, not part of the notation. Hence, hex = 23FC16 is ambiguous and shouldn't be used.

hex = cellstr(hex');

Transposing into cellstr is a handy trick when working with strings. cellstr moves strings in to individual cells in a cell array. cellstr('23FC') would create one cell containing '23FC', but transposing the input first puts one character in each row, so cellstr will treat each character as an individual string and move them to their own cell. Once each character is in its own cell, they're much more convenient to work with (particularly because we're about to start converting the letters to 2-digit numbers, so lengths will start changing).

At this point;
>> hex = 
    '2'
    '3'
    'F'
    'C'

% Convert letters to numbers
hexLen = length(hex);
pos = hexLen-1:-1:0;

We're going to use a for loop to work over each digit of the input and first convert it to a number then work out its value based on it's position. We need two bits on information to do this - the length hex (hexLen) and the position values (pos), which are the reverse of (1 to hexLen) minus 1 (because positions start from 0). So for the example value '23FC', hexLen = 4 and pos = [3, 2, 1, 0].

for h=1:hexLen;

The for loop will run for the values h=1, 2, 3, 4.

    % Convert letters to numbers
    switch hex{h}
        case {'A', 'a'}
            hex{h} = '10';
        case {'B', 'b'}
            hex{h} = '11';
        case {'C', 'c'}
            hex{h} = '12';
        case {'D', 'd'}
            hex{h} = '13';
        case {'E', 'e'}
            hex{h} = '14';
        case {'F', 'f'}
            hex{h} = '15';
    end 

Firstly, the value of hex{h} is checked using a switch and case, which provides an easy way to compare strings. Remember that at this point hex is a cell array, with each cell containing one character, so if h=1, hex{h} = '2'. If '2' doesn't match any of the cases (it doesn't), nothing is done. But for h=3, hex{h} = 'C'. 'C' satisfies the case {'C', 'c'} (as would a lower case 'c') and the contents of this cell is changed from 'C' to '12'. Notice that in this process the length of the contents of the cell hex{h} increases from 1 to 2, but that doesn't matter, because it's a cell array.

    hex{h} = str2double(hex{h});

The value in the current cell is then converted to a numerical value using str2double.
    
    % Calculate value of cell
    hex{h} = hex{h} * 16^pos(h);

Now we have a numerical value, we can perform the mathematical operation that we couldn't perform on a letter. The contents of the cell is multiplied by 16^pos(h). Remembering that for the number 23FC, pos = [3, 2, 1, 0], the first time through the loop (h=1), this calculation is 2*16^3, the second time through (h=2) it's 3*16^2, and so on.

end

% Convert to vector
hex = cell2mat(hex);
% And sum
dec = sum(hex);

Finally the sum of all the values is given to give the decimal value. Note that it's not possible to run sum on a cell array, so first hex is converted to a matrix using cell2mat.

No comments:

AdSense