-- Sample Script to test performance improvement from PL/SQL native compilation
-- Computational intensive algorithm with no database access
-- Consider the task of finding all right-angled triangles with all side lengths
-- integer (a. k. a. perfect triangles). We must count only unique triangles,
-- i. e. those whose sides are not each the same integral multiple of the
-- sides of a perfect triangle already found. The following implements an exhaustive
-- search among candidate triangles with all possible combinations of lengths of
-- the two shorter sides, each in the range 1 to a specified maximum. Each candidate
-- is coarsely filtered by testing if the square root of the sum of the squares
-- of the two short sides is within 0.01 of an integer. Triangles which pass this
-- test are tested exactly by applying Pythagoras's theorem using integer arithmetic.
-- Candidate perfect triangles are tested against the list of multiples of perfect
-- triangles found so far. Each new unique perfect triangle is stored in a PL/
-- SQL table, and its multiples (up to the maximum length) are stored in a separate
-- PL/ SQL table to facilitate uniqueness testing.
-- The implementation thus involves a doubly nested loop with these steps at its
-- heart: several arithmetic operations, casts and comparisons; calls to procedures
-- implementing comparisons driven by iteration through a PL/ SQL table (with yet
-- more arithmetic operations); and extension of PL/ SQL tables where appropriate.
-- The elapsed time was measured for p_ max= 5000 (i. e. 12.5 million
-- repetitions of the heart of the loop) using interpreted and natively compiled
-- versions of the procedure. The times were 548 sec and 366 sec respectively (on
-- a Sun Ultra60 with no load apart from the test). Thus the natively compiled
-- version was about 33% faster.
-- Connect programmer/p@9i
set serveroutput on
drop procedure Perfect_Triangles;
create or replace procedure Perfect_Triangles ( p_max in integer ) is
t1 integer; t2 integer;
long integer; short integer; hyp number; ihyp integer;
type side_r is record ( short integer, long integer );
type sides_t is table of side_r index by binary_integer;
unique_sides sides_t; n integer:=0 /* curr max elements in unique_sides */;
dup_sides sides_t; m integer:=0 /* curr max elements in dup_sides */;
procedure Store_Dup_Sides ( p_long in integer, p_short in integer ) is
mult integer:=2; long_mult integer:=p_long*2; short_mult integer:=p_short*2;
begin
while ( long_mult < p_max ) or ( short_mult < p_max )
loop
n := n+1;
dup_sides(n).long := long_mult; dup_sides(n).short := short_mult;
mult := mult+1; long_mult := p_long*mult; short_mult := p_short*mult;
end loop;
end Store_Dup_Sides;
function Sides_Are_Unique ( p_long in integer, p_short in integer )
return boolean is
begin
for j in 1..n
loop
if ( p_long = dup_sides(j).long ) and ( p_short = dup_sides(j).short )then
return false;
end if;
end loop;
return true;
end Sides_Are_Unique;
begin /* Perfect_Triangles */
t1 := Dbms_Utility.Get_Time;
for long in 1..p_max
loop
for short in 1..long
loop
hyp := Sqrt ( long*long + short*short ); ihyp := Floor(hyp);
if hyp-ihyp < 0.01 then
if ( ihyp*ihyp = long*long + short*short )then
if Sides_Are_Unique ( long, short )then
m := m+1;
unique_sides(m).long := long; unique_sides(m).short := short;
Store_Dup_Sides ( long, short );
end if;
end if;
end if;
end loop;
end loop;
t2 := Dbms_Utility.Get_Time;
Dbms_Output.Put_Line (
chr(10) || To_Char( ((t2-t1)/100), '9999.9' ) || ' sec' );
end Perfect_Triangles;
/
Show Errors