How does `Skipcond` work in the MARIE assembly language? - loops

I am trying to understand the MARIE assembly language. I don't quite understand skipcond for
doing things like <, or >, or multiply or divide.
I am taking this simple program:
x = 1
while x < 10 do
x = x +1
endwhile;
What I don't understand is how to use certain skip conditions:
Skipcond 800 if AC > 0,
Skipcond 400 if AC = 0,
Skipcond 000 if AC < 0
Now, I know I would subtract x from 10 and test using skipcond.
I am not sure which one and why. I guess if I knew how they really work maybe it would be easier to understand. Why is it used to compare to zero?
This is what I have:
100 load one
101 store x
102 subt ten
103 skipcond400 if x-10 = 0? // or skpcond000 x -10 < 0??

while x < 10 do
x = x + 1
will jump out of the loop as soon as x equals 10. If you subtract 10 from x, you'll get a negative value until x equals 10 (and the value is 0). So using skpcond000 would be wrong as it would jump out too soon. So skpcond400 is correct.
Perhaps it is easier to understand if you change the C code so it will be closer to the assembly code:
Original: while (x < 10) do
Subtract 10: while ((x - 10) < 0) do
Use != instead of <: while ((x - 10) != 0) do
Also note that you have to increase x after the condition to reproduce identical behaviour to the while loop.

This may help. There are many ways to write this but I think this is the easiest way to understand what is happening in the loop. Note: usually variables are placed at the bottom of the program.
while x<10
x = x+1
Org 100
Load One / loads accumulator = 1 from a decimal constant
Store X / initialize the var x = 1
loop, Load X / loads x into the accumulator
Subt Ten / compares x to 10
Skipcond 000 / if ac < 0 i.e. if x < 10 run rest of loop body
JUMP Endloop / if ac => 10 terminate loop
Load X / begin the Loop
ADD One / add 1 to x
Store X / store new value in X
JUMP loop / continue loop
Endloop Halt / ends loop
One = DEC 1 Constant
Ten = DEC 10 Constant
X = 0 Variable

Related

Check subset sum for special array equation

I was trying to solve the following problem.
We are given N and A[0]
N <= 5000
A[0] <= 10^6 and even
if i is odd then
A[i] >= 3 * A[i-1]
if i is even
A[i]= 2 * A[i-1] + 3 * A[i-2]
element at odd index must be odd and at even it must be even.
We need to minimize the sum of the array.
and We are given a Q numbers
Q <= 1000
X<= 10^18
We need to determine is it possible to get subset-sum = X from our array.
What I have tried,
Creating a minimum sum array is easy. Just follow the equations and constraints.
The approach that I know for subset-sum is dynamic programming which has time complexity sum*sizeof(Array) but since sum can be as large as 10^18 that approach won't work.
Is there any equation relation that I am missing?
We can make it with a bit of math:
sorry for latex I am not sure it is possible on stack?
let X_n be the sequence (same as being defined by your A)
I assume X_0 is positive.
Thus sequence is strictly increasing and minimization occurs when X_{2n+1} = 3X_{2n}
We can compute the general term of X_{2n} and X_{2n+1}
v_0 =
X0
X1
v_1 =
X1
X2
the relation between v_0 and v_1 is
M_a =
0 1
3 2
the relation between v_1 and v_2 is
M_b =
0 1
0 3
hence the relation between v_2 and v_0 is
M = M_bM_a =
3 2
9 6
we deduce
v_{2n} =
X_{2n}
X_{2n+1}
v_{2n} = M^n v_0
Follow the classical diagonalization... and we (unless mistaken) get
X_{2n} = 9^n/3 X_0 + 2*9^{n-1}X_1
X_{2n+1} = 9^n X_0 + 2*9^{n-1}/3X_1
recall that X_1 = 3X_0 thus
X_{2n} = 9^n X_0
X_{2n+1} = 3.9^n X_0
Now if we represent the sum we want to check in base 9 we get
9^{n+1} 9^n
___ ________ ___ ___
X^{2n+2} X^2n
In the X^{2n} places we can only put a 1 or a 0 (that means we take the 2n-th elem from the A)
we may also put a 3 in the place of the X^{2n} place which means we selected the 2n+1th elem from the array
so we just have to decompose number in base 9, and check whether all its digits or either 0,1 or 3 (and also if its leading digit is not out of bound of our array....)

