Overflow/underflow in unsigned numbers - numbers

So, if you have a carry out of 1 on addition with unsigned numbers, you have overflowed, and if you have a carry out of 0 with subtraction, you have underflowed. Does this work in every case, though?
If you do 5-0:
0101
-0000
=
0101
+(1111 + 1)
=
0101
+0000
= 0101... there is a carry out of zero here, instead of 1. How does one account for this case? Is there a different way to do it?
(using MIPS architecture, or anything else)
---Edit
Thanks Amadan. I understand that part, though. My problem is just that zero seems to be a special case. It does not seem to follow what normal numbers do: in my example above, there is no carry out of 1.
I'm doing circuit design working with an ALU at the moment and trying to implement the overflow detection, when this one case came up that doesn't follow what the others do.
We are assuming that with subtraction, the second operand is preinverted (twos complement) before going into the ALU (then added to the first operand). So, whenever the "invert_b" for subtraction is set to 1, b is inverted and we assume that the case we are checking for is subtraction, which should have a carry out of 1.

I believe the msbit carry out bit on its own covers unsigned and for signed you look to see if the carry in to the msbit and the carry out differ.
5-0 does not overflow because the result fits in the number of bits available. The same way that 15-1 does not overflow a 4 bit system for signed numbers
5 - 0 = 0101 + 1111 + 1
1
0101
+1111
=====
11111
0101
+1111
=====
0101
so 5 - 0 certainly carries out a 1, since this is a subtract that is not an overflow
15 - 1 = 1111 + ~1 with the carry in set
1
1111
1110
====
11111
1111
1110
====
1110
a subtract with a 1 out is not an unsigned overflow as you stated
Likewise -1 - 1 = 1111 + ~1 with the carry in bit set
11111
1111
1110
====
1110
the carry in to the last bit is a 1 the carry out is a 1 they match, no signed overflow.
8 + 8 = 1000 + 1000 with the carry in clear
0
1000
+1000
=====
10000
1000
+1000
=====
0000
unsigned overflow.
hmmm 4 + 4
0
0100
+0100
=====
01000
0100
+0100
=====
1000
unsigned add the carry out is 0 this is not an unsigned overflow. but this is a signed overflow because the carry in to the msbit and carry out differ. +4 + +4 = +8, in a 4 bit signed system you cannot represent +8, so the signed overflow is accurate.
No matter how many bits the weird numbers are all zeros and a one and the rest zeros, 0 and 8 or -8 for a 4 bit system.
Make a chart either with 2, 3, or 4 bit numbers all combinations and manually look through all of them to see that they make sense. whatever you find will scale no matter how many bits wide, a 100 bit adder works like a 10 bit adder...
add C V unsigned signed
00 + 00 = 000 0 0 0 + 0 = 0 0 + 0 = 0
00 + 01 = 001 0 0 0 + 1 = 1 0 + 1 = 1
00 + 10 = 010 0 0 0 + 2 = 2 0 + -2 = -2
00 + 11 = 011 0 0 0 + 3 = 3 0 + -1 = -1
01 + 00 = 001 0 0 1 + 0 = 1 1 + 0 = 1
01 + 01 = 010 0 1 1 + 1 = 2 1 + 1 = 2 signed cannot represent a +2
01 + 10 = 011 0 0 1 + 2 = 3 1 + -2 = -1
01 + 11 = 100 1 0 1 + 3 = 4 1 + -1 = 0 unsigned cannot represent +4
10 + 00 = 010 0 0 2 + 0 = 2 -2 + 0 = -2
10 + 01 = 011 0 0 2 + 1 = 3 -2 + 1 = -1
10 + 10 = 100 1 1 2 + 2 = 4 -2 + -2 = -4 neither +4 nor -4 will fit in 2 bits
10 + 11 = 101 1 1 2 + 3 = 5 -2 + -1 = -3 neither +4 nor -3 will fit in 2 bits
11 + 00 = 011 0 0 3 + 0 = 3 -1 + 0 = -1
11 + 01 = 100 1 0 3 + 1 = 4 -1 + 1 = -2 +4 does not fit in 2 bits
11 + 10 = 101 1 1 3 + 2 = 5 -1 + -2 = -3 neither +5 nor -3 fit in 2 bits
11 + 11 = 110 1 0 3 + 3 = 6 -1 + -1 = -2 6 does not fit in 2 bits
sub
00 - 00 = 100 0 0
00 - 01 = 011 1 0 0 - 1 = -1 -1 does not fit in an unsigned result
00 - 10 = 010 1 1 0 - 2 = -2 0 - -2 = +2
00 - 11 = 001 1 0 0 - 3 = -3
01 - 00 = 101 0 0
01 - 01 = 100 0 0
01 - 10 = 011 1 1 1 - 2 = -1 1 - -2 = 3
01 - 11 = 010 1 1 1 - 3 = -2 1 - -1 = 2
10 - 00 = 110 0 0
10 - 01 = 101 0 1 -2 - 1 = -3
10 - 10 = 100 0 0
10 - 11 = 011 1 0 2 - 3 = -1
11 - 00 = 111 0 0
11 - 01 = 110 0 0
11 - 10 = 101 0 0
11 - 11 = 100 0 0
The code that generated the above
printf("add\n");
for(ra=0;ra<4;ra++)
{
for(rb=0;rb<4;rb++)
{
rd=(ra&1)+(rb&1);
rc=ra+rb;
rd=(rd>>1)&1;
re=(rc>>2)&1;
if(re) c=1; else c=0;
if(rd!=re) v=1; else v=0;
if(ra&2) printf("1"); else printf("0");
if(ra&1) printf("1"); else printf("0");
printf(" + ");
if(rb&2) printf("1"); else printf("0");
if(rb&1) printf("1"); else printf("0");
printf(" = ");
if(rc&4) printf("1"); else printf("0");
if(rc&2) printf("1"); else printf("0");
if(rc&1) printf("1"); else printf("0");
printf(" %u %u\n",c,v);
}
}
printf("sub\n");
for(ra=0;ra<4;ra++)
{
for(rb=0;rb<4;rb++)
{
rd=(ra&1)+((~rb)&1)+1;
rc=ra+((~rb)&3)+1;
rd=(rd>>1)&1;
re=(rc>>2)&1;
if(re) c=0; else c=1;
if(rd!=re) v=1; else v=0;
if(ra&2) printf("1"); else printf("0");
if(ra&1) printf("1"); else printf("0");
printf(" - ");
if(rb&2) printf("1"); else printf("0");
if(rb&1) printf("1"); else printf("0");
printf(" = ");
if(rc&4) printf("1"); else printf("0");
if(rc&2) printf("1"); else printf("0");
if(rc&1) printf("1"); else printf("0");
printf(" %u %u\n",c,v);
}
}
Now your question was talking about unsigned numbers yes? so you may not care about the V bit nor the right half, the signed half.
Here is some HDL/RTL for a small 16 bit processor I implemented:
case 4b0000:
{
//0000 add rd,rs
op_a = bundle(1b0,reg[bundle(2b0,inst[4;8])].value);
op_b = bundle(1b0,reg[bundle(2b0,inst[4;4])].value);
op_res = op_a + op_b;
reg[1].value[CBIT] <= op_res[16];
reg[1].value[NBIT] <= op_res[15];
if(op_res[16;0] == 16h0000)
{
reg[1].value[ZBIT] <= 1b1;
}
else
{
reg[1].value[ZBIT] <= 1b0;
}
if((op_a[15] == op_b[15]) && (op_res[15] != op_b[15] ) )
{
reg[1].value[VBIT] <= 1b1;
}
else
{
reg[1].value[VBIT] <= 1b0;
}
reg[bundle(2b0,inst[4;8])].value <= op_res[16;0];
}
case 4b0001:
{
//0001 sub rd,rs
op_a = bundle(1b0,reg[bundle(2b0,inst[4;8])].value);
op_b = bundle(1b0,reg[bundle(2b0,inst[4;4])].value);
op_res = op_a - op_b;
reg[1].value[CBIT] <= (~op_res[16]);
reg[1].value[NBIT] <= op_res[15];
if(op_res[16;0] == 16h0000)
{
reg[1].value[ZBIT] <= 1b1;
}
else
{
reg[1].value[ZBIT] <= 1b0;
}
if((op_a[15] != op_b[15]) && (op_res[15] == op_b[15] ) )
{
reg[1].value[VBIT] <= 1b1;
}
else
{
reg[1].value[VBIT] <= 1b0;
}
reg[bundle(2b0,inst[4;8])].value <= op_res[16;0];
}
I have/had seen the msbit thing for signed overflow in other logic and couldnt find a case where it didnt match the carry in vs carry out method when trying every possible combination in a head to head analysis.
If I went overboard with the answer I dont mind clipping it off at the beginning where it shows that 5 - 0 has a 1 as a carry out of 1, which for a subtract is not an overflow. The long answer because it can be hard to wrap your head around signed vs unsigned and how the adder works in logic in general. The adder does not know or care about signed or unsigned, it does care about add vs subtract, with subtract you invert the second operand, invert the carry in to the lsbit and the carry out of the msbit (think about add, add with carry, sub and sub with carry). The signed vs unsigned takes care if itself (the beauty of twos complement). Reducing the above to an unsigned only discussion makes it more than half as simple as the signed overflow is not (as) obvious (as unsigned overflow) to the casual observer.
I sure hope I cut and pasted the debugged HDL , will get a lot of responses/corrections if I didnt...I spent a few days convincing myself of all of the above and comparing to the results of other processors I had access to, etc. Hopefully this saves you a few days.

