PL SQL - Lazy Caterer's Sequence - oracle

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
/

Related

Pascal - Sum of odd numbers between 0 and X

I've beeng having some trouble with this code... I need to create an algorithm which makes the user input a number (X), and then the program calculates the sum of all the odd numbers below (x).
This what I've tried so far, but can't really wrap my head around the logic behind it:
Program odd_numbers;
Var
Num, Limite, Soma: integer;
Begin;
Soma := 0;
Writeln('Choose a limit:');
Readln(Limite);
While (Limite / 2 > 0) do
Begin;
Soma := ((Num < Limite) mod 2 > 0);
Writeln('The sum of odd numbers from 0 to ', Limite, ' é ', Soma);
End;
if (Limite mod 2 = 0) then
Begin;
Soma := ((Num < Limite) mod 2 = 0);
Writeln('The sum of odd numbers from 0 to ', Limite, ' é ', Soma);
End;
End.
*PS: Been writing the code with variables in Portuguese, so don't mind the variables appearing weird to understand. *
I see that everyone is happily looping, but this is not necessary. This is a simple arithmetic sequence, and the sum can be calculated without a loop.
Just think of the following:
1 + 3 = 2 * (1 + 3) / 2 = 2 * 2 = 4 ; limits 3 and 4
1 + 3 + 5 = 3 * (1 + 5) / 2 = 3 * 3 = 9 ; limits 5 and 6
1 + 3 + 5 + 7 = 4 * (1 + 7) / 2 = 4 * 4 = 16 ; limits 7 and 8
1 + 3 + 5 + 7 + 9 = 5 * (1 + 9) / 2 = 5 * 5 = 25 ; limits 9 and 10
1 + 3 + 5 + 7 + 9 + 11 = 6 * (1 + 11) / 2 = 6 * 6 = 36 ; limits 11 and 12
But not only that, you'll see that it is in fact always a perfect square: Sqr((n+1) div 2).
So just calculate:
program odd_numbers;
var
Num, Limite, Soma: Integer;
begin
Write('Choose a limit: ');
Readln(Limite);
Num := (Limite + 1) div 2;
Soma := Num * Num;
Writeln('The sum of odd numbers from 0 to ', Limite, ' is ', Soma);
end.
Looks a little simpler than what the others propose.
The loop While (Limite / 2 > 0) do ... uses real arithmetic and not integer arithmetic. I guess you mean While (Limite div 2 > 0) do ... And you should change Limite in the loop otherwise you get stuck because the exit condition can never be reached.
After you have asked the user to enter a number, Limite, you need to keep that unchanged, because you need it in the final message. You also need a loop where you go through all numbers from Limite towards 0.
You started with a while loop which is ok, you are just missing the loop control variable. That is a variable that eventually gets a terminating value which then stops the loop. Use for example the Num variable you already have declared. You can use the same variable to investigate the numbers between user input and 0, for being odd values.
num := limite-1; // give num a start value based on user input (-1 because of "... numbers below (x)")
while num > 0 do // stop the loop when 0 is reached
begin
// here you investigate if `num` is a odd number (e.g. using `mod` operator or
// possibly your pascal has a built in `function Odd(value: integer): boolean;`)
// and add it to `Soma` if it is
num := num - 1;// decrement num at every iteration
end;
Finally you need to consider changes to the above, to handle negative input from the user.
To test if an integer is an odd value, you could use following function:
function IsOdd( value : Integer) : Boolean;
begin
IsOdd := (value mod 2) <> 0;
end;
Many pascal compilers have a built-in function called Odd(), which you could use.
A while loop works well to solve this problem. If you start with lowest odd number above zero, i.e. one and continue upwards so long we do not exceed the limit value we have a simple start:
function GetOddSumBelowX( X : Integer) : Integer;
var
i,sum: Integer;
begin
i := 1; // Start with first odd number
sum := 0;
while (i < X) do begin // as long as i less than X, loop
if IsOdd(i) then begin
sum := sum + i; // add to sum
end;
i := i + 1; // Increment i
end;
GetOddSumBelowX := sum;
end;
Now, that was simple enough. Next step to simplify the loop is to increment the i variable by two instead, just to jump between all odd numbers:
function GetOddSumBelowX( X : Integer) : Integer;
var
i,sum: Integer;
begin
i := 1; // Start with first odd number
sum := 0;
while (i < X) do begin // as long as i less than X, loop
sum := sum + i; // add to sum
i := i + 2; // Increment to next odd number
end;
GetOddSumBelowX := sum;
end;