Matlab: Find points within a certain range in an array and their order/location in the array?

I've an array
X =
10
5 (e)
20
5
30
6
40
4
50
3
60
8
70
12
and so on...
I already know the value 5 which I've called e. I also know where it is located in the array. I want the following:
all the elements in X(2:2:end) within a certain range of +/-3 from e. (which are 5, 5, 6, 4, 3, 8).
the corresponding X(1:2:end) to the values we found within range. That means the final answer Y should be:
Y =
10
5
20
5
30
6
40
4
50
3
60
8
Thanks a lot!
In MATLAB/Octave, you can find the indexes of non-zero elements with the function find. Your problem is easily solved combining find with logic operators:
Y = X(find(X <= X(2)+3 & X >= X(2)-3));
Explained:
e = X(2)
X <= e+3 % Produces a Matrix with the element-wise result (1 or 0). The
X >= e-3 % values are determined by the logic operators >= and <=.
find(X) % Returns a matrix with the indeces of non-zero elements of X.
X(find(X)) % Returns the non-zero elements.
Tested in Octave (though should work in MATLAB too).
Solved!
X = [10; 5; 20; 5; 30; 6; 40; 4; 50; 3; 60; 8; 70; 12];
Xodd=X(1:2:end);
Xeven=X(2:2:end);
i=find(Xeven>5) %just an example could be done with other conditions
t=[Xodd(i) Xeven(i)];
%cascade them back!
Y=t';Y=Y(:);

Prolog: How come this loop doesn't work?

