Oracle database experiences

Oracle database blog

Working with large integers using PL/SQL – Part II – Multiplication

Constructor

First of all, the constructor that has the 3 “int_part” as parameters is not very convenient, because you have to enumerate the 3 “int_part” parts starting by the last digits of the large integer.
We will add a new constructor method that will take a VARCHAR2 as a parameter. We will define this constructor as follow:

...
CONSTRUCTOR FUNCTION large_integer(p_large_integer VARCHAR2)
   RETURN SELF AS RESULT,
...
CONSTRUCTOR FUNCTION large_integer(p_large_integer VARCHAR2)
   RETURN SELF AS RESULT
   IS
      v_li_length     INTEGER;
      v_large_integer VARCHAR2(200);
   BEGIN
      IF LENGTH(p_large_integer) > 111 THEN
         RAISE_APPLICATION_ERROR(-20002,'Large integer too big!');
      ELSE

         v_large_integer := LPAD(p_large_integer,111,'0');
         v_li_length := LENGTH(v_large_integer);

         SELF.int_part0 := TO_NUMBER(SUBSTR(v_large_integer,v_li_length-36,37));
         SELF.int_part1 := TO_NUMBER(SUBSTR(v_large_integer,v_li_length-73,37));
         SELF.int_part2 := TO_NUMBER(SUBSTR(v_large_integer,v_li_length-110,37));

      END IF;
      
      RETURN;
   END large_integer;
...

Basic multiplication

We will start with a basic multiplication by multiplying a large integer by a digit (0-9). Except for the 0 digit, we will use the add_li member procedure to handle this multiplication as shown as follow:

...
 MEMBER PROCEDURE multiply_digit(p_digit NUMBER)
   IS
      v_large_integer large_integer;
      v_index         PLS_INTEGER;
   BEGIN
      IF p_digit NOT IN (0,1,2,3,4,5,6,7,8,9) 
      THEN
         RAISE_APPLICATION_ERROR(-20001,'Multiply_digit:p_digit should be between 0 and 9!');
      ELSIF p_digit = 0 
      THEN
         int_part0:=0;
         int_part1:=0;
         int_part2:=0;
      ELSE
         v_large_integer := SELF;
         FOR v_index IN 1..(p_digit-1)
         LOOP
            SELF.add_li(v_large_integer);  
         END LOOP;
      END IF;
   END multiply_digit; 
...

Modified specifications

You will find below the modified specifications:

CREATE OR REPLACE TYPE large_integer AS OBJECT (
   int_part0 NUMBER(37),
   int_part1 NUMBER(37),
   int_part2 NUMBER(37),
   --
   CONSTRUCTOR FUNCTION large_integer
   RETURN SELF AS RESULT,
   --
   CONSTRUCTOR FUNCTION large_integer(int_part0 number,int_part1 number,int_part2 number)
   RETURN SELF AS RESULT,
   --
   CONSTRUCTOR FUNCTION large_integer(p_large_integer VARCHAR2)
   RETURN SELF AS RESULT,
   --
   MEMBER PROCEDURE display,
   --
   MEMBER PROCEDURE add_li(p_large_integer large_integer), 
   --
   MEMBER PROCEDURE multiply_digit(p_digit NUMBER)

) INSTANTIABLE NOT FINAL;

Modified body

You will find below the modified body:

