181 lines
4.7 KiB
Ada
181 lines
4.7 KiB
Ada
with Ada.Unchecked_Deallocation;
|
|
|
|
package body BT is
|
|
|
|
procedure Free is new Ada.Unchecked_Deallocation (Trit_Array, Trit_Access);
|
|
|
|
-- Conversions
|
|
-- String to BT
|
|
function To_Balanced_Ternary (Str: String) return Balanced_Ternary is
|
|
J : Positive := 1;
|
|
Tmp : Trit_Access;
|
|
begin
|
|
Tmp := new Trit_Array (1..Str'Last);
|
|
for I in reverse Str'Range loop
|
|
case Str(I) is
|
|
when '+' => Tmp (J) := 1;
|
|
when '-' => Tmp (J) := -1;
|
|
when '0' => Tmp (J) := 0;
|
|
when others => raise Constraint_Error;
|
|
end case;
|
|
J := J + 1;
|
|
end loop;
|
|
return (Ada.Finalization.Controlled with Ref => Tmp);
|
|
end To_Balanced_Ternary;
|
|
|
|
-- Integer to BT
|
|
function To_Balanced_Ternary (Num: Integer) return Balanced_Ternary is
|
|
K : Integer := 0;
|
|
D : Integer;
|
|
Value : Integer := Num;
|
|
Tmp : Trit_Array(1..19); -- 19 trits is enough to contain
|
|
-- a 32 bits signed integer
|
|
begin
|
|
loop
|
|
D := (Value mod 3**(K+1))/3**K;
|
|
if D = 2 then D := -1; end if;
|
|
Value := Value - D*3**K;
|
|
K := K + 1;
|
|
Tmp(K) := Trit(D);
|
|
exit when Value = 0;
|
|
end loop;
|
|
return (Ada.Finalization.Controlled
|
|
with Ref => new Trit_Array'(Tmp(1..K)));
|
|
end To_Balanced_Ternary;
|
|
|
|
-- BT to Integer --
|
|
-- If the BT number is too large Ada will raise CONSTRAINT ERROR
|
|
function To_Integer (Num : Balanced_Ternary) return Integer is
|
|
Value : Integer := 0;
|
|
Pos : Integer := 1;
|
|
begin
|
|
for I in Num.Ref.all'Range loop
|
|
Value := Value + Integer(Num.Ref(I)) * Pos;
|
|
Pos := Pos * 3;
|
|
end loop;
|
|
return Value;
|
|
end To_Integer;
|
|
|
|
-- BT to String --
|
|
function To_String (Num : Balanced_Ternary) return String is
|
|
I : constant Integer := Num.Ref.all'Last;
|
|
Result : String (1..I);
|
|
begin
|
|
for J in Result'Range loop
|
|
case Num.Ref(I-J+1) is
|
|
when 0 => Result(J) := '0';
|
|
when -1 => Result(J) := '-';
|
|
when 1 => Result(J) := '+';
|
|
end case;
|
|
end loop;
|
|
return Result;
|
|
end To_String;
|
|
|
|
-- unary minus --
|
|
function "-" (Left : in Balanced_Ternary)
|
|
return Balanced_Ternary is
|
|
Result : constant Balanced_Ternary := Left;
|
|
begin
|
|
for I in Result.Ref.all'Range loop
|
|
Result.Ref(I) := - Result.Ref(I);
|
|
end loop;
|
|
return Result;
|
|
end "-";
|
|
|
|
-- addition --
|
|
Carry : Trit;
|
|
|
|
function Add (Left, Right : in Trit)
|
|
return Trit is
|
|
begin
|
|
if Left /= Right then
|
|
Carry := 0;
|
|
return Left + Right;
|
|
else
|
|
Carry := Left;
|
|
return -Right;
|
|
end if;
|
|
end Add;
|
|
pragma Inline (Add);
|
|
|
|
function "+" (Left, Right : in Trit_Array)
|
|
return Balanced_Ternary is
|
|
Max_Size : constant Integer :=
|
|
Integer'Max(Left'Last, Right'Last);
|
|
Tmp_Left, Tmp_Right : Trit_Array(1..Max_Size) := (others => 0);
|
|
Result : Trit_Array(1..Max_Size+1) := (others => 0);
|
|
begin
|
|
Tmp_Left (1..Left'Last) := Left;
|
|
Tmp_Right(1..Right'Last) := Right;
|
|
for I in Tmp_Left'Range loop
|
|
Result(I) := Add (Result(I), Tmp_Left(I));
|
|
Result(I+1) := Carry;
|
|
Result(I) := Add(Result(I), Tmp_Right(I));
|
|
Result(I+1) := Add(Result(I+1), Carry);
|
|
end loop;
|
|
-- remove trailing zeros
|
|
for I in reverse Result'Range loop
|
|
if Result(I) /= 0 then
|
|
return (Ada.Finalization.Controlled
|
|
with Ref => new Trit_Array'(Result(1..I)));
|
|
end if;
|
|
end loop;
|
|
return (Ada.Finalization.Controlled
|
|
with Ref => new Trit_Array'(1 => 0));
|
|
end "+";
|
|
|
|
function "+" (Left, Right : in Balanced_Ternary)
|
|
return Balanced_Ternary is
|
|
begin
|
|
return Left.Ref.all + Right.Ref.all;
|
|
end "+";
|
|
|
|
-- Subtraction
|
|
function "-" (Left, Right : in Balanced_Ternary)
|
|
return Balanced_Ternary is
|
|
begin
|
|
return Left + (-Right);
|
|
end "-";
|
|
|
|
-- multiplication
|
|
function "*" (Left, Right : in Balanced_Ternary)
|
|
return Balanced_Ternary is
|
|
A, B : Trit_Access;
|
|
Result : Balanced_Ternary;
|
|
begin
|
|
if Left.Ref.all'Length > Right.Ref.all'Length then
|
|
A := Right.Ref; B := Left.Ref;
|
|
else
|
|
B := Right.Ref; A := Left.Ref;
|
|
end if;
|
|
for I in A.all'Range loop
|
|
if A(I) /= 0 then
|
|
declare
|
|
Tmp_Result : Trit_Array (1..I+B.all'Length-1) := (others => 0);
|
|
begin
|
|
for J in B.all'Range loop
|
|
Tmp_Result(I+J-1) := B(J) * A(I);
|
|
end loop;
|
|
Result := Result.Ref.all + Tmp_Result;
|
|
end;
|
|
end if;
|
|
end loop;
|
|
return Result;
|
|
end "*";
|
|
|
|
procedure Adjust (Object : in out Balanced_Ternary) is
|
|
begin
|
|
Object.Ref := new Trit_Array'(Object.Ref.all);
|
|
end Adjust;
|
|
|
|
procedure Finalize (Object : in out Balanced_Ternary) is
|
|
begin
|
|
Free (Object.Ref);
|
|
end Finalize;
|
|
|
|
procedure Initialize (Object : in out Balanced_Ternary) is
|
|
begin
|
|
Object.Ref := new Trit_Array'(1 => 0);
|
|
end Initialize;
|
|
|
|
end BT;
|