%% Numeric and byte order (endian) conversions in MATLAB
%% Creating an integer variable
% Say I want to create a variable of type *uint16*, with value 100.
%%
% *Method 1*
val1 = uint16(100);
%%
% *Method 2*
val2 = cast(100, 'uint16');
%%
% *Method 3*
val3 = zeros(1,1,'uint16');
val3(1) = 100;
whos val1 val2 val3
%%
% *Incorrect method*
%
% The following won't work, since _val4_ will be reinitialized to have
% the type of the number '100', i.e., it will be a *double*.
val4 = zeros(1,1,'uint16');
val4 = 100;
whos val4
%% Destructive casting - I
% If I have a variable of type *uint16* and would like to
% convert it to a *uint8*, I can use the CAST or UINT8 commands.
%%
% First create a variable of type *uint16*
aval = uint16(10000);
%%
% Conversion to *int16* is safe, since 10000 is within
% the valid range for an *int16*.
bval = int16(aval)
%%
% Convert to *uint8* is not safe since the 10000 doesn't
% fit in the new type. Hence, the value gets clipped.
cval = uint8(aval)
%%
% It is not possible to recover the original _aval_ from
% the *uint8* variable _cval_
new_aval = uint16(cval);
aval,new_aval
%% Destructive casting - II
% The behavior of CAST and functions like UINT16 or INT8 can be frustrating
% if I have a signed integer that I want to treat as an unsigned number,
% or vice versa (i.e., I want to convert to/from the two's-complement
% representation of the number).
aval = int16(-200);
bval = uint16(aval);
whos aval bval, bval
%%
% _bval_ is 0 since the allowable range for a *uint16* is [0,65535], and
% the value of -100 gets clipped to 0. Hence, it is not possible to recover
% the original number, even though _aval_ and _bval_ have the same size
% (two bytes):
new_aval = int16(bval);
aval, new_aval
%% Non-destructive casting
% The way to do non-destructive casting is with the TYPECAST command.
aval = int16(-200);
bval = typecast(aval, 'uint16');
whos aval bval, bval
%%
% Now convert back from *uint16* to *int16*
new_aval = typecast(bval, 'int16');
aval, new_aval
%% Converting an integer to a sequence of bytes
% Say I want to convert a mulitbyte number to a sequence of
% bytes (e.g., I want to save the data in a custom binary format, or
% want to send it over a communications channel that only takes a
% sequence of bytes).
%%
% Make a 4-byte signed integer
aval = int32(-314159);
whos aval, aval
%%
% Convert the 4-byte integer to a sequence of four unsigned bytes
bval = typecast(aval, 'uint8');
whos bval, bval
%%
% Now convert from the sequence of bytes back to a multibyte value
new_aval = typecast(bval, 'int32');
aval, new_aval
%% Converting a floating-point value to a sequence of bytes
%%
% Create an 8-byte floating point value (i.e., of type *double*)
aval = 3.14159; % equivalent to double(3.14159)
whos aval, aval
%%
% This becomes a sequence of 8 unsigned bytes
bval = typecast(aval, 'uint8');
whos bval, bval
%%
% Now convert back:
new_aval = typecast(bval, 'double');
aval, new_aval
%% Converting a sequence of bytes to an integer
% Sometimes I have a sequence of bytes that I want to convert to
% a multibyte integer. This example shows how to go from an array of
% four bytes to a *uint32*.
%%
% Define a byte array of length 4
byteArray = zeros(1,4,'uint8');
byteArray(1) = 2;
byteArray(2) = 1;
whos byteArray, byteArray
%%
% Another way of specifying _byteArray_
byteArray = uint8([2 1 0 0]);
%%
% Now convert to a *uint32* (the bytes will be interpreted in Little-endian
% order on my system).
integerValue = typecast(byteArray, 'uint32');
whos integerValue, integerValue
%% Checking the Endianness of the system
% The COMPUTER command returns the current endian-ness
% (the value of _endian_ is 'L' if the system is Little-endian,
% and 'B' if it is Big-endian).
[computerType, maxSize, endian] = computer;
isLittleEndian = (endian == 'L')
%%
% Another way of testing the endianness
testNumber = uint32(1);
byteSeq = typecast(testNumber, 'uint8');
isLittleEndian = (byteSeq(1) == 1)
%% Little-endian and Big-endian conversions
% The TYPECAST operator makes it easy to do byte-order conversions, such as
% from Little-endian to Big-endian. For example, I may need to save to a
% binary file that needs to be read on big-endian system, or may need to
% send data over a communications channel that assumes big-endian
% representation.
%%
% Create a little-endian number (I know it is little-endian since my computer
% is a Little-endian system; see the section on checking endianness).
leNumber = uint32(258);
%%
% Get the bytes in the 32-bit little-endian number (note that the
% leftmost byte is the least-significant one).
byteSeq = typecast(leNumber, 'uint8')
%%
% See each byte as a binary number (each row is one byte)
dec2bin(byteSeq,8)
%%
% There are two ways to convert the little-endian value
% to a big-endian value
%%
% *Method 1*: Use the SWAPBYTES command
beNumber = swapbytes(leNumber)
newByteSeq = typecast(beNumber, 'uint8')
%%
% *Method 2*: Do the conversion myself
newByteSeq = byteSeq(end:-1:1)
beNumber = typecast(newByteSeq, 'uint32')
%% Help on functions
help class
%%
help cast
%%
help typecast
%%
help swapbytes