-- This is the implementation for the BigNum abstract data type, which supports
-- arithmetic with VERY LARGE natural values. The operations provided
-- work as one would expect for natural numbers.
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
package body BigNumPkg is
-- Currently the implementation uses a base 10 system for
-- storing numbers and performing arithmetic operations.
--
InternalBase : constant Positive := 10;
-- This is a stub routine
-- You are to complete the implementation of this routine
function toString(X: BigNum) return String is
begin
return "";
end toString;
function "<" (X, Y : BigNum) return Boolean is
begin
for I in 0..Size-1 loop
if X(I) < Y(I) then
return True;
elsif X(I) > Y(I) then
return False;
end if;
end loop;
return False;
end "<";
function ">" (X, Y : BigNum) return Boolean is
begin
return not (X < Y or X = Y);
end ">";
function "<=" (X, Y : BigNum) return Boolean is
begin
return X = Y or X < Y;
end "<=";
function ">=" (X, Y : BigNum) return Boolean is
begin
return not (X < Y);
-- return Standard.">="(X, Y); -- Causes error on intel platform
end ">=";
function "+" (X, Y : BigNum) return BigNum is
Overflow : Boolean;
Result : BigNum;
begin
plus_ov (X, Y, Result, Overflow);
if Overflow then
raise BigNumOverFlow;
end if;
return Result;
end "+";
-- To add two numbers, start in the right most part of the two
-- arrays and add column by column working toward the left. The
-- value of carry indicates how much of a previous column's value
-- should be carried forward to the next column's.
--
procedure plus_ov (X, Y : BigNum; Result : out BigNum; Overflow : out Boolean) is
Carry : Natural := 0;
Sum : Integer;
begin
for I in reverse 0..Size-1 loop
Sum := Carry + X(I) + Y(I);
-- Determine the amount of carry.
if Sum >= InternalBase then
Sum := Sum - InternalBase;
Carry := 1;
else
Carry := 0;
end if;
Result(I) := Sum;
end loop;
-- The result is too big if the left-most column gave
-- a carry.
Overflow := Carry > 0;
end plus_ov;
-- Currently implemented as repeated addition. This make "*" slow,
-- but at least the result is correct. :-)
--
function "*" (X, Y : BigNum) return BigNum is
Count, Result : BigNum := Zero;
begin
while Count /= Y loop
Count := Count + One;
Result := Result + X;
end loop;
return Result;
end "*";
-- Skips leading whitespace (spaces, tabs, end of lines) before
-- the data to be read.
--
procedure Get (Item : out BigNum) is
Letter : Character;
LineEnd : Boolean;
LastI : Natural := 0;
begin
-- Skip leading whitespace
loop
if End_Of_File then
raise DATA_ERROR;
elsif End_Of_Line then
Skip_Line;
else
Look_Ahead(Letter, LineEnd);
-- exit if find a digit
exit when Letter in '0'..'9';
-- Original version skipped leading zeros, as follows:
-- exit when Letter in '1'..'9';
Get(Letter);
if Letter /= ' ' and Letter /= ASCII.HT
and Letter /= '0' then
raise DATA_ERROR;
end if;
end if;
end loop;
-- Read in digits of number
for I in 0..Size-1 loop
exit when End_Of_Line;
Look_Ahead(Letter, LineEnd);
exit when LineEnd;
exit when Letter not in '0'..'9';
Get(Item(I), Width => 1);
LastI := I;
end loop;
-- If there's still more digits, then raise DATA_ERROR.
Look_Ahead(Letter, LineEnd);
if Letter in '0'..'9' then
raise DATA_ERROR;
end if;
-- Shift digits to the left within the array
for I in reverse 0..LastI loop
Item(I+Size-1-LastI) := Item(I);
end loop;
for I in 0..Size-2-LastI loop
Item(I) := 0;
end loop;
end Get;
-- Writes a BigNum to the output, padding with leading spaces
-- if the width given is larger than the length of the number
-- (leading zeros are not printed).
--
procedure Put (Item : BigNum; Width : Natural := 1) is
First : Integer := Size-1;
begin
-- Determine where the first digit of the number is,
-- and thus the length of the number.
for I in 0..Size-1 loop
if Item(I) /= 0 then
First := I;
exit;
end if;
end loop;
-- Put any leading blanks that are necessary.
for I in Size-First+1..Width loop
Put(' ');
end loop;
-- Write out the digits of the number.
for I in First..Size-1 loop
Put(Item(I), Width => 1);
end loop;
end Put;
end BigNumPkg;