maximum value of for loop in PL/SQL - oracle

I'd like to know, what is the maximum value in a for loop statement?
Is the datatype NUMBER?
BEGIN
-- Bounds are numeric literals:
FOR j IN 1..5000 LOOP
NULL;
END LOOP;
END;
I will need up to 3x10^14

As noted in the documentation, the lower and upper bounds of a for expression are stored in a temporary pls_integer variable. According to pls_integer's documentation, it can hold values from -2147483648 to 2147483647, represented in 32 bits.

You can give yourself some more room with regards to the upper bound on the loop iterator. For example if you have a loop like this:
declare
lower_bound number := 2147483640;
upper_bound number := 2147483650; -- <==Exceeds PLS_INTEGER max value
begin
for i in lower_bound..upper_bound
loop
... do something with i ...
end loop;
end;
that encounters an ORA-01426: numeric overflow error you can rewrite your loop like this:
declare
lower_bound number := 2147483640;
upper_bound number := 2147483650;
i number;
begin
for j in 0 .. upper_bound-lower_bound
loop
i := j + lower_bound;
... do something with i ...
end loop;
end;
In the above code, I've changed the loop iterator from i to j, changed the loop bounds to always iterate from zero to the number of iterations required, and added a new local variable i to be used by your original code. Finally adding i := j + lower_bound; as the first statement inside the loop ensures that your code sees i the way it expects.
Now as long as you aren't iterating 2,147,483,647 times you should be good.

I am not sure, why you may needed this much bigger loop.
may be you can try this
Thanks,
Thangamani Eraniyan
BEGIN
FOR j IN 3 LOOP
begin
FOR K IN 10 LOOP
begin
for L in 14 loop
Null /* you can try your code here */
End Loop;
End Loop;
END LOOP;
END;

Related

Convert Binary's 2's compliment to decimal in oracle SQL

I have a sample number in a column of oracle table which is binary's 2's complimanet -
e.g 0110001000110111
I want to convert this to normal decimal number in 2's compliment.
Expected output-
Reference link - https://www.rapidtables.com/convert/number/decimal-to-binary.html
You can loop as applying powers of 2 while multiplying by each bit(0 or 1) starting from the right end of your presented value such as
SET SERVEROUTPUT ON
DECLARE
bin_nr VARCHAR2(100) := '0110001000110';
dec_nr NUMBER;
BEGIN
FOR i IN 1..LENGTH(bin_nr)
LOOP
dec_nr := NVL(dec_nr,0) + SUBSTR(bin_nr,-i,1)*(2**(i-1));
END LOOP;
DBMS_OUTPUT.PUT_LINE(dec_nr);
END;
/
which results 3142 as the decimal value.
Demo
For 2s compliment, the most-significant bit represents the sign bit and if that is 1 then you have a negative number:
DECLARE
bin_nr VARCHAR2(100) := '1111001110111010';
sign PLS_INTEGER;
dec_nr PLS_INTEGER;
BEGIN
IF SUBSTR(bin_nr, 1, 1) = '1' THEN
bin_nr := TRANSLATE(bin_nr, '01', '10');
sign := -1;
dec_nr := 1;
ELSE
sign := 1;
dec_nr := 0;
END IF;
FOR i IN 1 .. LENGTH(bin_nr) LOOP
IF SUBSTR(bin_nr, -i, 1) = '1' THEN
dec_nr := dec_nr + POWER(2, i-1);
END IF;
END LOOP;
dec_nr := dec_nr * sign;
DBMS_OUTPUT.PUT_LINE(dec_nr);
END;
/
Outputs -3142
If you are expecting an N-bit binary number as the input (for example, the link in the question expects a 16-bit binary number as an input for 2s compliment) then you should LPAD with zeroes if you have fewer than that many bits.
db<>fiddle here

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
/

Array Tally Chart