Not an expert, but the whole statement on subtraction seems wrong.
You can implement subtraction in two basic ways: directly as subtraction, or as addition of two's complement.
If you go with two's complement addition, then it is as you say: carry of 1 is underflow.
5 - 6
= 0101 - 0110
= 0101 + (1001 + 1)
= 0101 + 1010
= (0)1111, carry 0 = underflow
If you subtract directly, then 1 carry is underflow:
0101 - 0110:
0 to 1 is 1
1 to (1)0 is 1, carry 1
1 + 1 to (1)1 is 1, carry 1
0 + 1 to (1)0 is 1, carry 1 = underflow

There may be other equivalent ways of designing overflow detection units for adders, but the most common is Cin XOR Cout. For example, see the end of lecture 4 http://cs.nyu.edu/~gottlieb/courses/2007-08-fall/arch/class-notes.html
It simply checks if the numbers being added (if something is inverted for 2's complement or not doesn't matter, we look at these values afterwards) carry in to the last digit's calculation but not into the digit beyond the supported bit-size, or the opposite.
This makes sense because if they carry in and not out the result must be negative (since the MSB must be 1) but the operands must be positive (since if they were negative there would be carry out). This is the definition of overflow, since two positives cannot sum to a negative.
This is a signed model however, I'm not sure if that's what you're looking for since you mentioned unsigned. If that's the case, then you're right, the simple addition model has overflow when carry out is 1 (this is equivalent to the above if you consider the addition to have an extra 0 for each operands' MSB, then the carry out will always be 0 and there's overflow iff the carry in is 1. The carry in in this case is the carry out in our model).
Subtraction results in underflow if the value is negative. We can again derive an equivalence if we consider the positive operand to have an appended MSB of 0 and the negative operand one of 1 (sign extension). Then we are negative when the MSB of the result is 1. This happens iff the carry out in our original model (the carry in in the new model) is 0, since only then will the MSB of the result in the new model remain 1.
You example is no exception: 0101 + 1111 + 1 = 0101 with a carry out of 1, and therefore no underflow, since the result is positive.

