SystemVerilog equivalent of C while loop - system-verilog

I am attempting to write a synthesizable systemverilog construct similar to the C code below. From a given range (0 to 9), a number is provided. The goal is then to randomly select another number from the range that does not match the number that has already been provided. I am using an 8-bit Galois LFSR PRNG for the randomness. I just don't know how then to select the alternate number without a while loop to correct a duplicate choice. Any suggestions?
Lets say the number already provided is 5:
const int RANGE = 10;
int given_no = 5;
int other_no = rand() % RANGE;
while(other_no == given_no) {
other_no = rand() % RANGE;
}
For those who do not code in C, rand() simply returns a random integer between 0 and a value called RAND_MAX (lets assume RAND_MAX = 0xFFFF). % RANGE simply determines the remainder from division by RANGE. Hence the line rand() % RANGE is simply generating a random integer from 0 to 9.
Output:
Assuming the first call of rand() % RANGE before the while loop generates a value other than 5 (for example 4), the while loop never runs. The variable would be:
given_no = 5
other_no = 4
If on the first call rand() % RANGE returns 5, the while loop will run and generate a second random number between 0-9. This will continue until the random number generated is not 5. Like so . .
given_no = 5
other_no = 5
other_no = 5
other_no = 4
An SV module to do this would look something like this ->
// 8-bit LFSR Pseudo-Random Number Generator
'include "lfsr8.sv"
module second_choice (
// A random number between 0 - 9 that is not the same as fst_val
output logic [3:0] snd_val,
// Pre-given number between 0 - 9
input logic [3:0] fst_val,
// Possible system-wide signals
input logic clk, enable_lfsr, enable_snd_choice
);
// Random 8-bit value from lfsr
logic [7:0] rand_out
lfsr8 lfsr8_inst(.rand_out(rand_out), .enable_lfsr(enable_lfsr), .clk(clk));
always_ff#(posedge clk)
begin
if(enable_snd_choice)
begin
{{System verilog code to determine snd_val}}
snd_val <= {{random value between 0 - 9 that != fst_val}}
end
end
endmodule
I know enough about systemverilog to know that loops are only synthesizable if the number of iterations is known at compile time. In this instance, the number of iterations is not known. I am therefore looking for an alternative way to do this.

As you have guessed, you simply cannot do this in a single clock cycle (or an unbounded while loop).
To achieve something like this, you will have to check on each clock cycle whether the random number is equal to the given number. If that is the case, set the snd_val_valid-output to low (see below).
Otherwise, write the unequal random number into the snd_val output of the module and also set an additional snd_val_valid-output to high, so that the "downstream" modules have a way of determining whether your calculation has already finished or not.
Also, you might want to think about implementing a small state machine, so that you are more flexible about accepting new inputs, stopping after the first unequal number, etc.

Related

I wrote the following code in matlab to randomize and after that round numbers 3 to 8 in 3x4 matrix but i want to not be repeated numbers in rows

i wrote this code for randomize and round numbers
x=3+5*rand(3,4);
for n=1:3
for m=1:4
y(n,m)=round(x(n,m));
end
end
y
Using the randperm() function may be an option. The first argument of randperm() sets the range. In this case randperm(6,4) will generate 4 numbers that are within the range 1 to 6 (a random permuatation of integers in this case permutations of 6). If we add 2 to this result we can generate an array of length 4 that will have values ranging from 3 to 8. Here we can use one for-loop and generate the rows upon each iteration.
Array = zeros(3,4);
for Row = 1: 3
Array(Row,:) = randperm(6,4) + 2;
end
Array
First of all the rand() function returns numbers between 0 and 1, so it probably doesn't make sense to use this function and then round the numbers off. If you're looking for random integers use randi() instead.
With this in mind, the following code produces a 3 by 4 matrix filled with random integers and no repeats:
maxInteger = 12; %change to any number greater than 3x4 = 12
y = randi(maxInteger, 3, 4);
used = [];
for i = 1:numel(y)
while sum(find(used == y(i)))>0
y(i) = randi(maxInteger);
end
used = [used, y(i)];
end
If the while loop takes too long (as might happen with large matrices) consider filling a matrix by pulling and removing elements from a predecided list of integers.

Function output contradicts function constraints

I wrote a function that takes as an imput a natural number 'n', and outputs a random walk, starting at 0, where each subsequent entry in the vector is obtained by adding or subtracting 1 to the previous entry. The random walk has to stop whenever it reaches n or -n.
The code is the following
function [N] = rand_walk2(n)
j=0; %J will be the outpur of the function
v=0; %Defines variable v.
i=2; %The following 'while' loop will start from the second entry of the vector.
while abs(j(i-1)) < n %This 'while' loop will continue running only if the previous entry is strictly between -n and n.
if rand >= 0.5 %This 'if' statement returns 1 or -1 with equal probability (it uses the uniform distribution with parameters [0,1]).
v = 1;
else v = -1;
end
j(i)=j(i-1)+v;
j = [j,j(i)];
i=i+1;
end
N = j;
end
The problem is that the output returns n or -n twice instead of only once, for example, if I evaluate rand_walk2(3) I get 0 -1 -2 -3 -3 instead of just o -1 -2 -3. Does anyone have any suggestions as to what I can change to fix this?
Line 10 pushes the current position into vector j
j(i)=j(i-1)+v;
and then line 11 concatenates that same value on to the end of the array
j = [j,j(i)];
Simply remove line 11.
As a usual side note, the symbols i and j are often used to produce imaginary numbers and often mistakenly as indexing variables. It is recommended by Mathworks:
Since i is a function, it can be overridden and used as a variable. However, it is best to avoid using i and j for variable names if you intend to use them in complex arithmetic.
In this case, it is not necessary, but I like to promote good programming practices when I can (also, I needed to force my brain to think through your code because of this practice).

Random number generation - code not working as it should

So I have to generate a random number (called 'p' here) between 0 and 90 whose frequency distribution is a cosine function (i.e I should have more numbers between 0 and 45 than numbers between 45 and 90).
I am working on matlab
The code is as follows -
flag = 1;
while flag == 1
candidate = randi([0,90]);
if rand < cosd( candidate )
p = candidate;
flag = 2;
end
end
I am generating 20 such numbers but always I get most of the numbers towards the higher end (45-90).
From those 20 numbers, there is hardly 1-2 numbers < 45.
Is my code wrong?
EDIT: Okay, so I got the answer. I tried running the code separately as follows-
for i = 1:20
flag = 1;
while flag == 1
candidate = randi([0,90]);
if rand < cosd( candidate )
p = candidate;
flag = 2;
disp(p);
end
end
end
And I'm getting most of the values of p between 0 and 45. My original code had an external 'if' condition which was the reason for only accepting higher values of 'p'. I used a while loop and the number of iterations were much more than 20 to get 20 values of 'p'.
Here is my original code snippet -
while zz <=20
d = randi([0,359]);
flag = 1;
while flag == 1
c = randi([0,90]);
x = rand(1);
if x < cosd(c)
p = c;
flag = 2;
end
end
if 'external condition'
strike(zz) = d;
dip(zz) = p;
slip(zz) = round(i);
zz= zz+1;
end
end
If you just want to get answer, read the last line. But if you want to know that why that answer is right, read the explanation.
Assume that you have a distinct distribution function like this:
f(0)=1;
f(1.5)=10;
f(4)=9;
So the cumulative function is:
F(0)=1;
F(1.5)=11;
F(4)=20;
No we want to have a relative cumulative function, as F(4)=20 (4 is the last item), we divide cumulative function by 20. So it would be:
F'(0)=0.05
F'(1.5)=0.55
F'(4)=1.00
Now, we generate a random number between 0 and 1. Every time we generate a random number, we generate a value for F'(x) and if F'(x) does not have that value anywhere, we use nearest bigger number (like y) which for some x, F(x)=y. For my example, based on relative cumulative function:
If the random number was less than 0.05, our distribution-based random number is 1.5
If the random number was between 0.05 and 0.55, our distribution-based random number is 2,
If was more than 0.55, our distribution-based random number is 4
We should do a similar work with continuous distribution functions. The difference is that in continuous world, we use integral instead of cumulative function. So for your question, we have:
f(x)=cos(x) , 0<=x<=90
F(x)=sin(x)-sin(0)=sin(x) , 0<=x<=90
F'(x)=cos(x) , 0<=x<=90 (Because F(90)=1)
Now we generate a random number between 0 and 1 (like r). So we have:
F'(x)=r => sin(x)=r => x=arcsin(r)
Actually, you just need to generate a random number between 0 and 1 and calculate the arcsin of that.

recursive function matlab decimal to binary conversion