Optimize a perfect number check to O(sqrt(n))

Part of the program I have checks if an input number is a perfect number. We're supposed to find a solution that runs in O(sqrt(n)). The rest of my program runs in constant time, but this function is holding me back.
function Perfect(x: integer): boolean;
var
i: integer;
sum: integer=0;
begin
for i := 1 to x-1 do
if (x mod i = 0) then
sum := sum + i;
if sum = x then
exit(true)
else
exit(false);
end;
This runs in O(n) time, and I need to cut it down to O(sqrt(n)) time.
These are the options I've come up with:
(1) Find a way to make the for loop go from 1 to sqrt(x)...
(2) Find a way to check for a perfect number that doesn't use a for loop...
Any suggestions? I appreciate any hints, tips, instruction, etc. :)
You need to iterate the cycle not for i := 1 to x-1 but for i := 2 to trunc(sqrt(x)).
The highest integer divisor is x but we do not take it in into account when looking for perfect numbers. We increment sum by 1 instead (or initialize it with 1 - not 0).
The code if (x mod i = 0) then sum := sum + i; for this purpose can be converted to:
if (x mod i = 0) then
begin
sum := sum + i;
sum := sum + (x div i);
end;
And so we get the following code:
function Perfect(x: integer): boolean;
var
i: integer;
sum: integer = 1;
sqrtx: integer;
begin
sqrtx := trunc(sqrt(x));
i := 2;
while i <= sqrtx do
begin
if (x mod i = 0) then
begin
sum := sum + i;
sum := sum + (x div i) // you can also compare i and x div i
//to avoid adding the same number twice
//for example when x = 4 both 2 and 4 div 2 will be added
end;
inc(i);
end;
if sum = x then
exit(true)
else
exit(false);
end;

Algorithm name for all 2-uplets of a set

I'm looking for the name (and for the code : in PL/SQL or PG/SQL) of the algorithm which is finding all couple (2-uplets) of a set.
Example :
A - B - C
Result :
1 : A - B
2 : A - C
3 : B - C
I know that the powerset algorithm do this part of the job, but I'm looking for an optimised couple finder algorithm.
Link for the powerset pg/sql algorithm : https://www.postgresql.org/message-id/20060924054759.GA71934%40winnie.fuhr.org
Have you considered something like
Select A.x, B.x
From YourTable as A, YourTable as B
Where A.key <> B.key
You mention SQL so this might be preferable. Note that the number of rows in the cross product is about the same as the number of pairs, so it isn't terribly inefficient.
I've build the solution :
CREATE OR REPLACE FUNCTION twouplets(a anyarray)
RETURNS SETOF anyarray AS
$BODY$
DECLARE
retval a%TYPE;
size integer := array_upper(a, 1);
i integer;
j integer;
BEGIN
i := 0;
j := 1;
FOR i IN 1 .. size LOOP
FOR j IN 1 .. size-i LOOP
retval := '{}';
retval := array_append(retval, a[i]);
retval := array_append(retval, a[i+j]);
RETURN NEXT retval;
END LOOP;
END LOOP;
RETURN;
END;
$BODY$
LANGUAGE plpgsql IMMUTABLE STRICT
COST 100
ROWS 1000;
ALTER FUNCTION twouplets(anyarray)
OWNER TO postgres;

PLSQL - How does this Prime number code work?

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');

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;

Resources