File: [local] / OpenXM_contrib / PHC / Ada / Math_Lib / Numbers / multprec_floating_numbers.adb (download)
Revision 1.1.1.1 (vendor branch), Sun Oct 29 17:45:26 2000 UTC (23 years, 8 months ago) by maekawa
Branch: PHC, MAIN
CVS Tags: v2, maekawa-ipv6, RELEASE_1_2_3, RELEASE_1_2_2_KNOPPIX_b, RELEASE_1_2_2_KNOPPIX, RELEASE_1_2_2, RELEASE_1_2_1, HEAD Changes since 1.1: +0 -0
lines
Import the second public release of PHCpack.
OKed by Jan Verschelde.
|
with Standard_Mathematical_Functions; use Standard_Mathematical_Functions;
package body Multprec_Floating_Numbers is
-- NOTES ON THE IMPLEMENTATION :
-- 0) See the notes in the bodies of Multprec_{Natural,Integer}_Numbers.
-- 1) 0.0 must have zero fraction and zero exponent.
-- 2) The truncate and round operations all depend on the decimal radix.
-- 3) The function "Decimal_Places" occupies a central place.
-- 4) The normalized representation has a nonzero least significant digit.
tol : constant double_float := 10.0**(-8);
-- AUXILIARIES :
function Truncate ( f : double_float ) return integer is
i : integer := integer(f);
begin
if i >= 0
then if double_float(i) > f + tol
then i := i-1;
end if;
else if double_float(i) < f - tol
then i := i+1;
end if;
end if;
return i;
end Truncate;
function Max_Size ( i1,i2 : Integer_Number ) return natural is
-- DESCRIPTION :
-- Return the maximal size of i1 and i2.
sz1 : constant natural := Size(i1);
sz2 : constant natural := Size(i2);
begin
if sz1 > sz2
then return sz1;
else return sz2;
end if;
end Max_Size;
procedure Shift_Left ( n : in out Natural_Number; ns : out natural ) is
-- DESCRIPTION :
-- Shifts n until the leading coefficient is larger than Base/10.
-- The number ns on return equals the number of shifts.
begin
if (Empty(n) or else Equal(n,0))
then ns := 0;
else ns := 0;
while (Coefficient(n,Size(n)) < Base/10) loop
Mul(n,10);
ns := ns+1;
end loop;
end if;
end Shift_Left;
procedure Shift_Right ( n : in out Natural_Number; ns : out natural ) is
-- DESCRIPTION :
-- Shifts n until the last digit in the least significant coefficient
-- of n is different from zero.
-- The number ns on return equals the number of shifts.
cff : natural;
begin
if (Empty(n) or else Equal(n,0))
then ns := 0;
else ns := 0;
cff := Coefficient(n,0) mod 10;
while (cff = 0) loop
Div(n,10);
ns := ns+1;
cff := Coefficient(n,0) mod 10;
end loop;
end if;
end Shift_Right;
procedure Shift_Right ( i : in out Integer_Number; ns : out natural ) is
-- DESCRIPTION :
-- Applies the Shift_Right to the number representation of i.
ni : Natural_Number;
begin
if Empty(i)
then ns := 0;
else --ni := Unsigned(i);
Copy(Unsigned(i),ni); -- avoid sharing
Shift_Right(ni,ns);
if Sign(i) < 0
then Clear(i); i := Create(ni); Min(i);
else Clear(i); i := Create(ni);
end if;
Clear(ni);
end if;
end Shift_Right;
procedure Normalize ( f : in out Floating_Number ) is
-- DESCRIPTION :
-- Normalizes the representation of f so that its fraction has as
-- rightmost digit a nonzero number.
ns : natural;
begin
Shift_Right(f.fraction,ns);
Add(f.exponent,ns);
end Normalize;
procedure Adjust_Expo ( f : in out double_float;
expo : in Integer_Number ) is
-- DESCRIPTION :
-- Multiplies f with 10**expo.
cnt : Integer_Number;
begin
Copy(expo,cnt);
while cnt > 0 loop
f := f*10.0;
Sub(cnt,1);
end loop;
while cnt < 0 loop
f := f/10.0;
Add(cnt,1);
end loop;
Clear(cnt);
end Adjust_Expo;
-- CONSTRUCTORS :
function Create ( i : integer ) return Floating_Number is
res : Floating_Number;
begin
res.fraction := Create(i);
res.exponent := Create(0);
Normalize(res);
return res;
end Create;
function Create ( i : Integer_Number ) return Floating_Number is
res : Floating_Number;
begin
res.fraction := +i;
res.exponent := Create(0);
Normalize(res);
return res;
end Create;
function Create ( fraction,exponent : integer ) return Floating_Number is
res : Floating_Number;
begin
res.fraction := Create(fraction);
res.exponent := Create(exponent);
Normalize(res);
return res;
end Create;
function Create ( fraction : Integer_Number;
exponent : integer ) return Floating_Number is
res : Floating_Number;
begin
res.fraction := +fraction;
res.exponent := Create(exponent);
Normalize(res);
return res;
end Create;
function Create ( fraction : integer;
exponent : Integer_Number ) return Floating_Number is
res : Floating_Number;
begin
res.fraction := Create(fraction);
res.exponent := +exponent;
Normalize(res);
return res;
end Create;
function Create ( fraction,exponent : Integer_Number )
return Floating_Number is
res : Floating_Number;
begin
res.fraction := +fraction;
res.exponent := +exponent;
Normalize(res);
return res;
end Create;
function Create ( f : double_float ) return Floating_Number is
-- NOTE :
-- To avoid rounding errors, comparison operations are prefered
-- above relying on intermediate results of calculations, although
-- rounding errors still occur!
res : Floating_Number;
ten : Integer_Number;
wrkflt,fltexp,lowflt,uppflt,incflt : double_float;
intexp : integer;
fraction,exponent,intinc : Integer_Number;
begin
if f = 0.0
then res := Create(0);
return res;
end if;
if f > 0.0
then wrkflt := f;
else wrkflt := -f;
end if;
fltexp := LOG10(wrkflt);
intexp := Truncate(fltexp);
if intexp < 15
then wrkflt := wrkflt*(10.0**(15-intexp));
exponent := Create(intexp-15);
intexp := 15;
else exponent := Create(0);
end if;
lowflt := 10.0**intexp;
uppflt := 10.0**(intexp+1);
while lowflt > wrkflt loop
intexp := intexp-1;
lowflt := 10.0**intexp;
uppflt := 10.0**(intexp+1);
end loop;
ten := Create(10);
fraction := ten**intexp;
for k in 1..16 loop
incflt := 10.0**intexp;
intinc := ten**intexp;
uppflt := lowflt;
for i in 1..10 loop
uppflt := uppflt + incflt;
exit when (uppflt > wrkflt);
lowflt := uppflt;
Add(fraction,intinc);
end loop;
intexp := intexp - 1;
Clear(intinc);
end loop;
Clear(ten);
if f < 0.0
then Min(fraction);
end if;
res := Create(fraction,exponent);
Normalize(res);
return res;
end Create;
-- SELECTORS :
function Fraction ( f : Floating_Number ) return Integer_Number is
begin
return f.fraction;
end Fraction;
function Exponent ( f : Floating_Number ) return Integer_Number is
begin
return f.exponent;
end Exponent;
function Size_Fraction ( f : Floating_Number ) return natural is
begin
return Size(Fraction(f));
end Size_Fraction;
function Size_Exponent ( f : Floating_Number ) return natural is
begin
return Size(Exponent(f));
end Size_Exponent;
function Decimal_Places_Fraction ( f : Floating_Number ) return natural is
begin
return Decimal_Places(Fraction(f));
end Decimal_Places_Fraction;
function Decimal_Places_Exponent ( f : Floating_Number ) return natural is
begin
return Decimal_Places(Exponent(f));
end Decimal_Places_Exponent;
function Decimal_to_Size ( deci : natural ) return natural is
res : natural;
exp : constant natural := Multprec_Natural_Numbers.Exponent;
begin
res := deci/exp;
if res*exp < deci
then res := res+1;
end if;
return res;
end Decimal_to_Size;
function AbsVal ( f : Floating_Number ) return Floating_Number is
res : Floating_Number;
begin
if Negative(f.fraction)
then res.fraction := -f.fraction;
else res.fraction := +f.fraction;
end if;
res.exponent := +f.exponent;
return res;
end AbsVal;
-- COMPARISON AND COPYING :
function Equal ( f1 : Floating_Number; f2 : double_float ) return boolean is
ff2 : Floating_Number := Create(f2);
res : boolean := Equal(f1,ff2);
begin
Clear(ff2);
return res;
end Equal;
function Equal ( f1,f2 : Floating_Number ) return boolean is
res : boolean;
f1deci : constant natural := Decimal_Places(f1.fraction);
f2deci : constant natural := Decimal_Places(f2.fraction);
f1expo : Integer_Number := f1.exponent + f1deci;
f2expo : Integer_Number := f2.exponent + f2deci;
mulfra : Integer_Number;
begin
if Equal(f1expo,f2expo)
then if f1deci = f2deci
then res := Equal(f1.fraction,f2.fraction);
else if f1deci < f2deci
then mulfra := f1.fraction*10;
for i in 1..(f2deci-f1deci-1) loop
Mul(mulfra,10);
end loop;
res := Equal(mulfra,f2.fraction);
else mulfra := f2.fraction*10;
for i in 1..(f1deci-f2deci-1) loop
Mul(mulfra,10);
end loop;
res := Equal(f1.fraction,mulfra);
end if;
Clear(mulfra);
end if;
else res := false;
end if;
Clear(f1expo); Clear(f2expo);
return res;
end Equal;
function "<" ( f1 : double_float; f2 : Floating_Number ) return boolean is
ff1 : Floating_Number := Create(f1);
res : boolean := (ff1 < f2);
begin
Clear(ff1);
return res;
end "<";
function "<" ( f1 : Floating_Number; f2 : double_float ) return boolean is
ff2 : Floating_Number := Create(f2);
res : boolean := (f1 < ff2);
begin
Clear(ff2);
return res;
end "<";
function "<" ( f1,f2 : Floating_Number ) return boolean is
res : boolean;
f1deci : constant natural := Decimal_Places(f1.fraction);
f2deci : constant natural := Decimal_Places(f2.fraction);
f1expo : Integer_Number := f1.exponent + f1deci;
f2expo : Integer_Number := f2.exponent + f2deci;
mulfra : Integer_Number;
begin
if (f1expo < f2expo)
then if Sign(f2.fraction) > 0
then res := true;
elsif Sign(f2.fraction) < 0
then res := false;
else res := (Sign(f1.fraction) < 0);
end if;
elsif (f1expo > f2expo)
then if Sign(f1.fraction) > 0
then res := false;
elsif Sign(f1.fraction) < 0
then res := true;
else res := (Sign(f2.fraction) > 0);
end if;
else if f1deci = f2deci
then res := (f1.fraction < f2.fraction);
else if f1deci < f2deci
then mulfra := f1.fraction*10;
for i in 1..(f2deci-f1deci-1) loop
Mul(mulfra,10);
end loop;
res := (mulfra < f2.fraction);
else mulfra := f2.fraction*10;
for i in 1..(f1deci-f2deci-1) loop
Mul(mulfra,10);
end loop;
res := (f1.fraction < mulfra);
end if;
Clear(mulfra);
end if;
end if;
Clear(f1expo); Clear(f2expo);
return res;
end "<";
function ">" ( f1 : double_float; f2 : Floating_Number ) return boolean is
ff1 : Floating_Number := Create(f1);
res : boolean := (ff1 > f2);
begin
Clear(ff1);
return res;
end ">";
function ">" ( f1 : Floating_Number; f2 : double_float ) return boolean is
ff2 : Floating_Number := Create(f2);
res : boolean := (f1 > ff2);
begin
Clear(ff2);
return res;
end ">";
function ">" ( f1,f2 : Floating_Number ) return boolean is
res : boolean;
f1deci : constant natural := Decimal_Places(f1.fraction);
f2deci : constant natural := Decimal_Places(f2.fraction);
f1expo : Integer_Number := f1.exponent + f1deci;
f2expo : Integer_Number := f2.exponent + f2deci;
mulfra : Integer_Number;
begin
if (f1expo > f2expo)
then if Sign(f1.fraction) > 0
then res := true;
elsif Sign(f1.fraction) < 0
then res := false;
else res := (Sign(f2.fraction) < 0);
end if;
elsif (f1expo < f2expo)
then if Sign(f2.fraction) > 0
then res := false;
elsif Sign(f2.fraction) < 0
then res := true;
else res := (Sign(f1.fraction) > 0);
end if;
else if f1deci = f2deci
then res := (f1.fraction > f2.fraction);
else if f1deci < f2deci
then mulfra := f1.fraction*10;
for i in 1..(f2deci-f1deci-1) loop
Mul(mulfra,10);
end loop;
res := (mulfra > f2.fraction);
else mulfra := f2.fraction*10;
for i in 1..(f1deci-f2deci-1) loop
Mul(mulfra,10);
end loop;
res := (f1.fraction > mulfra);
end if;
Clear(mulfra);
end if;
end if;
Clear(f1expo); Clear(f2expo);
return res;
end ">";
procedure Copy ( f1 : in Floating_Number; f2 : in out Floating_Number ) is
begin
Clear(f2);
Copy(f1.fraction,f2.fraction);
Copy(f1.exponent,f2.exponent);
end Copy;
-- EXPANDING AND SHORTENING THE MANTISSA :
function Expand ( i : Integer_Number; k : natural )
return Array_of_Naturals is
-- DESCRIPTION :
-- Returns the expanded coefficient vector of i.
cff : constant Array_of_Naturals := Coefficients(Unsigned(i));
res : Array_of_Naturals(cff'first..cff'last+k);
begin
res(cff'range) := cff(cff'range);
res(cff'last+1..res'last) := (cff'last+1..res'last => 0);
return res;
end Expand;
procedure Truncate ( i : in Integer_Number; k : in natural;
trc : out Array_of_Naturals; exp : out integer ) is
-- DESCRIPTION :
-- On return is the truncated coefficient vector of i and the number
-- of decimal places that are lost, or gained when exp is positive.
n : Natural_Number;
ns : natural; -- #shifts = #decimal places gained
begin
Copy(Unsigned(i),n);
Shift_Left(n,ns);
exp := k*Multprec_Natural_Numbers.Exponent - ns;
declare
cff : constant Array_of_Naturals := Coefficients(n);
begin
for i in trc'range loop
trc(i) := cff(i+k);
end loop;
Clear(n);
end;
end Truncate;
procedure Truncate ( i : in out Integer_Number; k : in natural;
exp : out integer ) is
n : Natural_Number := Unsigned(i);
neg : constant boolean := Negative(i);
ns : natural;
newint : Integer_Number;
begin
Shift_Left(n,ns);
exp := k*Multprec_Natural_Numbers.Exponent - ns;
declare
cff : constant Array_of_Naturals := Coefficients(n);
trc : Array_of_Naturals(cff'first..cff'last-k);
begin
for i in trc'range loop
trc(i) := cff(i+k);
end loop;
newint := Create(trc);
i := newint; --Copy(newint,i); --Clear(newint);
if neg
then Min(i);
end if;
end;
Clear(n);
end Truncate;
procedure Round ( i : in Integer_Number; k : in natural;
trc : out Array_of_Naturals; exp : out integer ) is
-- DESCRIPTION :
-- On return is the rounded coefficient vector of i and the number
-- of decimal places that are lost, or gained when exp is positive.
n : Natural_Number := Unsigned(i);
ns : natural; -- #shifts = #decimal places gained
begin
Shift_Left(n,ns);
exp := k*Multprec_Natural_Numbers.Exponent - ns;
declare
cff : constant Array_of_Naturals := Coefficients(n);
begin
for i in trc'range loop
trc(i) := cff(i+k);
end loop;
if k > 0
then if cff(k-1) >= Multprec_Natural_Numbers.Base/2
then trc(0) := trc(0)+1;
end if;
end if;
end;
Clear(n);
end Round;
function Expand ( f : Floating_Number; k : natural ) return Floating_Number is
res : Floating_Number;
cff : constant Array_of_Naturals := Expand(f.fraction,k);
begin
res.fraction := Create(Create(cff));
if Negative(f.fraction)
then Min(res.fraction);
end if;
Copy(f.exponent,res.exponent);
Normalize(res);
return res;
end Expand;
procedure Expand ( f : in out Floating_Number; k : in natural ) is
cff : constant Array_of_Naturals := Expand(f.fraction,k);
neg : constant boolean := Negative(f.fraction);
begin
Clear(f.fraction);
f.fraction := Create(Create(cff));
if neg
then Min(f.fraction);
end if;
Normalize(f);
end Expand;
function Round ( f : Floating_Number ) return double_float is
res : double_float;
szf,ns : natural;
n : Natural_Number;
expo : Integer_Number;
begin
if (Empty(f.fraction) or else Equal(f.fraction,0))
then res := 0.0;
else Copy(Unsigned(f.fraction),n);
Shift_Left(n,ns);
expo := f.exponent - ns;
szf := Size(n);
while Coefficient(n,szf) = 0 and szf > 0 loop
szf := szf - 1;
end loop;
res := double_float(Coefficient(n,szf));
if szf >= 1
then res := res*double_float(Multprec_Natural_Numbers.Base)
+ double_float(Coefficient(n,szf-1));
if szf >= 2
then if Coefficient(n,szf-2) > Multprec_Natural_Numbers.Base/2
then res := res+1.0;
end if;
ns := (szf - 1)*Multprec_Natural_Numbers.Exponent;
Add(expo,ns);
end if;
end if;
Adjust_Expo(res,expo);
Clear(n); Clear(expo);
end if;
return res;
end Round;
function Round ( f : Floating_Number; k : natural ) return Floating_Number is
res : Floating_Number;
cff : Array_of_Naturals(0..(Size(f.fraction)-k));
exp : integer;
begin
Round(f.fraction,k,cff,exp);
res.fraction := Create(Create(cff));
if Negative(f.fraction)
then Min(res.fraction);
end if;
Copy(f.exponent,res.exponent);
Add(res.exponent,exp);
Normalize(res);
return res;
end Round;
procedure Round ( f : in out Floating_Number; k : in natural ) is
exp : integer;
n : Natural_Number;
neg : constant boolean := Negative(f.fraction);
ns : natural;
begin
Copy(Unsigned(f.fraction),n);
Shift_Left(n,ns);
exp := k*Multprec_Natural_Numbers.Exponent - ns;
declare
cff : constant Array_of_Naturals := Coefficients(n);
trc : Array_of_Naturals(cff'first..cff'last-k);
begin
for i in trc'range loop
trc(i) := cff(i+k);
end loop;
if k > 0
then if cff(k-1) >= Multprec_Natural_Numbers.Base/2
then trc(0) := trc(0)+1;
end if;
end if;
Clear(f.fraction);
f.fraction := Create(trc);
if neg
then Min(f.fraction);
end if;
end;
Clear(n);
Add(f.exponent,exp);
Normalize(f);
end Round;
function Trunc ( f : Floating_Number ) return double_float is
res : double_float;
szf,ns : natural;
n : Natural_Number;
expo : Integer_Number;
begin
if (Empty(f.fraction) or else Equal(f.fraction,0))
then res := 0.0;
else n := Unsigned(f.fraction);
Shift_Left(n,ns);
expo := f.exponent - ns;
szf := Size(n);
while Coefficient(n,szf) = 0 and szf > 0 loop
szf := szf - 1;
end loop;
res := double_float(Coefficient(f.fraction,szf));
if szf >= 1
then res := res*double_float(Multprec_Natural_Numbers.Base)
+ double_float(Coefficient(f.fraction,szf-1));
if szf >= 2
then ns := (szf - 1)*Multprec_Natural_Numbers.Exponent;
Add(expo,ns);
end if;
end if;
Adjust_Expo(res,expo);
Clear(n); Clear(expo);
end if;
return res;
end Trunc;
function Trunc ( f : Floating_Number; k : natural ) return Floating_Number is
res : Floating_Number;
cff : Array_of_Naturals(0..(Size(f.fraction)-k));
exp : integer;
begin
Truncate(f.fraction,k,cff,exp);
res.fraction := Create(Create(cff));
if Negative(f.fraction)
then Min(res.fraction);
end if;
Copy(f.exponent,res.exponent);
Add(res.exponent,exp);
return res;
end Trunc;
procedure Trunc ( f : in out Floating_Number; k : in natural ) is
exp : integer;
n : Natural_Number;
neg : constant boolean := Negative(f.fraction);
ns : natural;
begin
Copy(Unsigned(f.fraction),n);
Shift_Left(n,ns);
exp := k*Multprec_Natural_Numbers.Exponent - ns;
declare
cff : constant Array_of_Naturals := Coefficients(n);
trc : Array_of_Naturals(cff'first..cff'last-k);
begin
for i in trc'range loop
trc(i) := cff(i+k);
end loop;
Clear(f.fraction);
f.fraction := Create(trc);
if neg
then Min(f.fraction);
end if;
end;
Clear(n);
Add(f.exponent,exp);
end Trunc;
procedure Set_Size ( f : in out Floating_Number; k : in natural ) is
sz : constant natural := Size_Fraction(f);
begin
if sz > k
then Round(f,sz-k);
elsif sz < k
then Expand(f,k-sz);
end if;
end Set_Size;
-- ARITHMETIC OPERATIONS as functions (no data sharing) :
function "+" ( f1 : Floating_Number; f2 : double_float )
return Floating_Number is
ff2 : Floating_Number := Create(f2);
res : Floating_Number := f1+ff2;
begin
Clear(ff2);
return res;
end "+";
function "+" ( f1 : double_float; f2 : Floating_Number )
return Floating_Number is
begin
return f2+f1;
end "+";
function "+" ( f1,f2 : Floating_Number ) return Floating_Number is
res : Floating_Number;
maxsz,diff_size,max_diff : integer;
diff_expo : Integer_Number;
cnt : natural;
begin
if (Empty(f1.fraction) or else Equal(f1.fraction,0))
then Copy(f2,res);
elsif (Empty(f2.fraction) or else Equal(f2.fraction,0))
then Copy(f1,res);
else maxsz := Max_Size(f1.fraction,f2.fraction) + 1;
if Equal(f1.exponent,f2.exponent)
then res.fraction := f1.fraction + f2.fraction;
Copy(f1.exponent,res.exponent);
else diff_expo := f1.exponent - f2.exponent;
max_diff := maxsz*Multprec_Natural_Numbers.Exponent;
if diff_expo > 0
then Copy(f1.fraction,res.fraction);
if diff_expo < 2*max_diff
then cnt := Create(diff_expo);
for i in 1..cnt loop
Mul(res.fraction,10);
end loop;
Add(res.fraction,f2.fraction);
Copy(f2.exponent,res.exponent);
else Copy(f1.exponent,res.exponent);
end if;
else Copy(f2.fraction,res.fraction);
Min(diff_expo);
if diff_expo < 2*max_diff
then cnt := Create(diff_expo);
for i in 1..cnt loop
Mul(res.fraction,10);
end loop;
Add(res.fraction,f1.fraction);
Copy(f1.exponent,res.exponent);
else Copy(f2.exponent,res.exponent);
end if;
end if;
Clear(diff_expo);
end if;
diff_size := Size(res.fraction) + 1 - maxsz;
if diff_size > 0
then Round(res,diff_size);
else Normalize(res);
end if;
end if;
return res;
end "+";
function "+" ( f : Floating_Number ) return Floating_Number is
res : Floating_Number;
begin
Copy(f,res);
return res;
end "+";
function "-" ( f : Floating_Number ) return Floating_Number is
res : Floating_Number;
begin
Copy(f,res);
Min(res.fraction);
return res;
end "-";
function "-" ( f1 : Floating_Number; f2 : double_float )
return Floating_Number is
minf2 : double_float := -f2;
res : Floating_Number := f1+minf2;
begin
return res;
end "-";
function "-" ( f1 : double_float; f2 : Floating_Number )
return Floating_Number is
ff1 : Floating_Number := Create(f1);
res : Floating_Number := ff1 - f2;
begin
Clear(ff1);
return res;
end "-";
function "-" ( f1,f2 : Floating_Number ) return Floating_Number is
res,minf2 : Floating_Number;
begin
minf2.exponent := f2.exponent;
minf2.fraction := -f2.fraction;
res := f1 + minf2;
Clear(minf2.fraction);
return res;
end "-";
function "*" ( f1 : Floating_Number; f2 : double_float )
return Floating_Number is
ff2 : Floating_Number := Create(f2);
res : Floating_Number := f1*ff2;
begin
Clear(ff2);
return res;
end "*";
function "*" ( f1 : double_float; f2 : Floating_Number )
return Floating_Number is
ff1 : Floating_Number := Create(f1);
res : Floating_Number := ff1*f2;
begin
Clear(ff1);
return res;
end "*";
function "*" ( f1,f2 : Floating_Number ) return Floating_Number is
res : Floating_Number;
diffsize : integer;
begin
if not (Empty(f1.fraction) or else Equal(f1.fraction,0))
then if not (Empty(f2.fraction) or else Equal(f2.fraction,0))
then res.fraction := f1.fraction*f2.fraction;
res.exponent := f1.exponent+f2.exponent;
diffsize := Size(res.fraction)
- Max_Size(f1.fraction,f2.fraction);
if diffsize > 0
then Round(res,diffsize);
end if;
Normalize(res);
end if;
end if;
return res;
end "*";
function "**" ( f : double_float; n : Natural_Number )
return Floating_Number is
ff : Floating_Number := Create(f);
res : Floating_Number := ff**n;
begin
Clear(ff);
return res;
end "**";
function "**" ( f : Floating_Number; n : Natural_Number )
return Floating_Number is
res : Floating_Number;
cnt : Natural_Number;
begin
if (Empty(n) or else Equal(n,0))
then res := Create(1);
else Copy(f,res);
cnt := Create(1);
while cnt < n loop
Mul(res,f);
Add(cnt,1);
end loop;
Clear(cnt);
Normalize(res);
end if;
return res;
end "**";
function "**" ( f : Floating_Number; i : integer ) return Floating_Number is
res : Floating_Number;
begin
if i = 0
then res := Create(1.0);
else if i > 0
then Copy(f,res);
for j in 1..(i-1) loop
Mul(res,f);
end loop;
else res := Create(1);
for j in 1..(-i) loop
Div(res,f);
end loop;
end if;
Normalize(res);
end if;
return res;
end "**";
function "**" ( f : double_float; i : Integer_Number )
return Floating_Number is
ff : Floating_Number := Create(f);
res : Floating_Number := ff**i;
begin
Clear(ff);
return res;
end "**";
function "**" ( f : Floating_Number; i : Integer_Number )
return Floating_Number is
res : Floating_Number;
cnt,n : Natural_Number;
begin
if (Empty(i) or else Equal(i,0))
then res := Create(1);
else n := Unsigned(i);
if i > 0
then Copy(f,res);
cnt := Create(1);
while cnt < n loop
Mul(res,f);
Add(cnt,1);
end loop;
else res := Create(1);
cnt := Create(0);
while cnt < n loop
Div(res,f);
Add(cnt,1);
end loop;
end if;
Clear(cnt);
Normalize(res);
end if;
return res;
end "**";
function "/" ( f1 : Floating_Number; f2 : double_float )
return Floating_Number is
ff2 : Floating_Number := Create(f2);
res : Floating_Number := f1/ff2;
begin
Clear(ff2);
return res;
end "/";
function "/" ( f1 : double_float; f2 : Floating_Number )
return Floating_Number is
ff1 : Floating_Number := Create(f1);
res : Floating_Number := ff1/f2;
begin
Clear(ff1);
return res;
end "/";
function Pos_Div ( f1,f2 : Floating_Number ) return Floating_Number is
-- DESCRIPTION :
-- This division only applies when f1 and f2 are both positive.
res : Floating_Number;
rmd_frac,new_rmd_frac : Integer_Number;
diffsize : integer;
maxsz : natural := Max_Size(f1.fraction,f2.fraction);
begin
Div(f1.fraction,f2.fraction,res.fraction,rmd_frac);
res.exponent := f1.exponent - f2.exponent;
diffsize := Size(res.fraction) - maxsz;
if not Equal(rmd_frac,0)
then while diffsize <= 0 loop
while rmd_frac < f2.fraction loop
Mul(rmd_frac,10);
Mul(res.fraction,10);
Sub(res.exponent,1);
end loop;
Div(rmd_frac,f2.fraction,new_rmd_frac);
Add(res.fraction,rmd_frac);
Clear(rmd_frac); rmd_frac := new_rmd_frac;
diffsize := Size(res.fraction) - maxsz;
exit when Equal(rmd_frac,0);
end loop;
end if;
Clear(rmd_frac);
if diffsize > 0
then Round(res,diffsize);
end if;
Normalize(res);
return res;
end Pos_Div;
function "/" ( f1,f2 : Floating_Number ) return Floating_Number is
res,minf1,minf2 : Floating_Number;
begin
if not (Empty(f1.fraction) or else Equal(f1.fraction,0))
then if not (Empty(f2.fraction) or else Equal(f2.fraction,0))
then if Multprec_Integer_Numbers.Positive(f1.fraction)
then if Multprec_Integer_Numbers.Positive(f2.fraction)
then res := Pos_Div(f1,f2);
else minf2.fraction := -f2.fraction;
minf2.exponent := f2.exponent;
res := Pos_Div(f1,minf2);
Clear(minf2.fraction);
Min(res);
end if;
else minf1.fraction := -f1.fraction;
minf1.exponent := f1.exponent;
if Multprec_Integer_Numbers.Positive(f2.fraction)
then res := Pos_Div(minf1,f2);
Min(res);
else minf2.fraction := -f2.fraction;
minf2.exponent := f2.exponent;
res := Pos_Div(minf1,minf2);
Clear(minf2.fraction);
end if;
Clear(minf1.fraction);
end if;
else raise NUMERIC_ERROR;
end if;
end if;
return res;
end "/";
-- ARITHMETIC OPERATIONS as procedures for memory management :
procedure Add ( f1 : in out Floating_Number; f2 : in double_float ) is
ff2 : Floating_Number := Create(f2);
begin
Add(f1,ff2);
Clear(ff2);
end Add;
procedure Add ( f1 : in out Floating_Number; f2 : in Floating_Number ) is
res : Floating_Number;
maxsz,diff_size,max_diff : integer;
diff_expo : Integer_Number;
cnt : natural;
begin
if (Empty(f1.fraction) or else Equal(f1.fraction,0))
then Copy(f2,f1);
elsif (Empty(f2.fraction) or else Equal(f2.fraction,0))
then null;
else maxsz := Max_Size(f1.fraction,f2.fraction) + 1;
if Equal(f1.exponent,f2.exponent)
then Add(f1.fraction,f2.fraction);
else diff_expo := f1.exponent - f2.exponent;
max_diff := maxsz*Multprec_Natural_Numbers.Exponent;
if diff_expo > 0
then if diff_expo < 2*max_diff
then cnt := Create(diff_expo);
for i in 1..cnt loop
Mul(f1.fraction,10);
end loop;
Add(f1.fraction,f2.fraction);
Copy(f2.exponent,f1.exponent);
else null;
end if;
else Copy(f2.fraction,res.fraction);
Min(diff_expo);
if diff_expo < 2*max_diff
then cnt := Create(diff_expo);
for i in 1..cnt loop
Mul(res.fraction,10);
end loop;
Add(f1.fraction,res.fraction);
Clear(res.fraction);
else Copy(f2.exponent,f1.exponent);
Clear(f1.fraction);
f1.fraction := res.fraction;
end if;
end if;
Clear(diff_expo);
end if;
diff_size := Size(f1.fraction) + 1 - maxsz;
if diff_size > 0
then Round(f1,diff_size);
else Normalize(f1);
end if;
end if;
end Add;
procedure Sub ( f1 : in out Floating_Number; f2 : in double_float ) is
minf2 : double_float := -f2;
begin
Add(f1,minf2);
end Sub;
procedure Sub ( f1 : in out Floating_Number; f2 : in Floating_Number ) is
minf2 : Floating_Number;
begin
minf2.exponent := f2.exponent;
minf2.fraction := -f2.fraction;
Add(f1,minf2);
Clear(minf2.fraction);
end Sub;
procedure Min ( f : in out Floating_Number ) is
begin
Min(f.fraction);
end Min;
procedure Mul ( f1 : in out Floating_Number; f2 : in double_float ) is
ff2 : Floating_Number := Create(f2);
begin
Mul(f1,ff2);
Clear(ff2);
end Mul;
procedure Mul ( f1 : in out Floating_Number; f2 : in Floating_Number ) is
diffsize,maxsize : integer;
begin
if Empty(f2.fraction)
then Clear(f1);
elsif Equal(f2.fraction,0)
then Clear(f1);
elsif Empty(f1.fraction)
then null;
elsif Equal(f1.fraction,0)
then null;
else maxsize := Max_Size(f1.fraction,f2.fraction);
Mul(f1.fraction,f2.fraction);
Add(f1.exponent,f2.exponent);
diffsize := Size(f1.fraction) - maxsize;
if diffsize > 0
then Round(f1,diffsize);
end if;
Normalize(f1);
end if;
end Mul;
procedure Div ( f1 : in out Floating_Number; f2 : in double_float ) is
ff2 : Floating_Number := Create(f2);
begin
Div(f1,ff2);
Clear(ff2);
end Div;
procedure Pos_Div ( f1 : in out Floating_Number; f2 : in Floating_Number ) is
-- DESCRIPTION :
-- Does the division in case f1 and f2 are both positive.
rmd_frac,new_rmd_frac : Integer_Number;
diffsize : integer;
maxsz : natural := Max_Size(f1.fraction,f2.fraction);
begin
Div(f1.fraction,f2.fraction,rmd_frac);
Sub(f1.exponent,f2.exponent);
diffsize := Size(f1.fraction) - maxsz;
if not Equal(rmd_frac,0)
then while diffsize <= 0 loop
while rmd_frac < f2.fraction loop
Mul(rmd_frac,10);
Mul(f1.fraction,10);
Sub(f1.exponent,1);
end loop;
Div(rmd_frac,f2.fraction,new_rmd_frac);
Add(f1.fraction,rmd_frac);
Clear(rmd_frac); rmd_frac := new_rmd_frac;
diffsize := Size(f1.fraction) - maxsz;
exit when Equal(rmd_frac,0);
end loop;
end if;
Clear(rmd_frac);
if diffsize > 0
then Round(f1,diffsize);
end if;
Normalize(f1);
end Pos_Div;
procedure Div ( f1 : in out Floating_Number; f2 : in Floating_Number ) is
minf1,minf2 : Floating_Number;
begin
if not (Empty(f1.fraction) or else Equal(f1.fraction,0))
then if not (Empty(f2.fraction) or else Equal(f2.fraction,0))
then if Multprec_Integer_Numbers.Positive(f1.fraction)
then if Multprec_Integer_Numbers.Positive(f2.fraction)
then Pos_Div(f1,f2);
else minf2.fraction := -f2.fraction;
minf2.exponent := f2.exponent;
Pos_Div(f1,minf2);
Clear(minf2.fraction); Min(f1);
end if;
else minf1 := -f1;
if Multprec_Integer_Numbers.Positive(f2.fraction)
then Pos_Div(minf1,f2);
Clear(f1); f1 := minf1; Min(f1);
else minf2.fraction := -f2.fraction;
minf2.exponent := f2.exponent;
Pos_Div(minf1,minf2);
Clear(minf2.fraction);
Clear(f1); f1 := minf1;
end if;
end if;
else raise NUMERIC_ERROR;
end if;
end if;
end Div;
-- DESTRUCTOR :
procedure Clear ( f : in out Floating_Number ) is
begin
Clear(f.fraction);
Clear(f.exponent);
end Clear;
end Multprec_Floating_Numbers;