I'm trying to create a Tally Chart based on values stored in array.
I know it is possible to do this in Python, but is there a way to do this in Pascal by keeping the amount of coding to a minimum?
var numbers:array [0..9] of integer;
Sum,aNumber, count,count2:integer;
Average:real=0;
begin
randomize;
// Put 10 Random numbers into an array
for count:= 0 to 9 do
begin
aNumber:=Random(10)+1;
numbers[count]:=aNumber
end;
// Show a Tally
begin
for count:= 0 to 9 do
writeln(numbers[count] * '£');
writeln;
end;
readln;
end.
I simply want to present the outcome of the array by showing all possible values. E.g. If my array had the following random values between 1 and 10: 3,3,8,8,9 it should show:
1-
2-
3- II
4-
..
8- II
9- I
10-
Thanks.
The obvious way would be another for loop:
for count := 0 to 9 do
begin
for i := 1 to numbers[count] do
write('£');
writeln;
end
If you can settle for just one character at the right position, you could use something like:
for count := 0 to 9 do
writeln('£' : numbers[count]);
Think it works now... i created a Function to return the number of instances in each element. That result helps me to know the no. of iterations for each number.
Function TallyCount(x:integer):integer;
var i,TotalCount:integer;
begin
i:=0;
TotalCount:=0;
for i := 0 to 9 do
begin
if numbers[i] = x then
TotalCount:=TotalCount +1;
end;
result:=Totalcount;
end;

factorial of a number in pl/sql

