PLSQL - How does this Prime number code work? - oracle

DECLARE
i number(3);
j number(3);
BEGIN
i := 2;
LOOP
j:= 2;
LOOP
exit WHEN ((mod(i, j) = 0) or (j = i));
j := j +1;
END LOOP;
IF (j = i ) THEN
dbms_output.put_line(i || ' is prime');
END IF;
i := i + 1;
exit WHEN i = 50;
END LOOP;
END;
The code works properly. I tried to figure out how it works and ended up having 4 as a prime number, which isn't. If you could help me understand how this nested loop works, I'd be very thankful.
Thank you.

The code is looking for all the prime numbers up to 50. The outer loop is just checking each value of i from 2 to 50 to see if that integer is prime.
For each value of i, it tries to divide that integer by every other integer one by one, starting from 2. If i is divisible by j with no remainder (mod is zero) then it is not prime; unless it is only divisible by itself (j=1).
It exits that inner loop as soon as it finds a value of j which divides into i, or it reaches i itself.
It then needs a further check to see which of those conditions actually caused it to exit; and thus whether or not it is actually prime.
You could do the same thing with slightly clearer (IMHO) logic:
BEGIN
<<OUTER>>
FOR i IN 2..50 LOOP
FOR j IN 2..i-1 LOOP
IF (mod(i, j) = 0) THEN
CONTINUE OUTER;
END IF;
END LOOP;
dbms_output.put_line(i || ' is prime');
END LOOP;
END;
/

Lets rewrite it so its a bit simpler:
BEGIN
<<outer_loop>>
FOR value IN 2 .. 50 LOOP
FOR divisor IN 2 .. value - 1 LOOP
CONTINUE outer_loop WHEN MOD( value, divisor ) = 0;
END LOOP;
DBMS_OUTPUT.PUT_LINE( value || ' is prime' );
END LOOP;
END;
/
All it is doing is, in the outer loop going through the number 2 .. 50 and in the inner loop is checking whether there is a number that divides exactly into that value; if there is then continue the outer loop and if there is not then output that the number is prime.
Your code is effectively the same code but it is complicated by not using FOR .. IN .. loops

If I understand your question.
When i = 4 and j = 2 then condition ((mod(i, j) = 0) or (j = i)) leads to the exit from inner loop, but condition (j = i ) is false and program doesn't go to line dbms_output.put_line(i || ' is prime');

Related

For oracle function to know if data is prime or not. Getting Warning: Function created with compilation errors

Wanted to create a function that can return records containing the number data type which are prime number
But getting warning of compilation error. What is the mistake in the code.I am a beginner in pl/sql.
CREATE OR REPLACE FUNCTION isPrime (num number)
RETURN number
IS
retVal number;
BEGIN
DECLARE
prime_or_notPrime number;
counter number;
retVal:= 1;
prime_or_notPrime:= 1
counter:= 2
WHILE (counter <= num/2) LOOP
IF (mod(num ,counter)= 0) THEN
prime_or_notPrime: = 0
EXIT;
END IF;
IF (prime_or_notPrime = 1 ) THEN
retVal: = 1;
counter: = counter + 1
END IF;
END LOOP;
return retVal;
END;
/
What is the mistake in the code
The DECLARE is invalid syntax for a function/procedure. You want to declare the variables between the IS and BEGIN keywords.
Then you are missing a ; statement terminator after prime_or_notPrime:= 1 and counter:= 2.
Then you have:
prime_or_notPrime: = 0 instead of prime_or_notPrime := 0;
retVal: = 1; instead of retVal := 1; and
counter: = counter + 1 instead of counter := counter + 1; (they all have a space between : and = and some are missing ; again).
You never set retVal to anything other than 1.
You do not handle NULL values or values lower than 2.
Fixing that (and the indentation) gives:
CREATE OR REPLACE FUNCTION isPrime (num number)
RETURN number
IS
retVal number;
prime_or_notPrime number;
counter number;
BEGIN
IF NUM IS NULL OR NUM < 2 THEN
RETURN 0;
END IF;
retVal:= 1;
prime_or_notPrime:= 1;
counter:= 2;
WHILE (counter <= num/2) LOOP
IF (mod(num ,counter)= 0) THEN
prime_or_notPrime := 0;
retVal := 0;
EXIT;
END IF;
IF (prime_or_notPrime = 1 ) THEN
counter := counter + 1;
END IF;
END LOOP;
return retVal;
END;
/
Note: the prime_or_notprime variable is not controlling anything as, as soon as you set it to 0 you EXIT from the loop so it will never be used again. Having noted that, you can get rid of the final IF statement and just always increment the counter.
You can simplify it to:
CREATE OR REPLACE FUNCTION isPrime (
num number
) RETURN number DETERMINISTIC
IS
BEGIN
IF NUM IS NULL OR NUM < 2 THEN
RETURN 0;
END IF;
FOR counter IN 2 .. SQRT(num) LOOP
IF MOD(num, counter) = 0 THEN
RETURN 0;
END IF;
END LOOP;
RETURN 1;
END;
/
You can then consider improvements. Such as starting by checking 2 as a special case and then skipping all the other even numbers.
db<>fiddle here

PL/SQL program to show the uses of nested loop. It seems ok, but its showing error"Encountered the symbol ">" when expecting one of the following:"

DECLARE
m PLS_INTEGER := 0; n PLS_INTEGER := 0; k PLS_INTEGER;
BEGIN
<>
LOOP
n := n + 1; k := 0;
DBMS_OUTPUT.PUT_LINE ('The values of inner loop are: ');
<>
LOOP
k := k + 1;
m := m + n * k; -- Sum several products
EXIT inner_loop WHEN (k > 3);
DBMS_OUTPUT.PUT_LINE ('n='||TO_CHAR(n)||' k='||TO_CHAR(k)||' m='||TO_CHAR(m));
EXIT outer_loop WHEN ((n * k) > 6); END LOOP inner_loop;
END LOOP outer_loop;
DBMS_OUTPUT.PUT_LINE
('The total sum after completing the process is: ' || TO_CHAR(m));
END;
/
You wrongly labelled loops. Instead of just <> (which just means that something's different from something else), you should have used e.g. <<outer_loop>>. When fixed, your code looks like this:
SQL> set serveroutput on;
SQL> DECLARE
2 m PLS_INTEGER := 0;
3 n PLS_INTEGER := 0;
4 k PLS_INTEGER;
5 BEGIN
6 <<outer_loop>>
7 LOOP
8 n := n + 1; k := 0;
9 DBMS_OUTPUT.PUT_LINE ('The values of inner loop are: ');
10
11 <<inner_loop>>
12 LOOP
13 k := k + 1;
14 m := m + n * k; -- Sum several products
15
16 EXIT inner_loop WHEN (k > 3);
17 DBMS_OUTPUT.PUT_LINE ('n='||TO_CHAR(n)||' k='||TO_CHAR(k)||' m='||TO_CHAR(m));
18 EXIT outer_loop WHEN ((n * k) > 6);
19 END LOOP inner_loop;
20 END LOOP outer_loop;
21
22 DBMS_OUTPUT.PUT_LINE('The total sum after completing the process is: ' || TO_CHAR(m));
23 END;
24 /
The values of inner loop are:
n=1 k=1 m=1
n=1 k=2 m=3
n=1 k=3 m=6
The values of inner loop are:
n=2 k=1 m=12
n=2 k=2 m=16
n=2 k=3 m=22
The values of inner loop are:
n=3 k=1 m=33
n=3 k=2 m=39
n=3 k=3 m=48
The total sum after completing the process is: 48
PL/SQL procedure successfully completed.
SQL>

In Verilog, when using a for-loop within a sequential process, how can you increment the sequential variable?

Here is a snippet of code, hopefully you are alright without the preamble:
always # (posedge clk)
begin
if(rst)
begin
i<=0;
j<=0;
end
else
begin
for(j = 0 ; j < 16 ; j = j+1)
begin
if(i<8)
begin
var[j] <= var_2[i];
i <= i+1;
end
end
end
end
Basically, I am wondering if the outer "for-loop" will erroneously increment the counter variable i, rather than simply calculating the 16 vars in parallel. If this is the case, should I cut the for-loop short so that the variable is incremented outside the for-loop?
Thanks!
You are making the code unnecessary complex.
If i<8 then these get executed:
var[j] <= var_2[i];
i <= i+1;
But the i is not incremented until after the clock edge.
As 'i' does not change the condition does not change and thus once true it stays true for all values of j.
Probably a better way of understanding this is to write the code as follows which has the exact same behavior:
always # (posedge clk)
begin
if(rst)
begin
i<=0;
j<=0;
end
else
begin
for (j = 0 ; j < 16 ; j = j+1)
begin
if(i<8)
var[j] <= var_2[i];
end
// i increment independent from the 'j' loop
if(i<8)
i <= i+1;
end
end

PL SQL - Lazy Caterer's Sequence

I need to write a PL/SQL program to print out the first 10 numbers of Lazy Caterer's sequence. I'm having trouble. I don't understand how to do this
Lazy caterer's sequence has the formula F(1)=2, F(n)=F(n-1)+n.
E.g., F(2) = F(1) + 2 = 2+2=4; F(3) = F(2)+3 = 4+3=7
Please use a loop. The numbers you print out should look like
2
4
7
...
56
DECLARE
n NUMBER := 1;
BEGIN
FOR i IN 1..10 LOOP
n := n + i;
DBMS_OUTPUT.PUT_LINE(n);
END LOOP;
END;
/
I cheated and looked up Lazy Caterer's algorithm on Wikipedia. This is an implementation of the simplistic version of the formula:
create or replace function lc_algo
(n in number)
return number as
begin
return (power(n,2) + n + 2) / 2;
end;
/
I admit it doesn't use a loop, but it's hard to see why anybody would need to. However, if your assignment insists on loops (because performance is not your bag) here you go:
create or replace function lc_algo
(n in number)
return number
as
rv simple_integer := 1;
begin
for i in 1..n loop
rv := rv + i;
end loop;
return rv;
end;
/
To get the first ten numbers (with whatever version):
select lc_algo(level) -- assuming you don't want to start with f(0)
from dual
connect by level <= 10
/

For loop and its reverse based on if-condition/ternary operation in Oracle

In Oracle, I have the following almost identical SQL in an if-else block of a stored procedure:
if v_endsid = '15' then
FOR i IN 1..v_num LOOP --loop around the number from the beginning
v_item := TRIM(SUBSTR(v_str, (i - 1) * 12 + 1, 12)); --now this is the evaluated item
if v_item = TRIM(cursorElement.ITEM) then --this is the time to break
break;
end if;
END LOOP;
else
FOR i IN REVERSE 1..v_num LOOP --loop around the number from the last
v_item := TRIM(SUBSTR(v_str, (i - 1) * 12 + 1, 12)); --now this is the evaluated item
if v_item = TRIM(cursorElement.ITEM) then --this is the time to break
break;
end if;
END LOOP;
end if;
As you can see, the only difference between the SQL in the if and else blocks is the FOR loop. One is a forward for loop, another is a reversed (backward) for loop.
Is there any way to combine the block? I am trying this:
FOR i IN (case when v_endsid = '15' then 1..v_num else REVERSE 1..v_num end) LOOP
v_item := TRIM(SUBSTR(v_str, (i - 1) * 12 + 1, 12)); --now this is the evaluated item
if v_item = TRIM(cursorElement.ITEM) then --this is the time to break
break;
end if;
END LOOP;
But it gives me compilation error in the 1..v_num:
Found: '..' Expecting: END -or- ELSE -or- WHEN -or- OR -or- AND -or-
BETWEEN IN LIKE LIKE2 LIKE4 LIKEC MEMBER SUBMULTISET -or- ! != < <= <>
= > >= ^ ^= IS NOT ~
There is no way of dynamically changing the direction of the for loop. The only thing you can do here if you want to combine the two blocks is to use a basic loop
if v_endsid = '15' then
i := 1;
reverse := false;
else
i := v_num;
reverse := true;
end if;
LOOP --loop around the number from the beginning
v_item := TRIM(SUBSTR(v_str, (v_num - 1) * 12 + 1, 12)); --now this is the evaluated item
if v_item = TRIM(cursorElement.ITEM) then --this is the time to break
break;
end if;
if reverse = true then
if i = 1 then
exit;
else
i := i - 1;
else
if i = v_num then
exit;
else
i := i + 1;
end if;
end if;
END LOOP;
The final solution I adapt is by using basic LOOP and some ternary operations:
i := case when v_endsid = '15' then 1 else v_num end; --evaluates from front or back depending on the case
Loop
v_item := TRIM(SUBSTR(v_str, (i - 1) * 12 + 1, 12)); --now this is the evaluated item
--other queries
i := i + (case when v_endsid = '15' then 1 else -1 end);
exit when i = 0 or i = v_num + 1; --exceeds the elements
end loop;
This, I think, is a fairly neat working replacement for the original SQL
How about the another way round ? Instead of manipulating the loop condition encapsulate the code evaluating the break condition into a function that can be called from the different loops.
declare
v_reverse constant boolean := true;
-- your parameters and break rule can be arbitrary complex, mine is simple
-- as this is just a demonstration
function break(i in pls_integer) return boolean is
begin
return 13 = i;
end;
begin
if v_reverse
then
for i in reverse 1 .. 15
loop
dbms_output.put_line(i);
exit when break(i);
end loop;
else
for i in 1 .. 15
loop
dbms_output.put_line(i);
exit when break(i);
end loop;
end if;
end;
/

Resources