I have a function that converts a decimal number to binary but i need to make the function recursive. I don't know how to make this function call itself. Any help will be very appreciated.
This is my function :
function bin = myBinary (dec_nr)
i = 1;
q = floor(dec_nr/2); %this is the quotient, the "floor" function is used to round down
r = rem(dec_nr, 2); % the "rem" function is used to get the remainder which will become the first binary value
bin(i) = num2str(r(i)); % the remainder is converted and stored as a string
while 2 <= q
dec_nr = q;
i = i + 1;
q = floor(dec_nr/2);
r = rem(dec_nr, 2);
bin(i) = num2str(r);
end
bin(i + 1) = num2str(q);
bin = fliplr(bin);
save myBinary
Thank you in advance!
That's pretty simple to do. I would implement this using something called tail recursion. Remember the algorithm for converting a decimal number (assuming unsigned) into binary.
Declare a number you want to convert.
Initially declare an output to be empty.
Until the number is 0...
a. Take the number and divide this by 2
b. If there is a remainder, then attach a bit of 1 from the left, so output <- [1 output]. Else, attach a 0, so output <- [0 output].
output will contain the binary representation of your number.
With recursion, there are two cases you must consider: The base case, where the algorithm stops and gives you a known output, and a recursive case that tells you that you need to keep going, and you call the function again with modified inputs.
As such, you can very easily achieve what you want above by tail recursion by providing a helper function that takes in the input number at a given state (basically the number after being divided by 2 for a number of times) and a binary string that gives you the current state of binary string construction as you're going through and determining each bit.
You would repeatedly call this function and taking the input number and dividing it by 2 until you get a result of 0. You would start by calling the function with the original input number, and an empty string. Make sure that when you send the input number back into the function for the recursive case, you need to truncate any decimal values that result, so you would take the floor.
Therefore, a possible function is very simply:
function bin = bin2dec_recursive(in)
%// Recursive helper
function [out] = recursive_helper(in_number, binstr)
%// Base case
if in_number == 0
out = binstr; %// Just return the current binary string
%// Recursive case
else
%// Recurse - Integer divide input number and concatenate string
out = recursive_helper(floor(in_number/2), [num2str(mod(in_number,2)) binstr]);
end
end
%// call recursive helper
bin = recursive_helper(in, '');
end
What's key is this statement right here:
out = recursive_helper(floor(in_number/2), [num2str(mod(in_number,2)) binstr]);
When we hit the recursive case, we need to call the function again by dividing the input number by 2 and the input binary string is the current string, but we add either a 0 or 1 to the left of the string. We convert the number to a string by num2str.
If you desire to have a double array of single digits, simply remove the num2str call inside the recursive case, and replace '' with [] when you're calling the recursive helper function for the first time at the last line of code above.
With this, here are some examples of it working:
>> bin2dec_recursive(3)
ans =
11
>> bin2dec_recursive(5)
ans =
101
>> bin2dec_recursive(9)
ans =
1001
>> bin2dec_recursive(127)
ans =
1111111
>> bin2dec_recursive(200)
ans =
11001000
Minor Note
Be advised that the recursion limit for MATLAB is 500 calls. Therefore, with recursion, you can only compute binary numbers that are up to a maximum of 500 bits, so this means that the maximum decimal number you can put into the above function is approximately 2500 - 1. Anything more will give you an error saying that MATLAB has reached its recursion limit.

Calculating the product of all the odd numbers

So I am trying to create a script that calculates the product of all the odd numbers from 1 to 1000 (using MATLAB). The program runs but the product is not correct:
%Program is meant to calculate the product of all the odd numbers from 1 to 1000
% declare variable ‘product’ as zero
product = 0.;
% initialize counter, ‘n’, to 1000
n = 1000;
for i = 1:2:n
product = product + i;
end
fprintf('The product of all the odd numbers from 1 to %d is %d\n', n, product)
So I'm not really sure how to go about this and am looking for some guidance. Thanks!
Solution
Currently, your script is set to add all of the odd numbers from 1 to 1000.
To perform the product, you just need to change the starting value of product to 1 and multiply within the loop:
product = 1;
for i = 1:2:1000
product = product * i;
end
However, it is faster to create a vector and have the built-in prod function perform the multiplication:
product = prod(1:2:1000);
Problem
MATLAB does not by default have enough memory in the default 64-bit numbers to compute the exact value of this product.
The number is too large since this is essentially a factorial.
You'll find that MATLAB returns Inf for the 500 numbers you're multiplying, and it is only finite for up to 150 elements.
In fact, using floating point arithmetic, the number is only accurate up to 15 digits for the first 17 digits using floats (integers saturate at that level as well).
Using Mathematica (which can perform arbitrary digit arithmetic out-of-the-box since I'm feeling lazy), I can see that the answer needs at least 1300 digits of precision, which we can have MATLAB do through the Symbolic Toolbox's vpa function:
digits(1300);
p = vpa(1);
pint = vpa(1);
for k = 2:N
pint = pint*p(k);
end
disp(pint);
>> StackOverflow
100748329763750854004038917392303538250323418583550415705013777513334847930864905026212149922688916514224446856302103818809813965739969905602683824057028542369814437703275217182106137628427025253936696857063927677887236450311036887007989218384076420973974651860279864376153012567675767840733574225799002463604490891982796305162134708837541147007332276627034016790073315219533088052639255340728943149219519187498959529434982654113006616219355830114439411562650611374970334868978510289340267833632215930432706056111069583472778227977585526504938921664232801595705593340414168289146933191250605578218896799783237156997993612173843567447982392426109444012350386990916069363415575527636429080027392875413821124412782341957015410685185402984322002697631153866494712956244870206835064084512590679022924697003630949759950902438767963278695296882620493296103779237046934780464541286585179975172680371269700518965123152181467825566303777704391998857792627009043170482928030252033752456172692668989206857862233381387134495504231267039972111966329704875185659372569246229419619030694680808504265784672316785572965414328005856656944666840982779185954031239345256896720409853053597049715408663604581472840976596002762935980048845023622727663267632821809277089697420848324327380396425724029541015625.0