pl/sql find greatest common factor from a table - plsql

I am trying to find the greatest common factor for some numbers that i have put into a table. So far I have the function that is suppose to calculate the gcf
CREATE FUNCTION gcd (x INTEGER, y INTEGER) RETURN INTEGER AS
ans INTEGER;
BEGIN
IF (y <= x) AND (x MOD y = 0) THEN
ans := y;
ELSIF x < y THEN
ans := gcd(y, x);
ELSE
ans := gcd(y, x MOD y);
END IF;
RETURN ans;
END;
and here I create and random populate my table
DROP TABLE numere
/
CREATE TABLE numbers (number NUMBER(3) NOT NULL)
/
set serveroutput on
DECLARE
number NUMBER(3);
cursor c1 is
SELECT * FROM note;
BEGIN
FOR i IN 1 .. 10 LOOP
number:=dbms_random.value(20,100);
insert into numbers values(number);
end loop;
commit;
END;
/
How can I integrate the gcf into my code? I want to display the numbers followed by their gcf.

I am not sure about your gcd function. It seems to me not working. There are many on the web. This is one of them:
CREATE OR REPLACE FUNCTION find_gcd (
p_n1 IN POSITIVE
, p_n2 IN POSITIVE
)
RETURN POSITIVE
IS
l_n1 POSITIVE := p_n1;
l_n2 POSITIVE := p_n2;
BEGIN
WHILE NOT (l_n1 = l_n2)
LOOP
CASE SIGN(l_n1 - l_n2)
WHEN +1
THEN l_n1 := l_n1 - l_n2;
ELSE l_n2 := l_n2 - l_n1;
END CASE;
END LOOP;
RETURN (l_n1);
END find_gcd;
/
You can simply amend your PL/SQL block to call the gcd function and print out the results (I here assumed you want to find the gcd for each number and the following number in your table, so I used LEAD function):
DECLARE
lv_number NUMBER(3);
lv_gcd INTEGER;
BEGIN
FOR i IN 1 .. 10 LOOP
lv_number:=dbms_random.value(20,100);
insert into numbers values(lv_number);
end loop;
commit;
FOR i in (select COL_VAL, lead(COL_VAL) over (order by rowid) nxt_val from numbers)
LOOP
lv_gcd := find_gcd(i.COL_VAL, i.nxt_val);
DBMS_OUTPUT.PUT_LINE('GCD for '||TO_CHAR(i.COL_VAL)||' and '|| TO_CHAR(i.nxt_val) ||' is '||TO_CHAR(lv_gcd));
END LOOP;
END;
/

Related

Drawing a flag with diagonal crosses in a V-Shape (ADA)

I turn to Stackoverflow yet again. having gotten help here previously I hope to be received equally friendly once more. I have an assignment where I need to draw a flag (including a box-like shape around it and a V-shape of crosses in its midst) in ADA. Ive managed to make the box and roughly half of the crosses. can anyone clue me in as to how one easiest fills in the remainder of the crosses?
Its supposed to be a V-shape, like this:
+ +
+ +
+
etc
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure exercise2 is
subtype Cross_Rows is Integer range 2..80;
Rows : Cross_Rows;
Flag_Width : Cross_Rows;
Left : Positive;
Right : Positive;
procedure Row_Get (Rows: out Cross_Rows) is
begin
Put("Enter the number of cross rows (min is 3): ");
Get(Rows);
Skip_Line;
end Row_Get;
procedure Print_Top (Rows: in Cross_Rows) is
begin
Flag_Width := (Rows * 2) + 4;
Put("+");
for Col in 1..Flag_Width-3 loop
Put("-");
end loop;
Put("+");
New_Line;
end Print_Top;
procedure Print_Middle (Rows: in Cross_Rows) is
begin
Left := 1;
Right := Flag_Width - 5;
for R in 1..Rows loop
Put("! ");
for C in 1..Flag_Width - 4 loop
if C = Left or else C = Right then
Put("+");
else
Put(" ");
end if;
end loop;
Left := Left + 1;
Right := Right - 1;
Put_Line("!");
end loop;
end Print_Middle;
procedure Print_Bottom (Rows: in Cross_Rows) is
begin
Flag_Width := (Rows * 2) + 4;
Put("+");
for C in 1..Flag_Width-3 loop
Put("-");
end loop;
Put_Line("+");
end Print_Bottom;
begin
Row_Get(Rows);
Print_Top(Rows);
Print_Middle(Rows);
Print_Bottom(Rows);
end exercise2;
EDIT: Thanks to Jim Rogers I managed to edit my program to draw the flag. Unfortunately its not exactly the way its meant to be as the top crosses are supposed to touch the sides and not be spaced like they are now. Additionally the Main program and the subprograms arent allowed to be more than 15 lines each so I compartmentalized them.
The smallest flag is supposed to look like this. I'll try to work with his code to achieve this. But any help is of value! :)
n=1
+---+
!+ +!
! + !
+---+
n=2
+-----+
!+ +!
! + + !
! + !
+-----+
You need to keep track of the left and right columns for the '+' characters, increasing the left column position and decreasing the right column position with each iteration of your loop for printing the crosses.
The following program works for any number of rows of crosses from 3 to 80.
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure Main is
subtype Cross_Rows is Integer range 3..80;
Rows : Cross_Rows;
Flag_Width : Cross_Rows;
Left : Positive;
Right : Positive;
begin
Put("Enter the number of cross rows (minimum is 3): ");
Get(Rows);
Skip_Line;
Flag_Width := (Rows * 2) + 4;
-- Print top row of flag boundary
for Col in 1..Flag_Width loop
Put("-");
end loop;
Put("-");
New_Line;
-- Print empty row below top flag boundary
Put("- ");
for C in 3..Flag_Width - 2 loop
Put(" ");
end loop;
Put_Line(" -");
-- Print crosses
Left := 1;
Right := Flag_Width - 5;
for R in 1..Rows loop
Put("- ");
for C in 1..Flag_Width - 4 loop
if C = Left or else C = Right then
Put("+");
else
Put(" ");
end if;
end loop;
Left := Left + 1;
Right := Right - 1;
Put_Line(" -");
end loop;
-- Print bottom flag rows
Put("- ");
for C in 3..Flag_Width - 2 loop
Put(" ");
end loop;
Put_Line(" -");
for C in 1..Flag_Width loop
Put("-");
end loop;
Put_Line("-");
end Main;
Example output is:
Enter the number of cross rows (minimum is 3): 7
-------------------
- -
- + + -
- + + -
- + + -
- + + -
- + + -
- + + -
- + -
- -
-------------------
Another approach uses the Set_Col procedure from Ada.Text_Io. Set_Col set the cursor to the specified column number in the current output line. For example, if the cursor starts at position 1 and you call Set_Col(10) the procedure will output 9 blank characters and set the column number to 10. You can then begin writing your non-blank output at column 10.
with Ada.Text_Io; use Ada.Text_IO;
with Ada.Integer_Text_Io; use Ada.Integer_Text_IO;
procedure V_columns is
subtype Cross_Rows is Integer range 3..80;
Rows : Cross_Rows;
Flag_Width : Positive;
Left : Positive;
Right : Positive;
begin
Put("Enter the number of cross rows (minimum is 3): ");
Get(Rows);
Skip_Line;
Flag_Width := (Rows * 2) + 4;
-- Print top row of flag boundary
for Col in 1..Flag_Width loop
Put("-");
end loop;
New_Line;
-- Print empty row below top flag boundary
Set_Col(1);
Put("|");
Set_Col(Positive_Count(Flag_Width));
Put_Line("|");
-- Print crosses
Left := 3;
Right := Flag_Width - 3;
for R in 1..Rows loop
Set_Col(1);
Put("|");
if Left < Right then
Set_Col(Positive_Count(Left));
Put("+");
Set_Col(Positive_Count(Right));
Put("+");
else
Set_Col(Positive_Count(Right));
Put("+");
end if;
Set_Col(Positive_Count(Flag_Width));
Put("|");
New_Line;
Left := Left + 1;
Right := Right - 1;
end loop;
-- Print bottom flag rows
Set_Col(1);
Put("|");
Set_Col(Positive_Count(Flag_Width));
Put_Line("|");
for C in 1..Flag_Width loop
Put("-");
end loop;
New_Line;
end V_Columns;
The output of the program is:
Enter the number of cross rows (minimum is 3): 7
------------------
| |
| + + |
| + + |
| + + |
| + + |
| + + |
| + + |
| + |
| |
------------------
You could also choose an approach in which the definition of the pattern (here: a flag) and the output mechanism are almost completely decoupled. This approach also allows you to parallelize the flag rendering in case you need to render really, really huge flags ;-):
main.adb
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
N : constant := 2;
Width : constant := 3 + 2 * N;
Height : constant := 3 + 1 * N;
type Screen_X is new Natural range 0 .. Width - 1;
type Screen_Y is new Natural range 0 .. Height - 1;
-------------
-- Pattern --
-------------
function Pattern (X : Screen_X; Y : Screen_Y) return Character is
Is_Border_LR : constant Boolean :=
X = Screen_X'First or else X = Screen_X'Last;
Is_Border_TB : constant Boolean :=
Y = Screen_Y'First or else Y = Screen_Y'Last;
-- The V-Shape is based on the implicit function:
--
-- abs (X - X0) + (Y - Y0) = 0
X0 : constant := (Screen_X'Last + Screen_X'First) / 2;
Y0 : constant := Screen_Y'Last - 1;
Is_V_Shape : constant Boolean :=
Integer (abs (X - X0)) + Integer (Y - Y0) = 0;
begin
if Is_Border_LR and Is_Border_TB then
return '+';
elsif Is_Border_LR then
return '!';
elsif Is_Border_TB then
return '-';
elsif Is_V_Shape then
return '+';
else
return ' ';
end if;
end Pattern;
begin
-- The Render loop.
for Y in Screen_Y loop
for X in Screen_X loop
Put (Pattern (X, Y));
end loop;
New_Line;
end loop;
end Main;
output (N = 1)
$ ./main
+---+
!+ +!
! + !
+---+
output (N = 2)
$ ./main
+-----+
!+ +!
! + + !
! + !
+-----+

How to perform arithmetic contract operations on function taking in 2D array type as parameter in Ada

I have a function that should return the count of Islands found.
I name this function Count_Islands that takes in a parameter of
Map_Array of type Map, of which Map is an array of Islands.
Islands is an enumerator type with set of Land, Water.
I have the function specification in the .ads and the body in the
.adb
The problem I face now is how to proof that my function
Count_Islands'Result will be less than (X * Y)
I have tried: with post => Count_Islands'Result < X * Y
-- Whenever I ran prove all I got: medium: postcondition might
fail cannot prove Count_Islands'Result < X * Y
Function in .ads:
function Count_Islands(Map_Array : Map)
return Integer with Pre => Map_Array'Length /= 0,
Post => Count_Islands'Result < X * Y;
Function in .adb:
function Count_Islands(Map_Array : Map) return Integer
is
Visited_Array : Visited := (others => (others=> False));
Count : Integer := 0;
begin
if (Map_Array'Length = 0)then
return 0;
end if;
for i in X_Range loop
for j in Y_Range loop
if (Map_Array(i, j) = Land and then not Visited_Array(i,j)) then
Visited_Array := Visit_Islands(Map_Array, i, j,Visited_Array);
Count := Count + 1;
end if;
end loop;
end loop;
return Count;
end Count_Islands;
In a matrix of 4 * 5 for instance,i.e my X = 4 And Y = 5:
I expect the output result of an Islands(Lands) found to be 1 which is less than 4 * 5. But GNATprove cannot prove my initial code to analyze that,using Post => Count_Islands'Result < X * Y;
Is there any better way to prove this arithmetic? Thanks for your help.
As the example is not complete, I took the liberty to change it a little bit. You can prove the post condition by adding loop invariants. The program below proves in GNAT CE 2019:
main.adb
procedure Main with SPARK_Mode is
-- Limit the range of the array indices in order to prevent
-- problems with overflow, i.e.:
--
-- Pos'Last * Pos'Last <= Natural'Last
--
-- Hence, as Natural'Last = 2**31 - 1,
--
-- Pos'Last <= Sqrt (2**31 - 1) =approx. 46340
--
-- If Pos'Last >= 46341, then overflow problems might occur.
subtype Pos is Positive range 1 .. 46340;
type Map_Item is (Water, Land);
type Map is
array (Pos range <>, Pos range <>) of Map_Item;
type Visited is
array (Pos range <>, Pos range <>) of Boolean;
function Count_Islands (Map_Array : Map) return Natural with
Post => Count_Islands'Result <= Map_Array'Length (1) * Map_Array'Length (2);
-------------------
-- Count_Islands --
-------------------
function Count_Islands (Map_Array : Map) return Natural is
Visited_Array : Visited (Map_Array'Range (1), Map_Array'Range (2)) :=
(others => (others => False));
Count : Natural := 0;
begin
for I in Map_Array'Range (1) loop
pragma Loop_Invariant
(Count <= (I - Map_Array'First (1)) * Map_Array'Length (2));
for J in Map_Array'Range (2) loop
pragma Loop_Invariant
(Count - Count'Loop_Entry <= J - Map_Array'First (2));
if Map_Array(I, J) = Land and then not Visited_Array(I, J) then
Visited_Array (I, J) := True; -- Simplified
Count := Count + 1;
end if;
end loop;
end loop;
return Count;
end Count_Islands;
begin
null;
end Main;

Pascal recursive summation function school practice problem

This function is a school practice problem (it is running but does not work properly).
My task is to call for a integer from the user.
When the number arrives, my task is to write out (with a recursive algorithm)
what is the sum of the number with the numbers before the given number.
For example if our number is 10 then the upshot is 55 because 1+2+3+4+5+6+7+8+9+10 = 55, etc.
I've already tried to write this code:
function egesszamosszeg(n:integer) : integer;
begin
egesszamosszeg:=0
if n=1 then
egesszamosszeg:=1
else
for n:=1 to egesszamosszeg do
begin
egesszamosszeg:=egesszamosszeg+1;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var egesszam:integer;
begin
egesszam:=strtoint(Inputbox('','Give an integer please!',''));
Showmessage(inttostr(Egesszamosszeg(egesszam)));
end;
My problem is that I do not know what is the main problem with this code.
I do not know what is the main problem with this code.
There are several problems with your code: it's iterative, not recursive; it's way too complicated; this loop:
for n:=1 to egesszamosszeg do
is effectively:
for n:=1 to 0 do
Consider this simple function which effectively implements the gist of your problem:
function egesszamosszeg(n:integer) : integer;
begin
egesszamosszeg := n;
if (n > 1) then
egesszamosszeg := egesszamosszeg + egesszamosszeg(n - 1);
end;
begin
writeln(egesszamosszeg(10));
end.
You are simply trying to increment egesszamosszeg (couldn't you use an easier name?), instead of adding the consecutive numbers to it. But your loop is wrong: eggesszamosszeg is 0, so you are in fact doing for n := 1 to 0 do. That loop will never run. Don't re-use n, use another variable for the loop index:
for i := 1 to n do
egesszamosszeg := egesszamosszeg + i;
But you say it must be recursive, so it must call itself with a different parameter value. Then do something like:
function egesszamosszeg(n: integer): integer;
begin
if n = 1 then // terminating condition
egesszamosszeg := 1
else
egesszamosszeg := n + egesszamosszeg(n - 1); // recursion
end;
In most Pascals, you can use the pseudo-variable Result instead of the function name. Often, that makes typing a little easier.
FWIW, did you know that you could make this a little simpler and do not need recursion or iteration at all? The result can be calculated directly:
function egesszamosszeg(n: Integer): Integer;
begin
result := n * (n + 1) div 2;
end;
For 1..10, that will give 10 * 11 div 2 = 55 too.
See: https://www.wikihow.com/Sum-the-Integers-from-1-to-N
In effect, you count (1+10) + (2+9) + (3+8) + (4+7) + (5+6) = 5 * 11 = 55. You can do the same for any positive number. Same with 1..6: (1+6) + (2+5) + (3+4) = 3 * 7 = 21.
That leads to the formula:
sum = n * (n + 1) div 2
(or actually:
n div 2 * (n+1) // mathematically: n/2 * (n+1)
which is the same).

Solving 4X4 sudoku in maple

So I am trying to use recursion and backtracking to solve a 4x4 sudoku.
When I call SolveSmallSudoku(L);
"Solving now..."
it gives me this "Error, (in SolveSmallSudoku) Matrix index out of range"
But I cannot spot any bug that is related to my matrix, L, indices. It seems like that my program doesn't do my backtracking part properly. I think my findPossibleEntries procedure works fine. It does find all the possible values for that certain cell. Anyone got any hint?
> L := Matrix(4,4,[ [0,4,0,0],[2,0,0,3],[4,0,0,1],[0,0,3,0] ]);
> isFull := proc(L)
local x, y;
for x from 1 to 4 do
for y from 1 to 4 do
if L[x,y]=0 then
return false;
end if;
end do;
end do;
return true;
end proc;
>findPossibleEntries := proc(L, i, j)
local x, y, possible:=[0,0,0,0];
local r:=1, c:=1;
#Checking possible entries in ith row
for y from 1 to 4 do
if not L[i,y] = 0 then
possible[L[i,y]] := 1;
end if;
end do;
#Checking possible entries in jth col
for x from 1 to 4 do
if not L[x,j] = 0 then
possible[L[x,j]] := 1;
end if;
end do;
#Checking possible entries block by block
if i >= 1 and i <= 2 then
r := 1;
elif i >= 3 and i <= 4 then
r := 3;
end if;
if j >= 1 and j <= 2 then
c := 1;
elif j >= 3 and j <= 4 then
c := 3;
end if;
#Using for-loop to find possible entries in the block
for x in range(r, r+1) do
for y in range(c, c+1) do
if not L[x,y] = 0 then
possible[L[x,y]] := 1;
end if;
end do;
end do;
#Now the list, possible, only holds the possible entries
for x from 1 to 4 do
if possible[x] = 0 then
possible[x] := x;
else
possible[x] := 0;
end if;
end do;
return possible;
end proc;
>SolveSmallSudoku := proc(L)
local x, y, i:=0, j:=0, possibleVal:=[0,0,0,0];
if isFull(L) then
print("Solved!");
print(L);
return;
else
print("Solving now...");
for x from 1 to 4 do
for y from 1 to 4 do
if L[x,y] = 0 then
i:=x;
j:=y;
break;
end if
end do;
#Breaks the outer loop as well
if L[x,y] = 0 then
break;
end if
end do;
#Finds all the possibilities for i,j
possibleVal := findPossibleEntries(L,i,j);
#Traverses the list, possibleVal to find the correct entries and finishes the sudoku recursively
for x from 1 to 4 do
if not possibleVal[x] = 0 then
L[i,j]:= possibleVal[x];
SolveSmallSudoku(L);
end if;
end do;
#Backtracking
L[i,j]:= 0;
end if;
end proc;
Get rid of,
#Breaks the outer loop as well
if L[x,y] = 0 then
break;
end if
As you had it originally that outer check was trying to access L[1,5] for your given example L.
Instead, replace the break in the inner loop with,
x:=4; break;
That will cause the outer loop to also complete at the next iteration (which happens to occur right after the inner loop ends or breaks. So you'll get the full break you wanted.
The code then seems to work as you intended, and the solution gets printed for your input example.

Pascal Quicksort - counting the total number of recursions

I am stuck on my quicksort program. I need to count the total number of times the sorting function calls itself.
procedure quick (first, last, counter: integer);
var i, k, x : integer;
begin
i := first;
k := last;
x := a[(i+k) div 2];
counter := counter + 1;
while i<=k do begin
while a[i] < x do
i:= i+1;
while a[k] > x do
k:= k-1;
if i<=k then begin
prohod(i,k);
i:=i+1;
k:=k-1;
end;
end;
if first<k then quick(first,k, counter);
if i<last then quick(i,last, counter);
P:= P + counter;
end;
I tried this, where P is global variable and counter is recursive variable, first called as 1 ( quick(1, n, 1) ) . Sadly did not work. I also set P:= 0; right before I called the sorting (quick) procedure (I am not quite sure if it is correct way to approach the problem but it's all I could come up with).
Any ideas how to make this correctly and / or why my counter is not working?
This looks overly complex. If you just remove the counter, initialize P with the value -1 (instead of 0) and replace P := P + counter with P := P + 1, it should work.

Resources