I just started learning prolog recently and am confused about how the recursion works. I have written this code:
test(X,B):- B is X + 2, B < 22, test(B,_).
test(X,Y).
I want it to return 20 or 21, but instead, if I call, say, test(4,X) it returns 6 over and over again (7 times to be exact), like this:
X = 6 ;
X = 6 ;
X = 6 ;
...
etc. So I was wondering what I was doing wrong. Thanks in advance for the help! Really appreciate it.
You misinterpreted the result you got, look:
?- test(4,X).
X = 6
; X = 6
; X = 6
; X = 6
; X = 6
; X = 6
; X = 6
; X = 6
; true. % <====
Note the true at the end, it means: Yes, this is true for any X!
Here is what you probably meant to write - trying to simulate your exact way of expression:
mtest(X0, X) :-
X1 is X0+2,
X1 < 22,
mtest(X1, X).
mtest(X0, X) :-
X is X0,
X+2 >= 22.
Some things are remarkable:
Note variable X in the first clause: It "hands back" the result.
The second clause needs to express the opposite of the very condition you gave in the first clause, because clauses are read independently of each other. In your original program the fact test(X,Y). stated that the relation is true for everything! (You got a warning for that, didn't you?) For example, also test(7,1000). succeeded.
The X is X0 is here to ensure that the second argument will be only a number but not an expression.
In any case, as a beginner, try to use library(clpfd), clpfd instead of (is)/2. Or even better, start with successor-arithmetics.

count elements falling within certain thresholds in array in matlab?

I have a huge vector. I have to count values falling within certain ranges.
the ranges are like 0-10, 10-20 etc. I have to count the number of values which fall in certain range.
I did something like this :
for i=1:numel(m1)
if (0<m1(i)<=10)==1
k=k+1;
end
end
Also:
if not(isnan(m1))==1
x=(0<m1<=10);
end
But both the times it gives array which contains all 1s. What wrong am I doing?
You can do something like this (also works for non integers)
k = sum(m1>0 & m1<=10)
You can use logical indexing. Observe:
>> x = randi(40, 1, 10) - 20
x =
-2 17 -12 -9 -14 -14 15 4 2 -14
>> x2 = x(0 < x & x < 10)
x2 =
4 2
>> length(x2)
ans =
2
and the same done in one step:
>> length(x(0 < x & x < 10))
ans =
2
to count the values in a specific range you can use ismember,
if m1 is vector use,
k = sum(ismember(m1,0:10));
If m1 is matrix use k = sum(sum(ismember(m1,0:10)));
for example,
m1=randi(20,[5 5])
9 10 6 10 16
8 9 14 20 6
16 13 14 7 11
16 15 4 12 14
4 16 3 5 18
sum(sum(ismember(m1,1:10)))
12
Why not simply do something like this?
% Random data
m1 = 100*rand(1000,1);
%Count elements between 10 and 20
m2 = m1(m1>10 & m1<=20);
length(m2) %number of elements of m1 between 10 and 20
You can then put things in a loop
% Random data
m1 = 100*rand(1000,1);
nb_elements = zeros(10,1);
for k=1:length(nb_elements)
temp = m1(m1>(10*k-10) & m1<=(10*k));
nb_elements(k) = length(temp);
end
Then nb_elements contains your data with nb_elements(1) for the 0-10 range, nb_elements(2) for the 10-20 range, etc...
Matlab does not know how to evaluate the combined logical expression
(0<m1(i)<=10)
Insted you should use:
for i=1:numel(m1)
if (0<m1(i)) && (m1(i)<=10)
k=k+1;
end
end
And to fasten it up probably something like this:
sum((0<m1) .* (m1<=10))
Or you can create logical arrays and then use element-wise multiplication. Don't know how fast this is though and it might use a lot of memory for large arrays.
Something like this
A(find((A>0.2 .* (A<0.8)) ==1))
Generate values
A= rand(5)
A =
0.414906 0.350930 0.057642 0.650775 0.525488
0.573207 0.763477 0.120935 0.041357 0.900946
0.333857 0.241653 0.421551 0.737704 0.162307
0.517501 0.491623 0.016663 0.016396 0.254099
0.158867 0.098630 0.198298 0.223716 0.136054
Find the intersection where the values > 0.8 and < 0.2. This will give you two logical arrays and the values where A>0.2 and A<0.8 will be =1 after element-wise multiplication.
find((A>0.2 .* (A<0.8)) ==1)
Then apply those indices to A
A(find((A>0.2 .* (A<0.8)) ==1))
ans =
0.41491
0.57321
0.33386
0.51750
0.35093
0.76348
0.24165
0.49162
0.42155
0.65077
0.73770
0.22372
0.52549
0.90095
0.25410

Building array from conditions on another array

I am new to matlab. I want to do the following:
Generate an array of a thousand replications of a random draws between three alternatives A,B and C, where at every draw, each alternative has the same probability to be picked.
So eventually I need something like P = [ A A B C B B B C A C A C C ... ] where each element in the array was chosen randomly among the three possible outcomes.
I came up with a solution which gives me exactly what I want, namely
% Generating random pick among doors 1,2,3, where 1 stands for A, 2 for B,
% 3 for B.
I = rand(1);
if I < 1/3
PP = 1;
elseif 1/3 <= I & I < 2/3
PP = 2;
else
PP = 3;
end
% Generating a thousand random picks among dors A,B,C
I = rand(999);
for i=1:999
if I(i) < 1/3
P = 1;
elseif 1/3 <= I(i) & I(i) < 2/3
P = 2;
else
P = 3;
end
PP = [PP P]
end
As I said, it works, but when I run the procedure, it takes a while for what appears to me as a simple task. At the same time, I long such a task is "supposed" to take in matlab. So I have three question:
Is this really a slow procedure to generate the desired outcome?
If it is, why is this procedure particularly slow?
What would be a more effective way to produce the desired outcome?
This can be done much easier with randi
>> PP = randi(3,1,10)
PP =
2 1 3 3 2 2 2 3 2 1
If you actually want to choose between 3 alternatives, you use the output of randi directly to index into another matrix.
>> options = [13,22,77]
options =
13 22 77
>> options(randi(3,1,10))
ans =
22 13 77 13 77 13 22 22 77 13
As to the reason why your solution is slow, you do something similar to this:
x = [];
for i=1:10
x = [x i^2]; %size of x grows on every iteration
end
This is not very good, since on every iteration, Matlab needs to allocate space for a larger vector x. In old versions of Matlab, this lead to quadratic behavior (if you double the size of the problem, it takes 4 times longer). In newer versions, Matlab is smart enough to avoid this problem. It is however still considered nice to preallocate space for your array if you know beforehand how big it will be:
x = zeros(1,10); % space for x is preallocated. can also use nan() or ones()
for i = 1:length(x)
x(i) = i^2;
end
But in many cases, it is even faster to use vectorized code that does not use any for-loops like so:
x = (1:10).^2;
All 3 solutions give the same result:
x = 1 4 9 16 25 36 49 64 81 100
cnt=10;
option={'a','b','c'}
x=option([randi(numel(option),cnt,1)])

Resources