CREATE OR REPLACE TYPE BODY large_integer
IS
   CONSTRUCTOR FUNCTION large_integer 
   RETURN SELF AS RESULT 
   IS
   BEGIN
      int_part0:=0;
      int_part1:=0;
      int_part2:=0;
      RETURN;
   END large_integer;
   --
   CONSTRUCTOR FUNCTION large_integer(int_part0 number,int_part1 number,int_part2 number) 
   RETURN SELF AS RESULT 
   IS
   BEGIN
      SELF.int_part0:=int_part0;
      SELF.int_part1:=int_part1;
      SELF.int_part2:=int_part2; 
      RETURN;
   END large_integer;
   --
   CONSTRUCTOR FUNCTION large_integer(p_large_integer VARCHAR2)
   RETURN SELF AS RESULT
   IS
      v_li_length     INTEGER;
      v_large_integer VARCHAR2(200);
   BEGIN
      IF LENGTH(p_large_integer) > 111 THEN
         RAISE_APPLICATION_ERROR(-20002,'Large integer too big!');
      ELSE

         v_large_integer := LPAD(p_large_integer,111,'0');
         v_li_length := LENGTH(v_large_integer);

         SELF.int_part0 := TO_NUMBER(SUBSTR(v_large_integer,v_li_length-36,37));
         SELF.int_part1 := TO_NUMBER(SUBSTR(v_large_integer,v_li_length-73,37));
         SELF.int_part2 := TO_NUMBER(SUBSTR(v_large_integer,v_li_length-110,37));

      END IF;
      
      RETURN;
   END large_integer;
   --
   MEMBER PROCEDURE display 
   IS
   BEGIN
      DBMS_OUTPUT.PUT_LINE('#' 
                        || LPAD(TO_CHAR(SELF.int_part2),37,'0') 
                        || LPAD(TO_CHAR(SELF.int_part1),37,'0') 
                        || LPAD(TO_CHAR(SELF.int_part0),37,'0'));
   END display;
   --
   MEMBER PROCEDURE add_li(p_large_integer large_integer) 
   IS
      v_carry    NUMBER    :=0;
      v_sub_add  NUMBER(38);
   BEGIN
      v_sub_add := SELF.int_part0 + p_large_integer.int_part0; 

      v_carry := TO_NUMBER(SUBSTR(LPAD(TO_CHAR(v_sub_add),38,'0'),1,1));

      SELF.int_part0 := TO_NUMBER(SUBSTR(LPAD(TO_CHAR(v_sub_add),38,'0'),2));

      v_sub_add := SELF.int_part1 + p_large_integer.int_part1 + v_carry;

      v_carry := TO_NUMBER(SUBSTR(LPAD(TO_CHAR(v_sub_add),38,'0'),1,1));

      SELF.int_part1 := TO_NUMBER(SUBSTR(LPAD(TO_CHAR(v_sub_add),38,'0'),2));

      v_sub_add := SELF.int_part2 + p_large_integer.int_part2 + v_carry;

      v_carry := TO_NUMBER(SUBSTR(LPAD(TO_CHAR(v_sub_add),38,'0'),1,1)); 

      SELF.int_part2 := TO_NUMBER(SUBSTR(LPAD(TO_CHAR(v_sub_add),38,'0'),2));

      IF v_carry > 0 THEN 
         RAISE_APPLICATION_ERROR(-20000,'Add_li:Large integer too big!'); 
      END IF;
     
   END add_li;
   --
   MEMBER PROCEDURE multiply_digit(p_digit NUMBER)
   IS
      v_large_integer large_integer;
      v_index         PLS_INTEGER;
   BEGIN
      IF p_digit NOT IN (0,1,2,3,4,5,6,7,8,9) 
      THEN
         RAISE_APPLICATION_ERROR(-20001,'Multiply_digit:p_digit should be between 0 and 9!');
      ELSIF p_digit = 0 
      THEN
         int_part0:=0;
         int_part1:=0;
         int_part2:=0;
      ELSE
         v_large_integer := SELF;
         FOR v_index IN 1..(p_digit-1)
         LOOP
            SELF.add_li(v_large_integer);  
         END LOOP;
      END IF;
   END multiply_digit; 
  
END;

Examples:

SA> DECLARE
  2     v_li1 large_integer;
  3     v_li2 large_integer;
  4  BEGIN
  5     DBMS_OUTPUT.PUT_LINE('-- Example3: Multiply_digit');
  6     v_li1 := large_integer('111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111');
  7     v_li1.display();
  8     v_li1.multiply_digit(9);
  9     v_li1.display();
 10
 11     DBMS_OUTPUT.PUT_LINE('-- Example4: Multiply_digit');
 12     v_li1 := large_integer('111111111111111111111111111111111111122222222222222222222222222222222222223333333333333333333333333333333333333');
 13     v_li1.display();
 14     v_li1.multiply_digit(3);
 15     v_li1.display();
 16
 17  END;
 18  /
-- Example3: Multiply_digit
#111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
#999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
-- Example4: Multiply_digit
#111111111111111111111111111111111111122222222222222222222222222222222222223333333333333333333333333333333333333
#333333333333333333333333333333333333366666666666666666666666666666666666669999999999999999999999999999999999999

PL/SQL procedure successfully completed.
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: