Babylonian Multiplication
with Ada.Text_IO;
procedure Mult is
generic
Width : Positive;
package Ints is
Overflow : exception;
type Bit is new Natural range 0 .. 1;
type Bit_Index is new Natural range 0 .. Width - 1;
type Int is array (Bit_Index) of Bit;
-- LSB is at 0.
Zero : constant Int := (others => 0);
One : constant Int := (0 => 1, others => 0);
function "+" (Left, Right : Int) return Int;
function "*" (Left, Right : Int) return Int;
function To_Natural (X : Int) return Natural;
function To_Int (X : Natural) return Int;
end;
package body Ints is
function "+" (Left, Right : Int) return Int is
type Bit_And_Carry is record
B, C : Bit;
-- Result bit and new carry.
end record;
Bit_Adder : array (Bit, Bit, Bit) of Bit_And_Carry
:= (0 => (0 => (0 => (0,0),
1 => (1,0)),
1 => (0 => (1,0),
1 => (0,1))),
1 => (0 => (0 => (1,0),
1 => (0,1)),
1 => (0 => (0,1),
1 => (1,1))));
Carry : Bit := 0;
X : Int;
begin
for Pos in Bit_Index loop
declare
Result : Bit_And_Carry
:= Bit_Adder (Carry, Left (Pos), Right (Pos));
begin
X (Pos) := Result.B;
Carry := Result.C;
end;
end loop;
if Carry /= 0 then
raise Overflow;
else
return X;
end if;
end "+";
procedure Double (X : in out Int) is
begin
X := X + X;
end Double;
function "*" (Left, Right : Int) return Int is
Pos_Value : Int := Left;
-- Multiple of Left coressponding to the current bit position in
-- Left.
X : Int := Zero;
-- Temporary result.
MSB_Set : Boolean := False;
-- Most significant bit in Pos_Value is set, no more set
-- bits in Right allowed.
begin
for Pos in Bit_Index loop
if Right (Pos) /= 0 then
if MSB_Set then
raise Overflow;
end if;
X := X + Pos_Value;
end if;
if Pos_Value (Bit_Index'Last) = 1 then
MSB_Set := True;
else
Double (Pos_Value);
end if;
end loop;
return X;
end "*";
function To_Natural (X : Int) return Natural is
Position_Value : Natural := 1;
Result : Natural := 0;
begin
for Pos in Bit_Index loop
if X (Pos) /= 0 then
Result := Result + Position_Value;
end if;
if Pos /= Bit_Index'Last then
Position_Value := Position_Value * 2;
end if;
end loop;
return Result;
end To_Natural;
function To_Int (X : Natural) return Int is
Y : Natural := X;
Position_Value : Int := One;
Result : Int := Zero;
begin
for Pos in Bit_Index loop
if Y mod 2 /= 0 then
Result := Result + Position_Value;
end if;
if Pos /= Bit_Index'Last then
Double (Position_Value);
Y := Y / 2;
end if;
end loop;
return Result;
end To_Int;
end Ints;
package I is new Ints (8);
use I;
begin
Ada.Text_IO.Put_Line (Natural'Image
(To_Natural (To_Int (0) * To_Int (0))));
Ada.Text_IO.Put_Line (Natural'Image
(To_Natural (To_Int (0) * To_Int (1))));
Ada.Text_IO.Put_Line (Natural'Image
(To_Natural (To_Int (1) * To_Int (0))));
Ada.Text_IO.Put_Line (Natural'Image
(To_Natural (To_Int (1) * To_Int (1))));
Ada.Text_IO.Put_Line (Natural'Image
(To_Natural (To_Int (21) * To_Int (11))));
Ada.Text_IO.Put_Line (Natural'Image
(To_Natural (To_Int (51) * To_Int (5))));
Ada.Text_IO.Put_Line (Natural'Image
(To_Natural (To_Int (21) * To_Int (13))));
end Mult;
(Note that this is neither fully tested nor very efficient, but you'll
get the idea. Extending it to 32 bits is trivial except for the
To_Natural and To_Int functions.)
Contributed by: Florian Weimer
Contributed on: October 13, 1999
License: Public Domain
Back