The following pl/sql program generates an error on execution on line the sum :=temp*sum; encountered symbol ; when expecting ( . Please explain my mistake.
declare
n number;
temp number;
sum number := 1;
begin
n := &n;
temp := n;
while temp>0 loop
sum := temp*sum;
temp := temp-1;
end loop;
dbms_output.put_line('Factorial of '||n||' is '||sum);
end;
/
Maybe not the answer to your question, but there is no need for PL/SQL here:
select round(exp(sum(ln(level))))
from dual
connect by level <= 5;
where 5 is your number (5!).
Additionally, if you like to operate faster in PL/SQL use pls_integer instead of number.
UPDATE
So according to comments I felt free to test:
create or replace package test_ is
function by_query(num number) return number deterministic;
function by_plsql(num number) return number deterministic;
end test_;
/
create or replace package body test_ is
function by_query(num number) return number deterministic
is
res number;
begin
select round(exp(sum(ln(level))))
into res
from dual
connect by level <= num;
return res;
end;
function by_plsql(num number) return number deterministic
is
n number := 0;
begin
for i in 1..num loop
n := n + ln(i);
end loop;
return round(exp(n));
end;
end test_;
So there are two functions with different content. Test query:
declare
dummy number;
begin
for i in 1..10000 loop
dummy := test_.by_query(5);
end loop;
end;
0.094 sec.
declare
dummy number;
begin
for i in 1..10000 loop
dummy := test_.by_plsql(5);
end loop;
end;
0.094 sec.
You'll say I am cheater and using deterministic keyword but here it is obvious and is needed by logic. If I remove it, the same scripts are working 1.7 sec vs 1.3 sec, so procedure is only a bit faster, there is no even double-win in performance. The totally opposite effect you will get if you use the function in a query so it is a fair trade.
Sum is reserved word in sql. Change variable name like
declare
n number;
temp number;
sum_ number := 1;
begin
n := &n;
temp := n;
while temp>0 loop
sum_ := temp*sum_;
temp := temp-1;
end loop;
dbms_output.put_line('Factorial of '||n||' is '||sum_);
end;
/
declare
n number;
i number;
sum_of_log_10s number;
exponent number;
base number;
begin
n := &n;
i := 1;
sum_of_log_10s := 0;
while i <= n loop
-- do stuff
sum_of_log_10s := sum_of_log_10s + log(10,i);
i := i + 1;
end loop;
dbms_output.put_line('sum of logs = '||sum_of_log_10s);
exponent := floor(sum_of_log_10s);
base := power(10,sum_of_log_10s - exponent);
dbms_output.put_line(n||'! = '||base||' x 10^'||exponent);
end;
I came up with this code that I like even better than #smnbbrv's answer. It's a great way to check the speed of a machine. I've been using a variation of this since my Atari 800
ALTER SESSION FORCE PARALLEL DDL PARALLEL 16;
ALTER SESSION FORCE PARALLEL DML PARALLEL 16;
ALTER SESSION FORCE PARALLEL QUERY PARALLEL 16;
with t as (
select /*+materialize*/
rownum i
from dual connect by rownum < 100000 -- put number to calculate n! here
)
,t1 as (
select /*+parallel(t,16)*/ /*+materialize*/
sum(log(10,i)) logsum
from t
)
select
trunc(power(10,(mod(logsum,1))),3) ||' x 10^'||trim(to_char(floor(logsum),'999,999,999,999')) factorial
-- logsum
from t1
;
-- returns 2.824 x 10^456,568
Here is the simple code for finding factorial of number at run time...
declare
-- it gives the final answer after computation
fac number :=1;
-- given number n
-- taking input from user
n number := &1;
-- start block
begin
-- start while loop
while n > 0 loop
-- multiple with n and decrease n's value
fac:=n*fac;
--dbms_output.put(n||'*');
n:=n-1;
end loop;
-- end loop
-- print result of fac
dbms_output.put_line(fac);
-- end the begin block
end;

vhdl "for loop" with step size not equal to 1

I have a simple question . Is it possible to write a VHDL for loop with step size not equal to 1 e.g 16
The loop should go like
0--> 16 --> 32--> 48.... to some value
any immediate help is appreciated
A possible solution is to use a range that is 1/16th of the desired range and unroll the loop inside it to generate the desired range:
for i in 0 to 3 -- Actually 0 to 48
loop
x(16*i) <= ...
x((16*i)+1) <= ...
(...)
x((16*i)+15) <= ...
end loop;
Another solution would be to use a while instead. Assuming your count variable is an integer:
while (i < 48)
loop
--Do something
i := count + 16;
end loop;
Edit: I haven't tested the code above, you might be unable to change the variable count inside the loop, I'm not sure. Maybe the first solution is the best one.
It is not possible to have a for loop with a step different then 1. You are not even allowed to change it inside the for, like this:
--THIS WILL NOT WORK
for i in 0 to 48 loop
--Do Something
i := i + 15; -- This will NOT increment the loop index by 16
end loop;
And finally, for steps of 2 or 3 you might use nested for's.
But anyway, What are you trying to accomplish? VHDL is a low-level hardware description language, you should be able to achieve whatever you are trying to without fancy for loops.
VHDL has no step parameter in for loop, so the step is always 1 for to
range direction and -1 for downto range direction.
So if you need loop with start and step value, you can do:
...
constant FOR_START : natural := 1;
constant FOR_STEP : natural := 2;
variable idx_v : natural; -- Support index variable
...
for idx_pre in 0 to 3 loop
idx_v := FOR_START + FOR_STEP * idx_pre;
z_o(idx_v) <= a_i(idx_v);
end loop;
A while loop can also be used as alternative:
constant FOR_START : natural := 1;
constant FOR_STEP : natural := 2;
constant FOR_MAX : natural := 7;
variable idx_v : natural;
...
idx_v := FOR_START;
while idx_v <= FOR_MAX loop
z_o(idx_v) <= a_i(idx_v);
idx_v := idx_v + FOR_STEP;
end loop;
How about looping over the entire range, but then using an 'if' statement to only act on every 16th value?
for i in start_thing to end_thing loop
if i mod 16 = 0 then
do things(i)
end if;
end loop; -- i
Or alternately use Next:
for i in start_thing to end_thing loop
next when i mod 16 /= 0 ;
do_things(i)
end loop; -- i
My research says no, but you can declare a second variable that acts as a multiple of your variable inside of your loop.
Yes, it is possible to "for loop" with a step size not equal to 1.
for i in range 1 downto 0 loop
foo(i) <= bar(1-i);
end
loop;

Resources