How to disable Matlab Integer Overflow saturation to get signed wraparound - matlab

I want to test a piece of function and from 127, it is normal for me that 127+1 = -128. But for Matlab, it saturates my value even though it is a desired behavior on my code.
There are explanations to disable this option on Simulink but what about for a script? I don't know how to disable this feature.

Overflow is not part of Matlab hypotheses.
You need to implement this behaviour in your script using the modulo function (mod).
For example:
>> a=127; mod(a+128,256)-128
ans =
127
>> a=128; mod(a+128,256)-128
ans =
-128

Since you use 127 and -128 as the examples, I assume you are working with int8 variable types. To get the modulo behavior you want, you could use a simple C mex routine to do the arithmetic (since your C compiler will in all likelihood optimize this overflow condition away as simple modulo behavior), or in m-code you can convert to a larger type and do the arithmetic yourself (assumes your machine uses 2's complement storage for integer types). E.g.,
a8 = int8(127); % sample data
b8 = int8(1); % sample data
a16 = int16(a8); % convert to larger type
b16 = int16(b8); % convert to larger type
c16 = a16 + b16 % do the addition in larger type
c16 = int16
128
c8s = typecast(c16,'int8') % typecast back to int8 (assume 2's complement storage)
c8s = 1x2
-128 0
c8 = c8s(1) % pick either c8s(1) or c8s(2) depending on endian of your machine
c8 = int8
-128
If you are working with arrays of numbers instead of scalars, then you could put this in a loop or vectorize the last line as either c8s(1:2:end) or c8s(2:2:end)

You may use fi object from Fixed-Point toolbox and set OverflowAction to Wrap.
Using fi for applying int8 type that overflows, is a bit of an overkill, but possible.
Example:
x = fi(127, true, 8, 0, 'OverflowAction', 'Wrap', 'SumMode', 'SpecifyPrecision', 'SumWordLength', 8, 'SumFractionLength', 0);
x + 1
Output:
ans =
-128
DataTypeMode: Fixed-point: binary point scaling
Signedness: Signed
WordLength: 8
FractionLength: 0
RoundingMethod: Nearest
OverflowAction: Wrap
ProductMode: FullPrecision
SumMode: SpecifyPrecision
SumWordLength: 8
SumFractionLength: 0
CastBeforeSum: true

If you really want to use the int8 overflow and not simulate it with the mod function, you can use the typecast function.
First, you need to convert your variable into an int (otherwise it is by default a double in Matlab). Then you cast it to an int8 and you keep only the first byte:
>> a=127; getfield(typecast(int64(a),'int8'),{1})
ans =
int8
127
>> a=128; getfield(typecast(int64(a),'int8'),{1})
ans =
int8
-128

Related

How to use bitset function in MATLAB to modify multiple bits simultaneously

>> a = 255
a =
255
>> bitset(a,1,0)
ans =
254
here the first bit is set to 0 so we get 11111110 equivalent to 254
>> bitset(a,[1,2],0)
ans =
254 253
here the 1st bit and 2nd bit are being set to 0 seperately. Hence we get
11111110 equivalent to 254
11111101 equivalent to 253
how to get 11111100 equivalent to 252?
Apply bitset twice:
bitset(bitset(a, 1, 0), 2, 0)
The order of application should not matter.
Alternatively, you can use the fact that bitset is an equivalent to applying the correct sequence of bitand, bitor and bitcmp operations.
Since you are interested in turning off multiple bits, you can do
bitand(bitset(a, 1, 0), bitset(a, 2, 0))
Here's a one-liner:
a = 255;
bits = [1,2];
bitand(a,bitcmp(sum(2.^(bits-1)),'uint32'))
Taken apart:
b = sum(2.^(bits-1))
computes the integer with the given bits set. Note that bits must not contain duplicate elements. Use unique to enforce this: bits = unique(bits).
c = bitcmp(b,'uint32')
computes the 32-bit complement of the above. ANDing with the complement resets the given bits.
bitand(a,c)
computes the binary AND of the input number and the integer with the given bits turned off.
Setting bits is easier:
a = 112;
bits = [1,2];
bitor(a,sum(2.^(bits-1)))
Maybe most explicit, easiest to understand, you can convert to a string representing binary and then do the operations there, then convert back.
a = 255
bin_a = flip(dec2bin(a)) % flip to make bigendian
bin_a([1, 2]) = '0'
a = bin2dec(flip(bin_a))
Here is a little recursive function based on the answer from #Mad Physicist that will allow zeroing of any number of bits in data . Thanks for the original info. The recursion is probably dead obvious to most people but it might help somebody out.
function y = zero_nbits(x, n)
y = bitset(x, n, 0)
if n > 1
y = zero_nbits(y, n-1);
end
end

What happens when I change int 8 to int 16

I understand that the int value is in relation with the storage capacity.But, if I change int 8 to int 16 only the capacity will be altered?
Since the other answers have not yet formalized this I will give you and explanation including some keywords to look up and some more elaborate explanation.
The size of a data type is actually based on the capacity of the storage.
int8 - 8 bits signed integer, MSB (most significant bit) representing the sign. Range [-2^7,2^7-1] = [-128,127]
uint8 - 8 bits unsigned integer, MSB denotes the highest power of 2. Range [0,2^8-1] = [0,255]
int16 - 16 bits signed integer
uint16 - 16 bits unsigned integer
I could keep going but you probably get the picture. There is also int32, uint32, int64, uint64.
There is also char which can be used for text, but also instead of uint8 (in MATLAB a char is 16-bits though) (with the difference that char is printed as a char and not a number). This is normal to do for many c-like languages.
The types float and double is different since they use a floating point precision, standardized by the IEEE. The format is used to represent large numbers in a good way.
This data type uses an exponential representation of the numbers. The data type allocates a fixed set of bits for exponential and precision digits and one bit for sign. A floating point number can be divided like this,
(sign),Mantissa,exponent
For double the bit allocation is 1-bit for sign, 11-bits for exponent, 52-bits for Mantissa. For single it is 8-bits for exponent, 23-bits for Mantissa.
This is some necessary background for discussing type conversion. When discussing type conversion you normally speak about implicit conversion and explicit conversion. The terms is not really relevant for Matlab since Matlab can identify type automatically.
a = 2; % a is a double
b=a; % b is a double
c = int8(57); % c is an int8
d = c; % d is an int 8
However explicit conversion is done with the built in conversion functions.
c = int8(57);
d = char(c);
When discussing different kinds of conversion we often talk about type promotion and type demotion. Type promotion is when a data type of lower precision is promoted to a type of higher precision.
a = int8(57);
b = int16(a);
This is lossless and considered safe. Type demotion is on the other hand when a type of higher precsion is converted to a type of lower precision.
c = int16(1234);
d = int8(c); % Unsafe! Data loss
This is generally considered risky and shuold be avoided. Normally the word type demotion is not used so often since this conversion is uncommon. A conversion from higher to lower precision needs to be checked.
function b = int16ToInt8(a)
if (any(a < -128 | a > 127))
error('Variable is out of range, conversion cannot be done.');
end
b=int8(a);
In most languages type demotion cannot be done implicitly. Also conversion between floating point types and integer types should be avoided.
An important note here is how Matlab initiates variables. If a "constructor" is not used (like a=int8(57)), then Matlab will automatically set the variable to double precision. Also, when you initiate a vector/matrix of integers like int64([257,3745,67]), then the "constructor" for the matrix is called first. So int64() will actually be called on a matrix of doubles. This is important because if the integer needs more precsion than 52-bits, the precision is too low for a double. So
int64([2^53+2^0,2^54+2^1, 2^59+2^2]) ~=
[int64(2^53) + int64(2^0), int64(2^54)+ int64(2^1), int64(2^59)+ int64(2^2)]
Further, in case the memory on the device allows it is commonly recommended to use int32 or int64 and double
Each type of integer has a different range of storage capacity:
int 8: Values range from -128 to 127
int 16: Values range from -32,768 to 32,767
You only need to worry about data loss when converting to a lower precision datatype. Because int16 is higher precision than int8, your existing data will remain intact but your data can span twice the range of values at the cost of taking up twice as much space (2 bytes vs. 1 byte)
a = int8(127);
b = int16(a);
a == b
% 1
whos('a', 'b')
% Name Size Bytes Class Attributes
%
% a 1x1 1 int8
% b 1x1 2 int16
int8 variables can range from -128 to 127, while this range for int16 class is from -32,768 to 32,767. Obviously, memory is the price to pay for the wider range ;)
Note 1: These limits do not apply only on the variables when defining them, but also usually on the outputs of calculations!
Example:
>> A = int8([0, 10, 20, 30]);
>> A .^ 2
ans =
0 100 127 127
>> int16(A) .^ 2
ans =
0 100 400 900
Note 2: Once you switch to int16, usually you should do it for all variables that participate in calculations together.
Example:
>> A + int16(A)
Error using +
Integers can only be combined with integers of the same class, or scalar doubles.

Increase Hex2dec or dec2hex output range in Matlab

I have a strange problem with hex2dec function in Matlab.
I realized in 16bytes data, it omits 2 LSB bytes.
hex2dec('123123123123123A');
dec2hex(ans)
Warning: At least one of the input numbers is larger than the largest integer-valued floating-point
number (2^52). Results may be unpredictable.
ans =
1231231231231200
I am using this in Simulink. Therefore I cannot process 16byte data. Simulink interpret this as a 14byte + '00'.
You need to use uint64 to store that value:
A='123123123123123A';
B=bitshift(uint64(hex2dec(A(1:end-8))),32)+uint64(hex2dec(A(end-7:end)))
which returns
B =
1310867527582290490
An alternative way in MATLAB using typecast:
>> A = '123123123123123A';
>> B = typecast(uint32(hex2dec([A(9:end);A(1:8)])), 'uint64')
B =
1310867527582290490
And the reverse in the opposite direction:
>> AA = dec2hex(typecast(B,'uint32'));
>> AA = [AA(2,:) AA(1,:)]
AA =
123123123123123A
The idea is to treat the 64-integer as two 32-bit integers.
That said, Simulink does not support int64 and uint64 types as others have already noted..

bit level operation in Matlab

How can we do this bit level operation in Matlab:
int instructionWord;
a = (instructionWord >>> 21) & 0x1F;
The code right shifts the instructionWord by 21 and obtains the least 5 bits. How can this be equivalently done in Matlab?
Given that your input value is an integer, you could do the following:
a = mod( floor(instructionWord/2^21), 32)
Another more bit-like solution would be:
a = bitand( bitshift(instructionWord, -21), hex2dec('1F'))
The last method will throw an error if you feed it anything else than intergers.
By the way, your variable instructionWord is declared like a signed integer. But if it is an instruction word or something like that, an unsigned integer would make more sense. The expressions above expect that your input is only positive. If not, it will require a bit more code to model the >>> (logical right-shift) in matlab.
see the bitshift page:
Code
a = intmax('uint8');
s1 = 'Initial uint8 value %5d is %08s in binary\n';
s2 = 'Shifted uint8 value %5d is %08s in binary\n';
fprintf(s1,a,dec2bin(a))
for i = 1:8
a = bitshift(a,1);
fprintf(s2,a,dec2bin(a))
end
Output
Initial uint8 value 255 is 11111111 in binary
Shifted uint8 value 254 is 11111110 in binary
Shifted uint8 value 252 is 11111100 in binary
Shifted uint8 value 248 is 11111000 in binary
Shifted uint8 value 240 is 11110000 in binary
Shifted uint8 value 224 is 11100000 in binary
Shifted uint8 value 192 is 11000000 in binary
Shifted uint8 value 128 is 10000000 in binary
Shifted uint8 value 0 is 00000000 in binary
EDIT
see bitget page on how to extract a specific bit value.
a = rem( bitshift( instructionWord, -21) , 2^5)
bitshift does the shifting of bits; and rem find the remainder from division by 32 giving last 5 bits' value.

Performing Bit modification on Floating point numbers in Matlab

I'm working in Matlab using Non-negative Matrix factorization to decompose a matrix into two factors. Using this I get from A two double precision floating point matrices, B and C.
sample results are
B(1,1) = 0.118
C(1,1) = 112.035
I am now trying to modify specific bits within these values but using the bitset function on either values I get an error because bitset requires unsigned integers.
I have also tried using dec2bin function, which I assumed would convert decimals to binary but it returns '0' for B(1,1).
Does anyone know of any way to deal with floats at bit level without losing precision?
You should look into the typecast and bitset functions. (Doc here and here respectively). That lets you do stuff like
xb = typecast( 1.0, 'uint64' );
xb = bitset( xb, 10, 1 );
typecast( xb, 'double' );
The num2hex and hex2num functions are your friends. (Though not necessarily very good friends; hexadecimal strings aren't the best imaginable form for working on binary floating-point numbers. You could split them into, say, 8-nybble chunks and convert each to an integer.)
From the MATLAB docs:
num2hex([1 0 0.1 -pi Inf NaN])
returns
ans =
3ff0000000000000
0000000000000000
3fb999999999999a
c00921fb54442d18
7ff0000000000000
fff8000000000000
and
num2hex(single([1 0 0.1 -pi Inf NaN]))
returns
ans =
3f800000
00000000
3dcccccd
c0490fdb
7f800000
ffc00000