Related

All unique multiplication products

I'd like to obtain all unique products for a given vector.
For example, given a:
a = [4,10,12,3,6]
I want to obtain a matrix that contains the results of:
4*10
4*12
4*3
4*6
10*12
10*3
10*6
12*3
12*6
3*6
Is there a short and/or quick way of doing this in MATLAB?
EDIT: a may contain duplicate numbers, giving duplicate products - and these must be kept.
Given:
a =
4 10 12 3 6
Construct the matrix of all pairwise products:
>> all_products = a .* a.'
all_products =
16 40 48 12 24
40 100 120 30 60
48 120 144 36 72
12 30 36 9 18
24 60 72 18 36
Now, construct a mask to keep only those values below the main diagonal:
>> mask = tril(true(size(all_products)), -1)
mask =
0 0 0 0 0
1 0 0 0 0
1 1 0 0 0
1 1 1 0 0
1 1 1 1 0
and apply the mask to the product matrix:
>> unique_products = all_products(mask)
unique_products =
40
48
12
24
120
30
60
36
72
18
If you have the Statistics Toolbox, you can abuse pdist, which considers only one of the two possible orders for each pair:
result = pdist(a(:), #times);
One option involves nchoosek, which returns all combinations of k elements out of a vector, each row is one combination. prod computes the product of rows or columns:
a = [4,10,12,3,6];
b = nchoosek(a,2);
b = prod(b,2); % 2 indicates rows
Try starting with this. Have the unique function filter out the result of multiplying a by itself.
b = unique(a*a')

How to rediagonalize the diagonal of a matrix in MATLAB?

I have a 5x5 matrix, V1, with values and a classification in both the first row and first column. If you wanted to, you could think of sectors in an economy that have a classification. The first two sectors have a 3-digit classification, the last two have a 4-digit classification.
V1 =
0 101 111 1234 1111
101 4 0 7 0
111 5 8 0 0
1234 6 0 6 2
1111 0 0 4 9
Now, I want to rediagonalize all columns that have a 4-digit code using MATLAB. That means in four-digit columns the values should be summed up over the whole column and shifted to the diagonal. In particular, the code should perform the following steps:
If the classification code has four digits AND the classification code is equal in both the first row AND the first column, then sum up the whole column (excl. the first value of the column, which is the classification code itself)
Elseif the classification code has three digits in the column, then leave the value as is
Else assign a zero.
The resulting matrix should look like this:
V1 =
0 101 111 1234 1111
101 4 0 0 0
111 5 8 0 0
1234 6 0 17 0
1111 0 0 0 11
I have tried the following code, but it didn't work:
[vrow vcol] = size(V1)
for c = 2:vcol;
for r = 2:vrow;
if all([ V1(1,c) == V1(r,1), numel(num2str(V1(1,c))) > 3, numel(num2str(V1(r,1))) > 3 ]) ;
V1(r,c) = sum(V1(2:end,c)) ;
elseif numel(num2str(V1(1,c))) == 3;
V1(r,c) = V1(r,c);
else
V1(r,c) = 0;
end
end
end
With the above code, I got the following result, which is sort of close to the desired result, only the column summations do not work yet:
V1 =
0 101 111 1234 1111
101 4 0 0 0
111 5 8 0 0
1234 6 0 10 0
1111 0 0 0 9
Thank you for any hints!
Since you're changing elements of V1 as the code executes, but also relying on values in V1 to get your answer (when you sum columns), you'll have errors if you set a value to 0 before it's needed in a sum. Below, I've fixed that issue by initializing a second matrix V2 as your output. I've also gone ahead and removed a few unneeded lines, as explained in the comments
[vrow vcol] = size(V1);
V2 = zeros(vrow, vcol);
for c = 2:vcol;
for r = 2:vrow;
if all([ V1(1,c) == V1(r,1), numel(num2str(V1(1,c))) > 3]) ; %Third statement was redundant
V2(r,c) = sum(V1(2:end,c)) ;
elseif numel(num2str(V1(1,c))) == 3;
V2(r,c) = V1(r,c);
end %We intialized whole thing to 0, so we don't need to set elements to 0
end
end

Change vector if even/odd in a matrix

I'm new to Matlab programming and I've only had 3 classes so far. I'm having problem with my homework. (Also I am from Iceland so english is not my first language, so please forgive my grammar)
I'm given a matrix, A and I'm supposed to change the value? of a vector to 0 if it is an even number and to 1 if it is an odd number.
This is what I have so far.
A = [90 100 87 43 20 58; 29 5 12 94 8 62; 75 21 36 83 35 24; 47 51 70 59 82 33];
B = zeros(size(A));
for k = 1:length(A)
if mod(A(k),2)== 0 %%number is even
B(k) = 0;
else
B(k) = 1; %%number is odd
end
end
B(A,2==0) = 0;
B(A,2~=0) = 1
What I am getting it this:
B =
0 0 0 0 0 0
1 1 0 0 0 0
1 0 0 0 0 0
1 0 0 0 0 0
1 0 0 0 0 0
If anyone could please help me, it would be greatly appreciated :)
You are very close. Don't use length(A) - use numel(A). length(A) returns the number of elements along the largest dimension. As such, because you have 6 columns and 4 rows, this loop will only iterate 6 times. numel returns the total number of elements in the array A, which is what you want as you want to iterate over each value in A.
Therefore:
A = [90 100 87 43 20 58; 29 5 12 94 8 62; 75 21 36 83 35 24; 47 51 70 59 82 33];
B = zeros(size(A));
for k = 1:numel(A) %// Change
if mod(A(k),2)== 0 %%number is even
B(k) = 0;
else
B(k) = 1; %%number is odd
end
end
The above loop will go through every single element in the matrix and set the corresponding element to 0 if even and 1 if odd.
However, I encourage you to use vectorized operations on your code. Don't use loops for this. Specifically, you can do this very easily with a single mod call:
B = mod(A,2);
mod(A,2) will compute the modulus of every value in the matrix A with 2 as the operand and output a matrix B of the same size. This will exactly compute the parity of each number.
We get for B:
>> A = [90 100 87 43 20 58; 29 5 12 94 8 62; 75 21 36 83 35 24; 47 51 70 59 82 33];
>> B = mod(A,2)
B =
0 0 1 1 0 0
1 1 0 0 0 0
1 1 0 1 1 0
1 1 0 1 0 1

MATLAB vectorize

I was wondering if anyone could help me vectorize this piece of code.
fr_bw is a matrix.
for i=1:height
for j=1:width
[min_w, min_w_index] = min(w(i,j,:));
mean(i,j,min_w_index) = double(fr_bw(i,j));
sd(i,j,min_w_index) = sd_init;
end
end
I can't help you with this sif (match == 0) stuff -- if it's supposed to be if (match == 0) you're not changing match so it could be brought outside the loop.
Otherwise, how about this:
[min_w, min_w_index] = min(w, [], 3);
r = repmat((1:height)',1,width);
c = repmat(1:width,height,1);
ind = sub2ind(size(w),r(:),c(:),min_w_index(:));
w_mean(ind) = double(fr_bw);
w_sd(ind) = repmat(sd_init,height,width);
(Please note that mean is a built-in function so I renamed your variables to w_mean and w_sd.)
The sub2ind call gives you linear indices that correspond to subscripts. (Direct subscripts won't work; z([a1 a2 a3],[b1 b2 b3],[c1 c2 c3]) refers to 27 elements in the z array with subscripts that are the cartesian product of the specified subscripts, rather than z(a1,b1,c1) and z(a2,b2,c2) and z(a3,b3,c3) that you might expect.)
Here's an illustration of this technique:
>> height = 6; width = 4;
>> w = randi(1000,height,width,2)
w(:,:,1) =
426 599 69 719
313 471 320 969
162 696 531 532
179 700 655 326
423 639 408 106
95 34 820 611
w(:,:,2) =
779 441 638 696
424 528 958 68
91 458 241 255
267 876 677 225
154 519 290 668
282 944 672 845
>> [min_w, min_w_index] = min(w, [], 3);
>> min_w_index
min_w_index =
1 2 1 2
1 1 1 2
2 2 2 2
1 1 1 2
2 2 2 1
1 1 2 1
>> z = zeros(height,width,2);
>> r = repmat((1:height)',1,width);
>> c = repmat(1:width,height,1);
>> ind = sub2ind(size(w),r(:),c(:),min_w_index(:));
>> z(ind) = 1
z(:,:,1) =
1 0 1 0
1 1 1 0
0 0 0 0
1 1 1 0
0 0 0 1
1 1 0 1
z(:,:,2) =
0 1 0 1
0 0 0 1
1 1 1 1
0 0 0 1
1 1 1 0
0 0 1 0
A few comments on your code:
Did you mean if rather than sif?
The code isn't replicable at the moment, since you haven't provided examples of the variables w, fr_bw and sd_init. This makes it tricky to give an exact answer.
It looks like you are assigning things to a variable named mean. This will shadow the mean function, and probably cause you grief.
I'm just guessing, but I don't think double does what you think it does. You don't need to convert individual elements of a numeric matrix to type double; they are already the correct type. (On the other hand, if fr_bw is a different type, say integers, then you should create a new variable dbl_fr_bw = double(fr_bw); before the loops.
You might need to adjust the dimension over which you calculate the minimums, but the first line of the loop can be replaced with
[min_w, min_w_index] = min(w, [], 3)
The second line with
mean_values(:, :, min_w_index) = double(fr_bw)
Not sure about the third line, since I don't know what sd_init is/does.

How to compare a matrix element with its neighbours without using a loop in MATLAB?

I have a matrix in MATLAB. I want to check the 4-connected neighbours (left, right, top, bottom) for every element. If the current element is less than any of the neighbours then we set it to zero otherwise it will keep its value. It can easily be done with loop, but it is very expensive as I have thousands of these matrices.
You might recognize it as nonmaxima suppression after edge detection.
If you have the image processing toolbox, you can do this with a morpological dilation to find local maxima and suppress all other elements.
array = magic(6); %# make some data
msk = [0 1 0;1 0 1;0 1 0]; %# make a 4-neighbour mask
%# dilation will replace the center pixel with the
%# maximum of its neighbors
maxNeighbour = imdilate(array,msk);
%# set pix to zero if less than neighbors
array(array<maxNeighbour) = 0;
array =
35 0 0 26 0 0
0 32 0 0 0 25
31 0 0 0 27 0
0 0 0 0 0 0
30 0 34 0 0 16
0 36 0 0 18 0
edited to use the same data as #gnovice, and to fix the code
One way to do this is with the function NLFILTER from the Image Processing Toolbox, which applies a given function to each M-by-N block of a matrix:
>> A = magic(6) %# A sample matrix
A =
35 1 6 26 19 24
3 32 7 21 23 25
31 9 2 22 27 20
8 28 33 17 10 15
30 5 34 12 14 16
4 36 29 13 18 11
>> B = nlfilter(A,[3 3],#(b) b(5)*all(b(5) >= b([2 4 6 8])))
B =
35 0 0 26 0 0
0 32 0 0 0 25
31 0 0 0 27 0
0 0 0 0 0 0
30 0 34 0 0 16
0 36 0 0 18 0
The above code defines an anonymous function which uses linear indexing to get the center element of a 3-by-3 submatrix b(5) and compare it to its 4-connected neighbors b([2 4 6 8]). The value in the center element is multiplied by the logical result returned by the function ALL, which is 1 when the center element is larger than all of its nearest neighbors and 0 otherwise.
If you don't have access to the Image Processing Toolbox, another way to accomplish this is by constructing four matrices representing the top, right, bottom and left first differences for each point and then searching for corresponding elements in all four matrices that are non-negative (i.e. the element exceeds all of its neighbours).
Here's the idea broken down...
Generate some test data:
>> sizeA = 3;
A = randi(255, sizeA)
A =
254 131 94
135 10 124
105 191 84
Pad the borders with zero-elements:
>> A2 = zeros(sizeA+2) * -Inf;
A2(2:end-1,2:end-1) = A
A2 =
0 0 0 0 0
0 254 131 94 0
0 135 10 124 0
0 105 191 84 0
0 0 0 0 0
Construct the four first-difference matrices:
>> leftDiff = A2(2:end-1,2:end-1) - A2(2:end-1,1:end-2)
leftDiff =
254 -123 -37
135 -125 114
105 86 -107
>> topDiff = A2(2:end-1,2:end-1) - A2(1:end-2,2:end-1)
topDiff =
254 131 94
-119 -121 30
-30 181 -40
>> rightDiff = A2(2:end-1,2:end-1) - A2(2:end-1,3:end)
rightDiff =
123 37 94
125 -114 124
-86 107 84
>> bottomDiff = A2(2:end-1,2:end-1) - A2(3:end,2:end-1)
bottomDiff =
119 121 -30
30 -181 40
105 191 84
Find the elements that exceed all of the neighbours:
indexKeep = find(leftDiff >= 0 & topDiff >= 0 & rightDiff >= 0 & bottomDiff >= 0)
Create the resulting matrix:
>> B = zeros(sizeA);
B(indexKeep) = A(indexKeep)
B =
254 0 0
0 0 124
0 191 0
After wrapping this all into a function and testing it on 1000 random 100x100 matrices, the algorithm appears to be quite fast:
>> tic;
for ii = 1:1000
A = randi(255, 100);
B = test(A);
end; toc
Elapsed time is 0.861121 seconds.