|
|
DataMuseum.dkPresents historical artifacts from the history of: Rational R1000/400 Tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Rational R1000/400 Tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: B T
Length: 110870 (0x1b116)
Types: TextFile
Names: »B«
└─⟦85b835f43⟧ Bits:30000549 8mm tape, Rational 1000, Xlib rev 6.00
└─⟦0c20f784e⟧ »DATA«
└─⟦1abbe589f⟧
└─⟦306851c02⟧
└─⟦this⟧
--/ if R1000 then
with Debug_Tools;
--/ elsif TeleGen2 and then Unix then
--// with Float_Text_Io;
--/ end if;
with Text_Io;
with Xlbt_Arithmetic;
use Xlbt_Arithmetic;
package body Trig is
------------------------------------------------------------------------------
-- Date - /Name/ Comment
--
-- 01-FEB-89 - /GEB/ Created based upon the book
-- - Software Manual for the Elementary Functions by
-- - William J. Cody, Jr. and William Waite
-- - Prentice-Hall Series in Computational Mathematics, 1980
-- 05-JUL-90 - /GEB/ Add structured comments, port to TeleGen2/TeleSoft.
------------------------------------------------------------------------------
--/ if not (TeleGen2 and then Unix) then
package Float_Text_Io is new Text_Io.Float_Io (Float);
--/ end if;
type Float_Array is array (Natural32 range <>) of Float;
Degrees_To_Radians : constant Float := Pi / 180.0;
Sqrt_One_Tenth : constant Float :=
0.316227766016837933199889354443271853371955513727833;
Sqrt_One_Half : constant Float :=
0.7071067811865475244008443621048490392848359375608;
Ln_Float_Large : Float;
Ln_Float_Small : Float;
Ln_2 : constant Float :=
0.693147180559945309417232121458176568075500133107812;
Log10_E : constant Float :=
0.434294481903251827651128918916605082294397005627727;
Ln_10 : constant Float :=
2.30258509299404568401799145468436420760110148794495;
Expx_A1 : Float_Array (1 .. 17);
Expx_A2 : Float_Array (1 .. 8);
Tanh_Xbig : Float;
Cot_Eps1 : Float;
--\f
function Truncate (X : Float) return Float is
------------------------------------------------------------------------------
-- Chop off any non-integral portion of X. We do this by converting it to
-- an "integer" form and then back again without rounding.
------------------------------------------------------------------------------
Result : Float;
Fr : Float := abs X;
Ex : Integer32;
Tmp : Integer32;
Delt : Integer32;
begin
----Anything less than 1.0 in magnitude is 0.0 for our result.
if Fr < 1.0 then
return 0.0;
end if;
----Anything < Integer32'Last can be done using Integer32s.
if Fr < Float (Integer32'Last) then
Tmp := Integer32 (Fr);
if Float (Tmp) > Fr then
Tmp := Tmp - 1;
end if;
if X >= 0.0 then
return Float (Tmp);
else
return -Float (Tmp);
end if;
end if;
----Separate the fraction and the exponent in the number. Each time we take
-- some bit out of the fraction (in order to put them into our result) we
-- will take out out Delt Float'Machine_Radix "digits" worth. This guarantees
-- that we don't overflow our Integer32 temporary.
Fraction_Exponent (abs X, Fr, Ex);
case Float'Machine_Radix is
when 2 =>
Delt := (Integer32'Size - 1);
when 4 =>
Delt := (Integer32'Size - 1) / 2;
when 8 =>
Delt := (Integer32'Size - 1) / 3;
when 16 =>
Delt := (Integer32'Size - 1) / 4;
when 10 =>
Delt := (Integer32'Size - 1) / 4;
when others =>
Delt := 1;
end case;
----Loop extracting "large" chunks of bits from the fraction. Keep placing
-- them into the result. We will be extracting only integral bits.
Result := 0.0;
while Ex > Delt loop
Ex := Ex - Delt;
Fr := Fr * Float (Float'Machine_Radix) ** Integer (Delt);
Tmp := Integer32 (Fr);
if Float (Tmp) > Fr then -- Reverse any rounding affects.
Tmp := Tmp - 1;
end if;
Fr := Fr - Float (Tmp);
Result := Result * Float (Float'Machine_Radix) ** Integer (Delt) +
Float (Tmp);
end loop;
----Remove the last few Ex Float'Machine_Radix "digits" from the fraction.
-- This removes the last of the integral portion of the original number.
Fr := Fr * Float (Float'Machine_Radix) ** Integer (Ex);
Tmp := Integer32 (Fr);
if Float (Tmp) > Fr then
Tmp := Tmp - 1; -- Reverse any rounding affects.
end if;
Result := Result * Float (Float'Machine_Radix) ** Integer (Ex) +
Float (Tmp);
----Return a result with the correct sign.
if X < 0.0 then
return -Result;
else
return Result;
end if;
end Truncate;
--\f
function Truncate (X : Float) return Integer32 is
------------------------------------------------------------------------------
-- Convert the Float to an Integer32; truncate the fraction; do not round.
------------------------------------------------------------------------------
I : Integer32 := Integer32 (X);
begin
if I >= 0 then
if Float (I) > X then
return I - 1;
else
return I;
end if;
else
if Float (I) < X then
return I + 1;
else
return I;
end if;
end if;
end Truncate;
--\f
function Round (X : Float) return Float is
------------------------------------------------------------------------------
-- Chop off any non-integral portion of X. We do this by converting it to
-- an "integer" form and then back again with rounding.
------------------------------------------------------------------------------
Result : Float;
Fr : Float := abs X;
Ex : Integer32;
Tmp : Integer32;
Delt : Integer32;
begin
----Anything < Integer32'Last can be done using Integer32s.
if Fr < Float (Integer32'Last) then
Tmp := Integer32 (Fr);
if X >= 0.0 then
return Float (Tmp);
else
return -Float (Tmp);
end if;
end if;
----Separate the fraction and the exponent in the number. Each time we take
-- some bit out of the fraction (in order to put them into our result) we
-- will take out out Delt Float'Machine_Radix "digits" worth. This guarantees
-- that we don't overflow our Integer32 temporary.
Fraction_Exponent (abs X, Fr, Ex);
case Float'Machine_Radix is
when 2 =>
Delt := (Integer32'Size - 1);
when 4 =>
Delt := (Integer32'Size - 1) / 2;
when 8 =>
Delt := (Integer32'Size - 1) / 3;
when 16 =>
Delt := (Integer32'Size - 1) / 4;
when 10 =>
Delt := (Integer32'Size - 1) / 4;
when others =>
Delt := 1;
end case;
----Loop extracting "large" chunks of bits from the fraction. Keep placing
-- them into the result. We will be extracting only integral bits.
Result := 0.0;
while Ex > Delt loop
Ex := Ex - Delt;
Fr := Fr * Float (Float'Machine_Radix) ** Integer (Delt);
Tmp := Integer32 (Fr);
if Float (Tmp) > Fr then -- Reverse any rounding affects.
Tmp := Tmp - 1;
end if;
Fr := Fr - Float (Tmp);
Result := Result * Float (Float'Machine_Radix) ** Integer (Delt) +
Float (Tmp);
end loop;
----Remove the last few Ex Float'Machine_Radix "digits" from the fraction.
-- This removes the last of the integral portion of the original number.
Fr := Fr * Float (Float'Machine_Radix) ** Integer (Ex);
Tmp := Integer32 (Fr); -- Allow rounding to occur.
Result := Result * Float (Float'Machine_Radix) ** Integer (Ex) +
Float (Tmp);
----Return a result with the correct sign.
if X < 0.0 then
return -Result;
else
return Result;
end if;
end Round;
--\f
function Round (X : Float) return Integer32 is
begin
return Integer32 (X);
end Round;
--\f
procedure Fraction_Exponent (X : Float;
Fraction : out Float;
Exponent : out Integer32) is
------------------------------------------------------------------------------
-- Separate the number into a fraction (0.5 <= abs F < 1.0) and an exponent
-- such that X == Fraction * Float'Machine_Radix ** Exponent
------------------------------------------------------------------------------
F : Float := abs X;
E : Integer32 := 0;
begin
----A zero is 0.0 with 0 exponent.
if X = 0.0 then
Fraction := 0.0;
Exponent := 0;
return;
end if;
----Reduce values > 1.0 to values < 1.0. We scale by Machine_Radix so there
-- is no roundoff error whatsoever.
if F >= 1.0 then
while F >= Float (Float'Machine_Radix) ** 50 loop
E := E + 50;
F := F / Float (Float'Machine_Radix) ** 50;
end loop;
while F >= Float (Float'Machine_Radix) ** 10 loop
E := E + 10;
F := F / Float (Float'Machine_Radix) ** 10;
end loop;
while F >= 1.0 loop
E := E + 1;
F := F / Float (Float'Machine_Radix);
end loop;
----Increase values < 1.0/Machine_Radix to values >= 1.0/Machine_Radix. We
-- scale by Machine_Radix so there is no roundoff error whatsoever.
elsif F < 1.0 / Float (Float'Machine_Radix) then
while F < 1.0 / Float (Float'Machine_Radix) ** 50 loop
E := E - 50;
F := F * Float (Float'Machine_Radix) ** 50;
end loop;
while F < 1.0 / Float (Float'Machine_Radix) ** 10 loop
E := E - 10;
F := F * Float (Float'Machine_Radix) ** 10;
end loop;
while F < 1.0 / Float (Float'Machine_Radix) loop
E := E - 1;
F := F * Float (Float'Machine_Radix);
end loop;
end if;
----Return our results; preserve signs.
if X < 0.0 then
Fraction := -F;
else
Fraction := F;
end if;
Exponent := E;
end Fraction_Exponent;
--\f
function Odd (X : Float) return Boolean is
------------------------------------------------------------------------------
-- Returns TRUE if Aint(X) is an ODD value. Any value < 1.0 is even
-- because it is less than 1;
-- and any value > Float'Machine_Radix ** Float'Machine_Mantissa is
-- even because the even/odd bit has been lost due to insufficient
-- precision in the Float representation.
------------------------------------------------------------------------------
Y : Float := abs X;
Z : Float;
Shift : Integer32 := 0;
Int : Integer32;
begin
----If the value is too small to have an Integer32 value or if it has lost the
-- 1-bit that determines odd-ness then we are de-facto even.
if Y < 1.0 or else
Y >= Float (Float'Machine_Radix) ** Float'Machine_Mantissa then
return False;
end if;
----If necessary we will shift the number around until we can Integer32() it.
if Y >= Float (Integer32'Last) then
----Determine our shift amount. Guarantee that Y mod Z is < Integer32'Last.
case Float'Machine_Radix is
when 2 =>
Z := 2.0 ** (Integer32'Size - 2);
when 4 =>
Z := 4.0 ** ((Integer32'Size - 2) / 2);
when 8 =>
Z := 8.0 ** ((Integer32'Size - 2) / 3);
when 16 =>
Z := 16.0 ** ((Integer32'Size - 1) / 4);
when 10 =>
Z := 10.0 ** 9;
when others =>
raise Program_Error;
end case;
----Keep shifting down until we are small enough to fit in an Integer32 when
-- we are Integer32()'ed. Keep a count of the number of shifts we perform.
while Y >= Float (Integer32'Last) loop
Shift := Shift + 1;
Y := Y / Z;
end loop;
----Now recover those shifts. Remove successive groups of bits until we are
-- left with just the bottom Integer32'Size (more or less) bits from the
-- original Float.
while Shift > 0 loop
Int := Integer32 (Y);
if Float (Int) > Y then
Int := Int - 1;
end if;
Y := Y - Float (Int);
Y := Y * Z;
end loop;
end if;
----Check the last few bits and see if they constitute odd'ness.
Int := Integer32 (Y);
if Float (Int) > Y then
Int := Int - 1;
end if;
if Int rem 2 /= 0 then
return True;
else
return False;
end if;
end Odd;
--\f
function Sqrt (A : Float) return Float is
------------------------------------------------------------------------------
-- Square-Root - returns the positive root of positive numbers
-- - raises Constraint_Error for negative number
-- Based upon elements from:
-- Computer Approximations by John F. Hart et. al.; Krieger Publishing 1968
-- pg 89-96
-- Software Manual for the Elementary Functions by W. J. Cody, Jr. and
-- W. Waite; Prentice-Hall 1980; pg 17-34
------------------------------------------------------------------------------
Adj : Float;
F : Float;
N : Integer32;
Y : Float;
Bits : Natural32;
begin
----We don't do negative numbers and sqrt(0.0) = 0.0.
if A <= 0.0 then
if A < 0.0 then
raise Constraint_Error;
end if;
return 0.0;
end if;
----Break A into a fraction and an exponent.
Fraction_Exponent (A, F, N);
----Compute an approximation of the answer for sqrt(f).
case Float'Machine_Radix is
when 2 =>
Y := 0.41731 + 0.59016 * F;
when others =>
Y := 0.580661 + F * 0.5 - 0.086462 / (F + 0.175241);
end case;
----Now we put back the exponential information.
if N rem 2 /= 0 then
case Float'Machine_Radix is
when 2 =>
Y := Y * 8#0.55202_36314_77473_63110#;
when 4 =>
Y := Y * 4#0.2#;
when 8 =>
Y := Y * 8#0.26501_17146_37635_71444#;
when 10 =>
Y := Y * 0.31622_77660_16837_93320;
when 16 =>
Y := Y * 16#0.4#;
when others =>
raise Program_Error;
end case;
N := N + 1;
end if;
N := N / 2;
Y := Y * Float (Float'Machine_Radix) ** Integer (N);
----Now use Newton's approximation to compute the result of sqrt(A).
Bits := 8; -- Currently valid bits (minimum)
while Bits < Float'Size loop
Y := 0.5 * (Y + A / Y);
Bits := Bits + Bits;
end loop;
----We now have an answer that is correct to within the bottom bit (or two).
-- See if we can improve on that. The Newton's approximation cannot
-- do any better because the hardware does (or does not do) rounding and this
-- introduces a "granularity" to the continuous Newton approximation.
-- So, we will sit and diddle with the bottom bit of the answer. We want a
-- value that when squared is strictly less than our original argument.
F := Y * Y;
if F /= A then
Adj := Float (Float'Machine_Radix) **
Integer (N - Float'Machine_Mantissa);
if not (Float'Machine_Rounds or else Y = Y + Adj / 2.0) or else
not (not Float'Machine_Rounds or else
Y = Y + Adj / 2.00001) or else
not (Y /= Y + Adj) or else not (Y = (Y + Adj) - Adj) then
raise Program_Error;
end if;
----Adj is so small that it only diddles the bottom bit of the
-- mantissa; we so assert.
begin
while F < A loop
Y := Y + Adj;
F := Y * Y;
end loop;
exception
when Numeric_Error =>
----We got an agument that was at/close-to Float'Large
-- Reduce Y back by Adj and return it.
Y := Y - Adj;
return Y;
end;
while F > A loop
Y := Y - Adj;
F := Y * Y;
end loop;
end if;
----Return the correct result.
return Y;
end Sqrt;
--\f
function Cbrt (A : Float) return Float is
------------------------------------------------------------------------------
-- Cube-Root - returns the real root
--
-- Based upon elements from:
-- Computer Approximations by John F. Hart et. al.; Krieger Publishing 1968
-- pg 89-96
-- Software Manual for the Elementary Functions by W. J. Cody, Jr. and
-- W. Waite; Prentice-Hall 1980; pg 17-34
------------------------------------------------------------------------------
Aa : Float := abs A;
Adj : Float;
F : Float;
N : Integer32;
Y : Float;
K : Integer32;
Bits : Natural32;
begin
----cbrt(0.0) = 0.0.
if A = 0.0 then
return 0.0;
end if;
----Break A into a fraction and an exponent.
Fraction_Exponent (Aa, F, N);
----Compute an approximation of the answer.
Y := (((-0.82075_488E-01 * F) + 0.42038_11298) * F + 0.78999_824) * F +
0.43261_46E-01;
Y := Y / (F + 0.17178_3523);
K := N rem 3;
if K > 0 then
----1/cbrt(3) = .69336.....
K := 3 - K;
Y := Y * 7.937005259840997373758528196362E-001 ** Integer (K);
N := N + K;
elsif K < 0 then
Y := Y * 7.937005259840997373758528196362E-001 ** Integer (abs K);
N := N - K;
end if;
N := N / 3;
Y := Y * Float (Float'Machine_Radix) ** Integer (N);
----Each time we do the equation we double our correct digits. We need
-- Float_Digits worth correct. Loop until this is true.
Bits := 8;
while Bits < Float'Size loop
Y := (Y + Y + Aa / (Y * Y)) / 3.0;
Bits := Bits + Bits;
end loop;
----We now have an answer that is correct to within the bottom bit (or two).
-- See if we can improve on that. The Newton's approximation cannot
-- do any better because the hardware does (or does not do) rounding and this
-- introduces a "granularity" to the continuous Newton approximation.
-- So, we will sit and diddle with the bottom bit of the answer. We want a
-- value that when squared is strictly less than our original argument.
F := Y * Y * Y;
if F /= Aa then
Adj := Float (Float'Machine_Radix) **
Integer (N - Float'Machine_Mantissa);
if not (Float'Machine_Rounds or else Y = Y + Adj / 2.0) or else
not (not Float'Machine_Rounds or else
Y = Y + Adj / 2.00001) or else
not (Y /= Y + Adj) or else
not (Y = (Y + Adj) - Adj) then
raise Program_Error;
end if;
----Adj is so small that it only diddles the bottom bit of the
-- mantissa; we so assert.
begin
while F < Aa loop
Y := Y + Adj;
F := Y * Y * Y;
end loop;
exception
when Numeric_Error =>
----We got an agument that was at/close-to Float'Large
-- Reduce Y back by Adj and return it.
Y := Y - Adj;
return Y;
end;
while F > Aa loop
Y := Y - Adj;
F := Y * Y * Y;
end loop;
end if;
----Return the correct result.
if A < 0.0 then
return -Y;
else
return Y;
end if;
end Cbrt;
--\f
function Sin (A : Float) return Float is
R : Float;
F : Float;
G : Float;
Y : Float;
Xn : Float;
Tmp : Float;
Sign : Boolean;
begin
----Get Y := abs A where Rad is also in radians.
if In_Radians then
Y := A;
else
Y := A * Degrees_To_Radians;
end if;
if Y < 0.0 then
Y := -Y;
Sign := True;
else
Sign := False;
end if;
----Check for ridiculously large values of Y.
if Y >= Pi * Float (Float'Machine_Radix) **
(Float'Machine_Mantissa / 2) then
return 0.0;
end if;
----Form XN and check for even/odd-ness.
Xn := Round (Y * 0.31830_98861_83790_67154);
if Odd (Xn) then
Sign := not Sign;
end if;
----Compute the f portion of the argument.
Tmp := Truncate (Y);
if (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 33) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 33) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 33) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 33) then
F := ((Tmp - Xn * 8#3.1104#) + (Y - Tmp)) +
Xn * 8.9089_10206_76153_73566_17E-06;
else
F := ((Tmp - Xn * 8#3.11#) + (Y - Tmp)) - Xn * 9.6765_35897_93E-04;
end if;
----See if there is no point to computing sin(x).
if abs F < Float (Float'Machine_Radix) **
(-Float'Machine_Mantissa / 2) then
if Sign then
return -F;
else
return F;
end if;
end if;
----Compute an answer.
G := F * F;
if (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 51) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 51) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 51) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 51) or else
(Float'Machine_Radix = 10 and then Float'Machine_Mantissa >= 16) then
R := (((((((0.27204_79095_78888_46175E-014 * G -
0.76429_17806_89104_67734E-012) * G +
0.16058_93649_03715_89114E-09) * G -
0.25052_10679_82745_84544E-07) * G +
0.27557_31921_01527_56119E-05) * G -
0.19841_26984_12018_40457E-03) * G +
0.83333_33333_33316_50314E-02) * G -
0.16666_66666_66666_65052E+00) * G;
elsif (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 33) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 33) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 33) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 33) or else
(Float'Machine_Radix = 10 and then
Float'Machine_Mantissa >= 11) then
R := ((((((-0.73706_62775_07114_174E-012 * G +
0.16047_84463_23816_900E-09) * G -
0.25051_87088_34705_760E-07) * G +
0.27557_31642_12926_457E-05) * G -
0.19841_26982_32225_068E-03) * G +
0.8333_33333_27592_139E-02) * G -
0.16666_66666_66659_653E+00) * G;
elsif (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 25) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 25) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 25) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 25) or else
(Float'Machine_Radix = 10 and then
Float'Machine_Mantissa >= 9) then
R := ((((-0.23868_34640_601E-07 * G +
0.27523_97106_775E-05) * G -
0.19840_83282_313E-03) * G +
0.83333_30720_556E-02) * G -
0.16666_66660_883E+00) * G;
else
R := (((0.26019_03036E-05 * G -
0.19807_41872E-03) * G +
0.83330_25139E-02) * G -
0.16666_65668E+00) * G;
end if;
----Now finish off the result.
R := F + F * R;
if Sign then
return -R;
else
return R;
end if;
end Sin;
--\f
function Cos (A : Float) return Float is
R : Float;
F : Float;
G : Float;
Y : Float;
Xn : Float;
Tmp : Float;
Sign : Boolean;
begin
----Get Y := abs A where Rad is also in radians.
if In_Radians then
Y := abs A;
else
Y := abs A * Degrees_To_Radians;
end if;
Y := Y + 1.57079_63267_94896_61923;
Sign := False;
----Check for ridiculously large values of Y.
if Y >= Pi * Float (Float'Machine_Radix) **
(Float'Machine_Mantissa / 2) then
return 0.0;
end if;
----Form XN and check for even/odd-ness.
Xn := Round (Y * 0.31830_98861_83790_67154);
if Odd (Xn) then
Sign := not Sign;
end if;
Xn := Xn - 0.5;
----Compute the f portion of the argument.
Tmp := Truncate (abs A);
if (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 33) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 33) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 33) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 33) then
F := ((Tmp - Xn * 8#3.1104#) + (abs A - Tmp)) +
Xn * 8.9089_10206_76153_73566_17E-06;
else
F := ((Tmp - Xn * 8#3.11#) + (abs A - Tmp)) -
Xn * 9.6765_35897_93E-04;
end if;
----See if there is no point to computing cos(x).
if abs F < Float (Float'Machine_Radix) **
(-Float'Machine_Mantissa / 2) then
if Sign then
return -F;
else
return F;
end if;
end if;
----Compute an answer.
G := F * F;
if (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 51) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 51) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 51) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 51) or else
(Float'Machine_Radix = 10 and then Float'Machine_Mantissa >= 16) then
R := (((((((0.27204_79095_78888_46175E-014 * G -
0.76429_17806_89104_67734E-012) * G +
0.16058_93649_03715_89114E-09) * G -
0.25052_10679_82745_84544E-07) * G +
0.27557_31921_01527_56119E-05) * G -
0.19841_26984_12018_40457E-03) * G +
0.83333_33333_33316_50314E-02) * G -
0.16666_66666_66666_65052E+00) * G;
elsif (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 33) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 33) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 33) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 33) or else
(Float'Machine_Radix = 10 and then
Float'Machine_Mantissa >= 11) then
R := ((((((-0.73706_62775_07114_174E-012 * G +
0.16047_84463_23816_900E-09) * G -
0.25051_87088_34705_760E-07) * G +
0.27557_31642_12926_457E-05) * G -
0.19841_26982_32225_068E-03) * G +
0.8333_33333_27592_139E-02) * G -
0.16666_66666_66659_653E+00) * G;
elsif (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 25) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 25) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 25) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 25) or else
(Float'Machine_Radix = 10 and then
Float'Machine_Mantissa >= 9) then
R := ((((-0.23868_34640_601E-07 * G +
0.27523_97106_775E-05) * G -
0.19840_83282_313E-03) * G +
0.83333_30720_556E-02) * G -
0.16666_66660_883E+00) * G;
else
R := (((0.26019_03036E-05 * G -
0.19807_41872E-03) * G +
0.83330_25139E-02) * G -
0.16666_65668E+00) * G;
end if;
----Now finish off the result.
R := F + F * R;
if Sign then
return -R;
else
return R;
end if;
end Cos;
--\f
function Tan (A : Float) return Float is
Aa : Float;
F : Float;
X1 : Float;
Xnum : Float;
Xden : Float;
Even : Boolean;
Xn : Float;
begin
----Make sure we have the correct units.
if In_Radians then
Aa := A;
else
Aa := A * Degrees_To_Radians;
end if;
F := abs Aa;
----See if our argument is much too large to make any sense.
if F > Truncate (Float (Float'Machine_Radix) **
(Float'Machine_Mantissa / 2) * Pi_Over_2) then
return 0.0;
end if;
----Form XN and check for even/odd-ness.
Xn := Round (Aa * 0.63661_97723_67581_34308);
Even := not Odd (Xn);
----Compute f.
X1 := Truncate (Aa);
if Float'Machine_Radix /= 10 then
F := ((X1 - Xn * 8#1.4442#) + (Aa - X1)) +
Xn * 4.4544_55103_38706_86783_08E-06;
else
F := ((X1 - Xn * 1.57079) + (Aa - X1)) +
Xn * 6.32679489661923132169163975144E-06;
end if;
if not (abs F <= Pi_Over_4) then
raise Program_Error;
end if;
----See if f is very very small.
if abs F < Float (Float'Machine_Radix) **
(-Float'Machine_Mantissa / 2) then
Xnum := F;
Xden := 1.0;
else
X1 := F * F;
if (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 53) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 53) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 53) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 53) or else
(Float'Machine_Radix = 10 and then
Float'Machine_Mantissa >= 17) then
Xnum := (((-0.17861_70734_22544_26711E-04 * X1 +
0.34248_87823_58905_89960E-02) * X1 -
0.13338_35000_64219_60681E+00) * X1) * F + F;
Xden := (((0.49819_43399_37865_12270E-06 * X1 -
0.31181_53190_70100_27307E-03) * X1 +
0.25663_83228_94401_12864E-01) * X1 -
0.46671_68333_97552_94240E+00) * X1 +
0.5;
elsif (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 33) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 33) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 33) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 33) or else
(Float'Machine_Radix = 10 and then
Float'Machine_Mantissa >= 11) then
Xnum := (((-0.74836_34966_61206_5149E-05 * X1 +
0.28059_18241_16998_8906E-02) * X1 -
0.12828_34704_09574_3847E+00) * X1) * F + F;
Xden := ((-0.20844_80442_20387_0948E-03 * X1 +
0.23344_85282_20687_2802E-01) * X1 -
0.46161_68037_42904_8840E+00) * X1 +
0.5;
elsif (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 25) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 25) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 25) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 25) or else
(Float'Machine_Radix = 10 and then
Float'Machine_Mantissa >= 8) then
Xnum := ((0.10751_54738_488E-02 * X1 -
0.11136_14403_566E+00) * X1) * F + F;
Xden := (0.15973_39213_300E-01 * X1 -
0.44469_47720_281E+00) * X1 +
0.5;
else
Xnum := (-0.95801_7723E-01 * X1) * F + F;
Xden := (0.97168_5835E-02 * X1 -
0.42913_5777E+00) * X1 +
0.5;
end if;
Xden := Xden + 0.5;
end if;
----If XN was odd then change sign of result.
if not Even then
Xnum := Xden / (-Xnum);
else
Xnum := Xnum / Xden;
end if;
return Xnum;
end Tan;
--\f
function Sec (A : Float) return Float is
begin
return 1.0 / Cos (A);
end Sec;
--\f
function Csc (A : Float) return Float is
begin
return 1.0 / Sin (A);
end Csc;
--\f
function Cot (A : Float) return Float is
Aa : Float;
F : Float;
X1 : Float;
Xnum : Float;
Xden : Float;
Even : Boolean;
Xn : Float;
begin
----Make sure we have the correct units.
if In_Radians then
Aa := A;
else
Aa := A * Degrees_To_Radians;
end if;
F := abs Aa;
----See if our argument is much too small to handle.
if F < Cot_Eps1 then
if Aa = 0.0 then
return Float'Last;
elsif Aa < 0.0 then
return Float'First;
else
return Float'Last;
end if;
end if;
----See if our argument is much too large to make any sense.
if F > Truncate (Float (Float'Machine_Radix) **
(Float'Machine_Mantissa / 2) * Pi_Over_2) then
return 0.0;
end if;
----Form XN and check for even/odd-ness.
Xn := Round (Aa * 0.63661_97723_67581_34308);
Even := not Odd (Xn);
----Compute f.
X1 := Truncate (Aa);
if Float'Machine_Radix /= 10 then
F := ((X1 - Xn * 8#1.4442#) + (Aa - X1)) +
Xn * 4.4544_55103_38706_86783_08E-06;
else
F := ((X1 - Xn * 1.57079) + (Aa - X1)) +
Xn * 6.32679489661923132169163975144E-06;
end if;
----See if f is very very small.
if abs F < Float (Float'Machine_Radix) **
(-Float'Machine_Mantissa / 2) then
Xnum := F;
Xden := 1.0;
else
X1 := F * F;
if (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 53) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 53) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 53) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 53) or else
(Float'Machine_Radix = 10 and then
Float'Machine_Mantissa >= 17) then
Xnum := (((-0.17861_70734_22544_26711E-04 * X1 +
0.34248_87823_58905_89960E-02) * X1 -
0.13338_35000_64219_60681E+00) * X1) * F + F;
Xden := (((0.49819_43399_37865_12270E-06 * X1 -
0.31181_53190_70100_27307E-03) * X1 +
0.25663_83228_94401_12864E-01) * X1 -
0.46671_68333_97552_94240E+00) * X1 +
0.5;
elsif (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 33) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 33) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 33) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 33) or else
(Float'Machine_Radix = 10 and then
Float'Machine_Mantissa >= 11) then
Xnum := (((-0.74836_34966_61206_5149E-05 * X1 +
0.28059_18241_16998_8906E-02) * X1 -
0.12828_34704_09574_3847E+00) * X1) * F + F;
Xden := ((-0.20844_80442_20387_0948E-03 * X1 +
0.23344_85282_20687_2802E-01) * X1 -
0.46161_68037_42904_8840E+00) * X1 +
0.5;
elsif (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 25) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 25) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 25) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 25) or else
(Float'Machine_Radix = 10 and then
Float'Machine_Mantissa >= 8) then
Xnum := ((0.10751_54738_488E-02 * X1 -
0.11136_14403_566E+00) * X1) * F + F;
Xden := (0.15973_39213_300E-01 * X1 -
0.44469_47720_281E+00) * X1 +
0.5;
else
Xnum := (-0.95801_7723E-01 * X1) * F + F;
Xden := (0.97168_5835E-02 * X1 -
0.42913_5777E+00) * X1 +
0.5;
end if;
Xden := Xden + 0.5;
end if;
----If XN was odd then change sign of result.
if not Even then
Xnum := -Xnum / Xden;
else
Xnum := Xden / Xnum;
end if;
return Xnum;
end Cot;
--\f
function Asin (A : Float) return Float is
Y : Float := abs A;
F : Float;
G : Float;
I : Integer32;
begin
----Very small arguments are equal to the answer.
if Y < Float (Float'Machine_Radix) ** (-Float'Machine_Mantissa / 2) then
I := 0;
G := Y;
else
----Compute the intermediate G value differently depending upon the
-- magnitude of the argument.
if Y > 0.5 then
I := 1;
if Y > 1.0 then
raise Constraint_Error;
end if;
F := ((0.5 - Y) + 0.5) / 2.0;
Y := Sqrt (F);
Y := -(Y + Y);
G := F;
else
I := 0;
G := Y * Y;
end if;
----Approximate our result.
if (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 49) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 49) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 49) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 49) or else
(Float'Machine_Radix = 10 and then
Float'Machine_Mantissa >= 15) then
F := ((((-0.69674_57344_73506_46411E+00 * G +
0.10152_52223_38064_63645E+02) * G -
0.39688_86299_75048_77339E+02) * G +
0.57208_22787_78917_31407E+02) * G -
0.27368_49452_41642_55994E+02) * G
/ (((((G - 0.23823_85915_36702_38830E+02) * G +
0.15095_27084_10306_04719E+03) * G -
0.38186_30336_17501_49284E+03) * G +
0.41714_43024_82604_12556E+03) * G -
0.16421_09671_44985_60795E+03);
elsif (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 37) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 37) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 37) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 37) or else
(Float'Machine_Radix = 10 and then
Float'Machine_Mantissa >= 12) then
F := (((-0.65404_06899_93350_09E+00 * G +
0.59683_15761_77515_34E+01) * G -
0.13428_70791_34253_12E+02) * G +
0.85372_16436_67719_50E+01) * G
/ ((((G - 0.16429_55755_74951_70E+02) * G +
0.68729_59765_38088_06E+02) * G -
0.10362_27318_64014_80E+03) * G +
0.51223_29862_01096_91E+02);
elsif (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 25) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 25) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 25) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 25) or else
(Float'Machine_Radix = 10 and then
Float'Machine_Mantissa >= 8) then
F := ((-0.59450_14419_3246E+00 * G +
0.29058_76237_4859E+01) * G -
0.27516_55529_0596E+01) * G
/ (((G - 0.10333_86707_2113E+02) * G +
0.24864_72896_9164E+02) * G -
0.16509_93320_2424E+02);
else
F := (-0.50440_0557E+00 * G +
0.93393_5835E+00) * G
/ ((G - 0.55484_6723E+01) * G +
0.56036_3004E+01);
end if;
G := Y + Y * F;
----Adjust our answer to a different quadrant if necessary.
if I = 1 then
G := 8#0.62207_73250_42055_06043# +
(8#0.62207_73250_42055_06043# + G);
end if;
end if;
----Return the result with the correct sign.
if not In_Radians then
G := G / Degrees_To_Radians;
end if;
if A < 0.0 then
return -G;
else
return G;
end if;
end Asin;
--\f
function Acos (A : Float) return Float is
Y : Float := abs A;
F : Float;
G : Float;
I : Integer32;
begin
----Very small arguments are equal to the answer.
if Y < Float (Float'Machine_Radix) ** (-Float'Machine_Mantissa / 2) then
I := 1;
G := Y;
else
----Compute the intermediate G value differently depending upon the
-- magnitude of the argument.
if Y > 0.5 then
I := 0;
if Y > 1.0 then
raise Constraint_Error;
end if;
F := ((0.5 - Y) + 0.5) / 2.0;
Y := Sqrt (F);
Y := -(Y + Y);
G := F;
else
I := 1;
G := Y * Y;
end if;
----Approximate our result.
if (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 49) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 49) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 49) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 49) or else
(Float'Machine_Radix = 10 and then
Float'Machine_Mantissa >= 15) then
F := ((((-0.69674_57344_73506_46411E+00 * G +
0.10152_52223_38064_63645E+02) * G -
0.39688_86299_75048_77339E+02) * G +
0.57208_22787_78917_31407E+02) * G -
0.27368_49452_41642_55994E+02) * G
/ (((((G - 0.23823_85915_36702_38830E+02) * G +
0.15095_27084_10306_04719E+03) * G -
0.38186_30336_17501_49284E+03) * G +
0.41714_43024_82604_12556E+03) * G -
0.16421_09671_44985_60795E+03);
elsif (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 37) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 37) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 37) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 37) or else
(Float'Machine_Radix = 10 and then
Float'Machine_Mantissa >= 12) then
F := (((-0.65404_06899_93350_09E+00 * G +
0.59683_15761_77515_34E+01) * G -
0.13428_70791_34253_12E+02) * G +
0.85372_16436_67719_50E+01) * G
/ ((((G - 0.16429_55755_74951_70E+02) * G +
0.68729_59765_38088_06E+02) * G -
0.10362_27318_64014_80E+03) * G +
0.51223_29862_01096_91E+02);
elsif (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 25) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 25) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 25) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 25) or else
(Float'Machine_Radix = 10 and then
Float'Machine_Mantissa >= 8) then
F := ((-0.59450_14419_3246E+00 * G +
0.29058_76237_4859E+01) * G -
0.27516_55529_0596E+01) * G
/ (((G - 0.10333_86707_2113E+02) * G +
0.24864_72896_9164E+02) * G -
0.16509_93320_2424E+02);
else
F := (-0.50440_0557E+00 * G +
0.93393_5835E+00) * G
/ ((G - 0.55484_6723E+01) * G +
0.56036_3004E+01);
end if;
G := Y + Y * F;
end if;
----Adjust our answer to a different quadrant if necessary.
if A < 0.0 then
if I = 1 then
G := 8#0.62207_73250_42055_06043# +
(8#0.62207_73250_42055_06043# + G);
else
G := 8#1.44417_66521_04132_14107# +
(8#1.44417_66521_04132_14107# + G);
end if;
else
if I = 1 then
G := 8#0.62207_73250_42055_06043# +
(8#0.62207_73250_42055_06043# - G);
else
G := -G;
end if;
end if;
----Return the result.
if not In_Radians then
G := G / Degrees_To_Radians;
end if;
return G;
end Acos;
--\f
function Atan (A : Float) return Float is
F : Float;
G : Float;
R : Float;
N : Natural32 range 0 .. 3;
begin
----Reduce the argument to a small value close to zero.
F := abs A;
if F > 1.0 then
F := 1.0 / F;
N := 2;
else
N := 0;
end if;
if F > 8#0.21114_12136_47546_52614# then
F := (((8#0.56663_65641_30231_25163_55# * F - 0.5) - 0.5) + F) /
(8#1.56663_65641_30231_25163_55# + F);
N := N + 1;
end if;
----Approximate the result.
if abs F >= Float (Float'Machine_Radix) **
(-Float'Machine_Mantissa / 2) then
G := F * F;
if (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 51) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 51) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 51) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 51) or else
(Float'Machine_Radix = 10 and then
Float'Machine_Mantissa >= 16) then
R := (((-0.83758_29936_81500_59274E+00 * G -
0.84946_24035_13206_83534E+01) * G -
0.20505_85519_58616_51981E+02) * G -
0.13688_76889_41919_26929E+02) * G
/ ((((G + 0.15024_00116_00285_76121E+02) * G +
0.59578_43614_25973_44465E+02) * G +
0.86157_34959_71302_42515E+02) * G +
0.41066_30668_25757_81263E+02);
elsif (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 33) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 33) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 33) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 33) or else
(Float'Machine_Radix = 10 and then
Float'Machine_Mantissa >= 11) then
R := ((-0.79439_12954_08336_251E+00 * G -
0.42744_49853_67930_329E+01) * G -
0.42743_26720_26241_096E+01) * G
/ (((G + 0.91978_93648_35039_806E+01) * G +
0.20517_13765_64218_456E+02) * G +
0.12822_98016_07919_841E+02);
elsif (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 25) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 25) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 25) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 25) or else
(Float'Machine_Radix = 10 and then
Float'Machine_Mantissa >= 9) then
R := (-0.72002_68488_98E+00 * G -
0.14400_83448_74E+01) * G
/ ((G + 0.47522_25845_99E+01) * G +
0.43202_50389_19E+01);
else
R := (-0.50909_58253E-01 * G -
0.47083_25141E+00) * G
/ (G + 0.14125_00740E+01);
end if;
F := F + F * R;
end if;
----Correct the result based upon the initial range reduction performed above.
if N > 1 then
F := -F;
end if;
case N is
when 0 =>
null;
when 1 =>
F := F + 0.52359_87755_98298_87308;
when 2 =>
F := F + 1.57079_63267_94896_61923;
when 3 =>
F := F + 1.04719_75511_96597_74615;
end case;
----Return a result of the correct sign.
if not In_Radians then
F := F / Degrees_To_Radians;
end if;
if A < 0.0 then
F := -F;
end if;
return F;
end Atan;
--\f
function Asec (A : Float) return Float is
begin
return Acos (1.0 / A);
end Asec;
--\f
function Acsc (A : Float) return Float is
begin
return Asin (1.0 / A);
end Acsc;
--\f
function Acot (A : Float) return Float is
begin
return Atan (1.0 / A);
end Acot;
--\f
function Ln (A : Float) return Float is
------------------------------------------------------------------------------
-- Ln - returns the natural logarithm of its positive argument
--
-- Based upon elements from
-- Software Manual for the Elementary Functions by W. J. Cody, Jr. and
-- W. Waite; Prentice-Hall 1980; pg 35-48
------------------------------------------------------------------------------
F : Float;
N : Integer32;
Znum : Float;
Zden : Float;
begin
----Base=10 systems use the log10 function.
if Float'Machine_Radix = 10 then
return Log10 (A) / Log10_E;
else
----Negative arguments are errors. A 0.0 argument has an "easy" answer.
if A < 0.0 then
raise Constraint_Error;
end if;
if A = 0.0 then
raise Numeric_Error;
end if;
----Extract the fraction and the exponent from the argument. Adjust them
-- so that 0.5 <= f < 1.0. We want the exponent expressed as a power of
-- 2.0.
Fraction_Exponent (A, F, N);
case Float'Machine_Radix is
when 2 =>
null;
when 4 =>
N := N * 2;
while F < 0.5 loop
F := F + F;
N := N - 1;
end loop;
when 8 =>
N := N * 3;
while F < 0.5 loop
F := F + F;
N := N - 1;
end loop;
when 16 =>
N := N * 4;
while F < 0.5 loop
F := F + F;
N := N - 1;
end loop;
when others =>
raise Program_Error;
end case;
----Now we adjust N and z if f <= sqrt(0.5) and we just adjust z if
-- f > sqrt(0.5).
if F > Sqrt_One_Half then
Znum := (F - 0.5) - 0.5;
Zden := F * 0.5 + 0.5;
else
N := N - 1;
Znum := F - 0.5;
Zden := Znum * 0.5 + 0.5;
end if;
----Now we evaluate a rational approximation of exp(z).
Znum := Znum / Zden;
F := Znum * Znum;
if (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 49) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 49) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 49) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 49) then
Zden :=
((-0.78956_11288_74912_57267E+00 * F +
0.16383_94356_30215_34222E+02)
* F - 0.64124_94342_37455_81147E+02)
/ (((F - 0.35667_97773_90346_46171E+02)
* F + 0.31203_22209_19245_32844E+03)
* F - 0.76949_93210_84948_79777E+03);
elsif (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 33) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 33) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 33) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 33) then
Zden :=
((F * 0.44445_51510_98033_23E-02 -
0.63260_86623_38596_65E+00)
* F + 0.37339_16896_31608_66E+01) /
((F - 0.14312_35435_58853_24E+02)
* F + 0.44807_00275_57364_36E+02);
elsif (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 25) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa >= 25) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa >= 25) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa >= 25) then
Zden := (F * 0.13600_95468_621E-01 - 0.46490_62303_464E+00) /
(F - 0.55788_73750_242E+01);
else
Zden := (-0.555270_74855E+00) / (F - 0.66327_18214E+01);
end if;
F := Znum + Znum * (F * Zden);
----Now compute the result.
Znum := Float (N);
F := (-2.12194_44005_46905_827679E-04 * Znum + F);
F := F + Znum * 8#0.543#;
return F;
end if;
end Ln;
--\f
function Log10 (A : Float) return Float is
------------------------------------------------------------------------------
-- Log10 - returns the base-10 logarithm of its positive argument
--
-- Based upon elements from
-- Software Manual for the Elementary Functions by W. J. Cody, Jr. and
-- W. Waite; Prentice-Hall 1980; pg 35-48
------------------------------------------------------------------------------
F : Float;
N : Integer32;
S : Float;
S2 : Float;
begin
----Base/=10 systems use the ln function.
if Float'Machine_Radix /= 10 then
return Ln (A) / Ln_10;
else
----Negative arguments are errors. A 0.0 argument has an "easy" answer.
if A < 0.0 then
raise Constraint_Error;
end if;
if A = 0.0 then
raise Numeric_Error;
end if;
----Extract the fraction and the exponent from the argument.
Fraction_Exponent (A, F, N);
----Now we adjust N and z if f <= sqrt(0.5) and we just adjust z if
-- f > sqrt(0.5).
if F > Sqrt_One_Tenth then
null;
else
N := N - 1;
F := F * 10.0;
end if;
----Now we evaluate a rational approximation of exp(z).
S := ((F - 0.5) - 0.5) / (F + 1.0);
S2 := S * S;
if Float'Machine_Mantissa >= 16 then
F := ((((-0.74101_07841_61919_23924E+00 * S2 +
0.10333_85715_14793_86456E+02)
* S2 - 0.39273_74102_03156_25018E+02)
* S2 + 0.55408_59120_41205_93097E+02)
* S2 - 0.26044_70024_05557_63612E+02)
/ (((((S2 - 0.19373_23458_32854_78594E+2)
* S2 + 0.10710_97891_15668_00857E+03)
* S2 - 0.24430_30353_41829_54205E+03)
* S2 + 0.24534_76188_68489_34790E+3)
* S2 - 0.89955_20778_81033_11704E+02);
elsif Float'Machine_Mantissa >= 11 then
F := (((-0.71433_38215_32264_273E+00 * S2 +
0.62503_65112_79083_731E+01)
* S2 - 0.13682_37024_15026_896E+02)
* S2 + 0.85167_31987_23885_403E+01)
/ ((((S2 - 0.13210_47835_01562_817E+02)
* S2 + 0.47925_25604_38733_968E+02)
* S2 - 0.64906_68274_09428_483E+02)
* S2 + 0.29415_75017_23226_173E+02);
elsif Float'Machine_Mantissa >= 8 then
F := ((-0.67358_16014_777E+00 * S2 + 0.31630_34915_570E+01)
* S2 - 0.29156_81437_901E+01)
/ (((S2 - 0.81908_00454_670E+01)
* S2 + 0.16966_98140_210E+02)
* S2 - 0.10070_40695_423E+02);
else
F := (-0.60368_24627E+00 * S2 + 0.10756_13712E+01) /
((S2 - 0.43144_78001E+01) * S2 + 0.37150_53570E+01);
end if;
S2 := S2 * F;
F := S * (Log10_E + S2);
----Now compute the result.
F := F + Float (N);
return F;
end if;
end Log10;
--\f
function Logx (X : Float; Y : Float) return Float is
begin
if Float'Machine_Radix /= 10 then
return Ln (Y) / Ln (X);
else
return Log10 (Y) / Log10 (X);
end if;
end Logx;
--\f
function Exp (A : Float) return Float is
------------------------------------------------------------------------------
-- Exp - returns E to the power represented by its argument
--
-- Based upon elements from Computer Approximations by John F. Hart et. al.
-- Krieger Publishing 1968
-- pg 97-105
------------------------------------------------------------------------------
N : Integer32;
Xn : Float;
G : Float;
Xi : Integer32;
X1 : Float;
X2 : Float;
Pz : Float;
Qz : Float;
begin
----Make sure that it is possible to represent the result. (too big/small)
if A > Ln_Float_Large then
raise Numeric_Error;
end if;
if A < Ln_Float_Small then
return 0.0;
end if;
----If the answer will inevitably be 1.0 then return 1.0.
if abs A <
Float (Float'Machine_Radix) ** (-Float'Machine_Mantissa) / 2.0 then
return 1.0;
end if;
----Handle non-base-10 machines here.
if Float'Machine_Radix /= 10 then
----Perform agrument range reduction.
N := Integer32
(A * 1.44269504088896340735992468100189213742664595602385);
Xn := Float (N);
Xi := Integer32 (abs A);
if Float (Xi) > abs A then
Xi := Xi - 1;
end if;
if A < 0.0 then
X1 := -Float (Xi);
else
X1 := Float (Xi);
end if;
X2 := A - X1;
G := ((X1 - Xn * 8#0.543#) + X2) +
Xn * 2.1219_44400_54690_58277E-04;
----Now approximate exp(g)
X1 := G * G;
if (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 57) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 57) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 57) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 57) then
Pz := (0.31555_19276_56846_46356E-04 * X1 +
0.75753_18015_94227_76666E-02) * X1 + 0.25;
Qz := ((0.75104_02839_98700_46114E-06 * X1 +
0.63121_89437_43985_03557E-03) * X1 +
0.56817_30269_85512_21787E-01) * X1 + 0.5;
elsif (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 43) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 43) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 43) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 43) then
Pz := (0.16520_33002_68279_130E-04 * X1 +
0.69436_00015_11792_852E-02) * X1 +
0.24999_99999_99999_993E+00;
Qz := (0.49586_28849_05441_294E-03 * X1 +
0.55553_86669_69001_118E-01) * X1 + 0.5;
elsif (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 30) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 30) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 30) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 30) then
Pz := 0.59504_25497_7591E-02 * X1 + 0.24999_99999_9992E+00;
Qz :=
(0.29729_36368_2238E-03 * X1 + 0.53567_51764_522E-01) * X1 +
0.5;
else
Pz := 0.41602_88626_8E-02 * X1 + 0.24999_99995_0E+00;
Qz := 0.49987_17877_8E-01 * X1 + 0.5;
end if;
Pz := Pz * G;
G := 0.5 + Pz / (Qz - Pz);
----Compute the final result.
N := N + 1;
Xi := N / 2;
N := N - Xi;
G := G * 2.0 ** Integer (Xi);
G := G * 2.0 ** Integer (N);
return G;
----Handle base-10 machines here.
else
----Perform agrument range reduction.
N := Integer32
(A * 0.868588963806503655302257837833210164588794011255454);
Xn := Float (N);
Xi := Integer32 (abs A);
if Float (Xi) > abs A then
Xi := Xi - 1;
end if;
if A < 0.0 then
X1 := -Float (Xi);
else
X1 := Float (Xi);
end if;
X2 := A - X1;
G := ((X1 - Xn * 1.151E+00) + X2) - Xn * 2.9254_64970_22842_009E-04;
----Now approximate exp(g)
X1 := G * G;
if Float'Machine_Mantissa >= 15 then
Pz := (0.42041_42681_37450_31524E+02 * X2 +
0.10097_41487_24273_91798E+05) * X2 +
0.33326_70292_26801_61137E+06;
Qz := ((X2 + 0.84124_35845_14154_54514E+03) * X2 +
0.75739_33461_59883_44395E+05) * X2 +
0.66653_40584_53603_22323E+06;
elsif Float'Machine_Mantissa >= 11 then
Pz := (0.33287_36465_16410_3E-01 * X1 +
0.14008_29975_62819_6E+02) * X1 +
0.50446_48895_05869_7E+03;
Qz := (X1 + 0.11209_40810_96616_9E+03) * X1 +
0.50445_48895_05869_7E+03;
elsif Float'Machine_Mantissa >= 8 then
Pz := 0.20041_43275_526E+02 * X1 + 0.84249_03867_900E+03;
Qz := (X2 + 0.18049_79288_462E+03) * X2 + 0.16849_80773_608E+04;
else
Pz := 0.83046_5413E-01 * X1 + 0.50034_9857E+01;
Qz := X1 + 0.10006_9975E+02;
end if;
Pz := Pz * G;
G := 0.5 + Pz / (Qz - Pz);
G := G + G;
----Compute the final result.
if N rem 2 /= 0 then
if N > 0 then
G :=
G * 3.16227766016837933199889354443271853371955514008093;
else
G :=
G / 3.16227766016837933199889354443271853371955514008093;
end if;
end if;
N := N / 2;
Xi := N / 2;
N := N - Xi;
G := G * 2.0 ** Integer (Xi);
G := G * 2.0 ** Integer (N);
return G;
end if;
end Exp;
--\f
function Exp10 (A : Float) return Float is
begin
return Expx (10.0, A);
end Exp10;
--\f
function Expx (X : Float; Y : Float) return Float is
M : Integer32;
F : Float;
R : Integer32;
P : Integer32;
Z : Float;
Rv : Float;
U1 : Float;
U2 : Float;
Y1 : Float;
Y2 : Float;
Iw1 : Integer32;
W : Float;
W1 : Float;
W2 : Float;
I : Integer32;
N : Integer32;
begin
----We use the conventions where (-f)**g is illegal and f**0.0 is 1.0.
if Y = 0.0 then
return 1.0;
elsif X < 0.0 then
raise Constraint_Error;
end if;
----Here we handle non-base-10 floating point machines.
if Float'Machine_Radix /= 10 then
Fraction_Exponent (X, F, M);
case Float'Machine_Radix is
when 2 =>
null;
when 4 =>
if F < 0.5 then
R := 1;
F := F + F;
else
R := 0;
end if;
when 8 =>
if F < 0.25 then
R := 2;
F := F + F;
F := F + F;
elsif F < 0.5 then
R := 1;
F := F + F;
else
R := 0;
end if;
when 16 =>
if F < 0.125 then
R := 3;
F := F + F;
F := F + F;
F := F + F;
elsif F < 0.25 then
R := 2;
F := F + F;
F := F + F;
elsif F < 0.5 then
R := 1;
F := F + F;
else
R := 0;
end if;
when others =>
raise Program_Error;
end case;
----Compute the P index.
P := 1;
if F <= Expx_A1 (9) then
P := 9;
end if;
if F <= Expx_A1 (P + 4) then
P := P + 4;
end if;
if F <= Expx_A1 (P + 2) then
P := P + 2;
end if;
----Compute z.
if Float'Machine_Radix /= 2 then
Z := F - Expx_A1 (P + 1);
Z := Z - Expx_A2 ((P + 1) / 2);
Z := Z / (F * 0.5 + Expx_A1 (P + 1) * 0.5);
else
Z := F - Expx_A1 (P + 1);
Z := Z - Expx_A2 ((P + 1) / 2);
Z := Z / (F + Expx_A1 (P + 1));
Z := Z + Z;
end if;
----Now compute the z*P(z**2) approximation.
F := Z * Z;
if (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 51) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 51) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 51) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 51) then
Rv := ((0.43445_77567_21631_19635E-03 * F +
0.22321_42128_59242_58967E-02) * F +
0.12500_00000_05037_99174E-01) * F +
0.83333_33333_33332_11405E-01;
elsif (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 37) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 37) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 37) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 37) then
Rv :=
(0.22338_24352_81541_8E-02 * F + 0.12499_99796_50060_8E-01) *
F +
0.83333_33333_41213_6E-01;
elsif (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 25) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 25) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 25) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 25) then
Rv := 0.12506_48500_52E-01 * F + 0.83333_32862_45E-01;
else
Rv := 0.83357_541E-01;
end if;
Rv := Z * F * Rv;
Rv := Rv + 0.44269_50408_88963_40736 * Rv;
U2 := (Rv + Z * 0.44269_50408_88963_40736) + Z;
----Now create W, our partial answer.
case Float'Machine_Radix is
when 2 =>
U1 := Float (M * 16 - P) * 0.0625;
when 4 =>
U1 := Float ((2 * M - R) * 16 - P) * 0.0625;
when 8 =>
U1 := Float ((3 * M - R) * 16 - P) * 0.0625;
when 16 =>
U1 := Float ((4 * M - R) * 16 - P) * 0.0625;
when others =>
raise Program_Error;
end case;
Y1 := Truncate (Y * 16.0) * 0.0625;
Y2 := Y - Y1;
W := U2 * Y + U1 * Y2;
W1 := Truncate (W * 16.0) * 0.0625;
W2 := W - W1;
W := W1 + U1 * Y1;
W1 := Truncate (W * 16.0) * 0.0625;
W2 := W2 + (W - W1);
W := Truncate (W2 * 16.0) * 0.0625;
Iw1 := Truncate (16.0 * (W1 + W));
W2 := W2 - W;
if W2 > 0.0 then
Iw1 := Iw1 + 1;
W2 := W2 - 1.0 / 16.0;
end if;
if Iw1 < 0 then
I := 0;
else
I := 1;
end if;
----Compute the new p,r,m values.
case Float'Machine_Radix is
when 2 =>
M := Iw1 / 16 + I;
P := 16 * M - Iw1;
when 4 =>
N := Iw1 / 16 + I;
P := 16 * N - Iw1;
M := N / 2 + I;
R := 2 * M - N;
when 8 =>
N := Iw1 / 16 + I;
P := 16 * N - Iw1;
M := N / 3 + I;
R := 3 * M - N;
when 16 =>
N := Iw1 / 16 + I;
P := 16 * N - Iw1;
M := N / 4 + I;
R := 4 * M - N;
when others =>
raise Program_Error;
end case;
----Now do Z.
if (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 53) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 53) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 53) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 53) then
Z := ((((((0.14928_85268_05956_08186E-04 * W2 +
0.15400_29044_09897_64601E-03) * W2 +
0.13333_54131_35857_84703E-02) * W2 +
0.96181_29059_51724_16964E-02) * W2 +
0.55504_10866_40855_95326E-01) * W2 +
0.24022_65069_59095_37056E+00) * W2 +
0.69314_71805_59945_29629E+00) * W2;
elsif (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 46) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 46) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 46) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 46) then
Z := (((((0.15077_40617_88142_382E-03 * W2 +
0.13330_81011_34082_075E-02) * W2 +
0.96181_17691_38724_104E-02) * W2 +
0.55504_10842_47568_661E-01) * W2 +
0.24022_65069_56777_522E+00) * W2 +
0.69314_71805_59937_815E+00) * W2;
elsif (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 25) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 25) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 25) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 25) then
Z := ((((0.13052_55159_42810E-02 * W2 +
0.96162_06595_83789E-02) * W2 +
0.55504_04881_30765E-01) * W2 +
0.24022_65061_44710E+00) * W2 +
0.69314_71805_56341E+00) * W2;
else
Z := ((0.54360_383E-01 * W2 +
0.24018_510E+00) * W2 +
0.69314_675E+00) * W2;
end if;
----Nearly there; one more step.
Z := Expx_A1 (P + 1) + Expx_A1 (P + 1) * Z;
if Float'Machine_Radix /= 2 then
Z := Z * 2.0 ** Integer (R);
end if;
I := M / 2;
M := M - I;
Z := Z * Float (Float'Machine_Radix) ** Integer (I);
Z := Z * Float (Float'Machine_Radix) ** Integer (M);
return Z;
----Here we handle base-10 floating point machines.
else
Fraction_Exponent (X, F, M);
----Compute the P index.
P := 1;
while F <= Expx_A1 (P + 2) loop
P := P + 2;
end loop;
----Compute z.
Z := F - Expx_A1 (P + 1);
Z := Z - Expx_A2 ((P + 1) / 2);
Z := Z / (F + Expx_A1 (P + 1));
----Now compute the z*P(z**2) approximation.
F := Z * Z;
if Float'Machine_Mantissa >= 15 then
Rv := ((-0.68650_74087_13682_76474E+00 * F +
0.35829_52156_67236_56966E+01) * F -
0.35184_51552_93711_75192E+01) * F
/ (((F - 0.89628_58940_90517_72560E+01) * F +
0.19666_45902_38905_35938E+02) * F -
0.12152_30114_43221_36016E+02);
elsif Float'Machine_Mantissa >= 9 then
Rv := (-0.62077_57571_87918_2E+00 * F +
0.12095_10556_17031_7E+01) * F
/ ((F - 0.46505_84419_61834_9E+01) * F +
0.41775_01464_74140_2E+01);
else
Rv := -0.48144_78516E+00 * F / (F - 0.16628_73334E+01);
end if;
U2 := Z * (Rv + 0.86858_89638_06503_65530);
----Now create W, our partial answer.
U1 := Float (M * 16 - P) * 0.0625;
Y1 := Truncate (Y * 10.0) * 0.1;
Y2 := Y - Y1;
W := U2 * Y + U1 * Y2;
W1 := Truncate (W * 10.0) * 0.1;
W2 := W - W1;
W := W1 + U1 * Y1;
W1 := Truncate (W * 10.0) * 0.1;
W2 := W2 + (W - W1);
W := Truncate (W2 * 10.0) * 0.1;
Iw1 := Truncate (10.0 * (W1 + W));
W2 := W2 - W;
if Iw1 > 10 * Float'Machine_Emax - 1 then
raise Numeric_Error; -- Result far too large
end if;
if Iw1 < 10 * Float'Machine_Emin + 1 then
return 0.0; -- Result far too small
end if;
if W2 > 0.0 then
Iw1 := Iw1 + 1;
W2 := W2 - 0.1;
end if;
if Iw1 < 0 then
I := 0;
else
I := 1;
end if;
----Compute the new p,m values.
M := Iw1 / 10 + I;
P := 10 * M - Iw1;
----Now do Z.
if Float'Machine_Mantissa >= 15 then
Z := ((((0.41071_57590_70777_89734E+0 * W2 +
0.35616_93889_90563_55495E+01) * W2 +
0.34363_74379_23829_31895E+02) * W2 +
0.28195_17958_42955_14217E+02) * W2 +
0.23539_70807_49261_19272E+03) * W2
/ ((((W2 - 0.10224_89787_60959_10327E+02) * W2 +
0.45994_87860_33907_54883E+02) * W2 -
0.10545_35294_64899_79088E+03) * W2 +
0.10223_16532_25538_32434E+03);
elsif Float'Machine_Mantissa >= 11 then
Z := (((-0.51359_30940_15587_9E+0 * W2 -
0.46710_07431_07040_0E+01) * W2 -
0.57975_91698_28398_6E+01) * W2 -
0.37713_99188_31947_3E+02) * W2
/ (((W2 - 0.63664_36505_45209_5E+01) * W2 +
0.16339_13385_89750_1E+02) * W2 -
0.16378_97856_54144_4E+02);
elsif Float'Machine_Mantissa >= 8 then
Z := ((0.68536_85048_84E+00 * W2 +
0.17805_77775_84E+01) * W2 +
0.82998_14853_06E+01) * W2
/ ((W2 - 0.33766_11203_26E+01) * W2 +
0.36045_63799_45E+01);
else
Z := ((-0.78964_7014E+00 * W2 -
0.21742_4847E+01) * W2 -
0.38883_9832E+01) * W2
/ (W2 - 0.16887_0925E+01);
end if;
----Nearly there; one more step.
Z := Expx_A1 (P + 1) + Expx_A1 (P + 1) * Z;
I := M / 2;
M := M - I;
Z := Z * 10.0 ** Integer (I);
Z := Z * 10.0 ** Integer (M);
return Z;
end if;
end Expx;
--\f
function Sinh (A : Float) return Float is
------------------------------------------------------------------------------
-- Sinh - returns the hyperbolic sine of its argument
------------------------------------------------------------------------------
Y : Float := abs A;
W : Float;
Z : Float;
begin
----SINH for "large" arguments is computed this way.
if Y > 1.0 then
----Base-2 machines can compute things the easy way for "small" arguments.
if Float'Machine_Radix = 2 and then Y <= Ln_Float_Large then
Z := Exp (Y);
Z := (Z * 0.5 - 0.5 / Z);
if A < 0.0 then
return -Z;
else
return Z;
end if;
end if;
----Reduce the argument.
if Float'Machine_Radix /= 10 then
W := Y - 8#0.542714#;
else
W := Y - 0.6932;
end if;
if W > Ln_Float_Large then
raise Numeric_Error;
end if;
----Now take the EXP of the argument and compute the result with corrections
-- based on the machine radix.
Z := Exp (W);
if (Float'Machine_Radix = 10 and then
W <= 1.16 * Float (Float'Machine_Mantissa + 1)) then
Z := Z - 0.24997_35916_74870_15965 / Z;
elsif (Float'Machine_Radix /= 10 and then
Float'Machine_Radix /= 2 and then
W <= 0.35 * Float (Float'Machine_Mantissa + 1)) then
Z := Z - 0.24999_30850_04514_99336 / Z;
end if;
if Float'Machine_Radix /= 10 then
Z := Z + 0.13830_27787_96019_02638E-04 * Z;
else
Z := Z + 0.52820_83502_58748_52469E-04 * Z;
end if;
----Return the result with the correct sign.
if A < 0.0 then
return -Z;
else
return Z;
end if;
----Compute the result for "small" arguments here.
else
if Y < Float (Float'Machine_Radix) **
(-Float'Machine_Mantissa / 2) then
return A;
end if;
Y := A * A;
if (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 51) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 51) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 51) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 51) or else
(Float'Machine_Radix = 10 and then
Float'Machine_Mantissa >= 16) then
W := (((-0.78966_12741_73570_99479E+00 * Y -
0.16375_79820_26307_51372E+03) * Y -
0.11563_52119_68517_68270E+05) * Y -
0.35181_28343_01771_17881E+06) * Y
/ (((Y - 0.27773_52311_96507_01667E+03) * Y +
0.36162_72310_94218_36460E+05) * Y -
0.21108_77005_81062_71242E+07);
elsif (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 41) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 41) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 41) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 41) or else
(Float'Machine_Radix = 10 and then
Float'Machine_Mantissa >= 13) then
W := (((0.77239_39820_29419_23E-02 * Y +
0.13286_42866_92242_29E+01) * Y +
0.85943_28483_85490_10E+02) * Y +
0.23941_43592_30500_69E+04) * Y
/ ((Y - 0.20258_33686_64278_69E+03) * Y +
0.14364_86155_38302_92E+05);
elsif (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 25) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 25) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 25) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 25) or else
(Float'Machine_Radix = 10 and then
Float'Machine_Mantissa >= 8) then
W := ((0.34364_14035_8506E+00 * Y +
0.31359_75645_6058E+02) * Y +
0.10622_28883_7151E+04) * Y
/ ((Y - 0.13051_01250_9199E+03) * Y +
0.63733_73302_1822E+04);
else
W := (-0.19033_3399E+00 * Y - 0.71379_3159E+01) * Y
/ (Y - 0.42827_7109E+02);
end if;
W := A + A * W;
return W;
end if;
end Sinh;
--\f
function Cosh (A : Float) return Float is
------------------------------------------------------------------------------
-- Cosh - returns the hyperbolic cosine of its argument
------------------------------------------------------------------------------
Y : Float := abs A;
W : Float;
Z : Float;
begin
----Base-2 machines can compute things the easy way for "small" arguments.
if (Float'Machine_Radix = 2 and then Y <= Ln_Float_Large) or else
(Float'Machine_Radix /= 2 and then Y <= 1.0) then
Z := Exp (Y);
Z := (Z * 0.5 + 0.5 / Z);
return Z;
end if;
----Reduce the argument.
if Float'Machine_Radix /= 10 then
W := Y - 8#0.542714#;
else
W := Y - 0.6932;
end if;
if W > Ln_Float_Large then
raise Numeric_Error;
end if;
----Now take the EXP of the argument and compute the result with corrections
-- based on the machine radix.
Z := Exp (W);
if (Float'Machine_Radix = 10 and then
W <= 1.16 * Float (Float'Machine_Mantissa + 1)) then
Z := Z + 0.24997_35916_74870_15965 / Z;
elsif (Float'Machine_Radix /= 10 and then
Float'Machine_Radix /= 2 and then
W <= 0.35 * Float (Float'Machine_Mantissa + 1)) then
Z := Z + 0.24999_30850_04514_99336 / Z;
end if;
if Float'Machine_Radix /= 10 then
Z := Z + 0.13830_27787_96019_02638E-04 * Z;
else
Z := Z + 0.52820_83502_58748_52469E-04 * Z;
end if;
----Return the result.
return Z;
end Cosh;
--\f
function Tanh (A : Float) return Float is
------------------------------------------------------------------------------
-- Tanh - returns the hyperbolic tangent of its argument
------------------------------------------------------------------------------
F : Float := abs A;
G : Float;
Result : Float;
begin
----Bigger arguments tend toward 1.0.
if F > Tanh_Xbig then
Result := 1.0;
----Middling big arguments can be best approximated this way.
elsif F > 0.54930_61443_34054_84570 then
Result := 0.5 - 1.0 / (Exp (F + F) + 1.0);
Result := Result + Result;
----Very small arguments result in themselves.
elsif F < Float (Float'Machine_Radix) **
(-Float'Machine_Mantissa / 2) then
Result := F;
----All other arguments get approximated here.
else
G := F * F;
if (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 49) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 49) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 49) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 49) or else
(Float'Machine_Radix = 10 and then
Float'Machine_Mantissa >= 15) then
Result := ((-0.96437_49277_72254_69787E+00 * G -
0.99225_92967_22360_83313E+02) * G -
0.16134_11902_39962_28058E+04) * G
/ (((G + 0.11274_47438_05349_49335E+03) * G +
0.22337_72071_89623_12926E+04) * G +
0.48402_35707_19886_88686E+04);
elsif (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 37) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 37) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 37) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 37) or else
(Float'Machine_Radix = 10 and then
Float'Machine_Mantissa >= 12) then
Result := ((-0.36242_42193_46421_73E-03 * G -
0.92318_68945_14261_77E+00) * G -
0.19059_52242_69822_92E+02) * G
/ ((G + 0.25640_98759_51789_75E+02) * G +
0.57178_56728_09658_17E+02);
elsif (Float'Machine_Radix = 2 and then
Float'Machine_Mantissa >= 25) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 >= 25) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 >= 25) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 >= 25) or else
(Float'Machine_Radix = 10 and then
Float'Machine_Mantissa >= 9) then
Result := (-0.93363_47565_2401E+00 * G -
0.21063_95800_0245E+02)
/ ((G + 0.28077_65347_0471E+02) * G +
0.63191_87401_5582E+02);
else
Result := (-0.38310_10665E-02 * G - 0.82377_28127E+00) * G
/ (G + 0.24713_19654E+01);
end if;
Result := F + F * Result;
end if;
----Return a result with the correct sign.
if A < 0.0 then
return -Result;
else
return Result;
end if;
end Tanh;
--\f
function Sech (A : Float) return Float is
begin
return 1.0 / Cosh (A);
end Sech;
--\f
function Csch (A : Float) return Float is
begin
return 1.0 / Sinh (A);
end Csch;
--\f
function Coth (A : Float) return Float is
begin
return 1.0 / Tanh (A);
end Coth;
--\f
function Asinh (A : Float) return Float is
begin
return Ln (A + Sqrt (A * A + 1.0));
end Asinh;
--\f
function Acosh (A : Float) return Float is
begin
return Ln (A + Sqrt (A * A - 1.0));
end Acosh;
--\f
function Atanh (A : Float) return Float is
begin
return Ln ((1.0 + A) / (1.0 - A)) / 2.0;
end Atanh;
--\f
function Asech (A : Float) return Float is
begin
return Acosh (1.0 / A);
end Asech;
--\f
function Acsch (A : Float) return Float is
begin
return Asinh (1.0 / A);
end Acsch;
--\f
function Acoth (A : Float) return Float is
begin
return Atanh (1.0 / A);
end Acoth;
--\f
function Hex (Dig : Integer32) return Character is
------------------------------------------------------------------------------
-- Returns '0'..'9' or 'A'..'F'; Dig in 0..15.
------------------------------------------------------------------------------
begin
if Dig <= 9 then
return Character'Val (Dig + Character'Pos ('0'));
else
return Character'Val (Dig - 10 + Character'Pos ('A'));
end if;
end Hex;
--\f
function Cat (Frac : Float; Bits : Natural32) return String is
------------------------------------------------------------------------------
-- Convert a fraction that is in the range 1.0/Float'Machine_Radix <= X < 1.0
-- into a bunch of Hex digits with an implicit initial decimal point.
-- This routine is only called when Float'Machine_Radix /= 10
------------------------------------------------------------------------------
Valstr : String (1 .. 4);
I : Integer32;
Nxt : Float;
begin
----Get the next 16 bits off of the top of the fraction.
Nxt := Frac * 16.0 ** 4;
I := Integer32 (Nxt);
if Float (I) > Nxt then
I := I - 1;
end if;
----Remove those 16 bits from the fraction. Do it this "strange" way so that
-- we don't get wobbling-precision problems on base-4/8/16 machines.
Nxt := Frac - Float (I) / 16.0 ** 4;
Nxt := Nxt * 16.0 ** 4;
----Convert the 4 hex digits to a string.
Valstr (1) := Hex (I / 16 ** 3);
Valstr (2) := Hex (I / 16 ** 2 rem 16);
Valstr (3) := Hex (I / 16 rem 16);
Valstr (4) := Hex (I rem 16);
----Get the rest of the digits and return.
if Bits > 16 then
return Valstr & Cat (Nxt, Bits - 16);
else
return Valstr;
end if;
end Cat;
--\f
--/ if R1000 then
function Debug_Tools_Float_Image
(Value : Float;
Level : Natural;
Prefix : String;
Expand_Pointers : Boolean) return String is
------------------------------------------------------------------------------
-- Return a string containing the normal base-10 printed representation of the
-- string and (if Machine_Radix /= 10) the Machine_Radix representation.
------------------------------------------------------------------------------
Frac : Float;
Expo : Integer32;
Str : String (1 .. Float'Digits + 12);
Bits : Natural32;
begin
----Get the base 10 string.
Float_Text_Io.Put (Str, Value, Aft => Float'Digits + 3, Exp => 5);
----Compute the number of bits in the mantissa.
case Float'Machine_Radix is
when 2 =>
Bits := Float'Machine_Mantissa;
when 4 =>
Bits := Float'Machine_Mantissa * 2;
when 8 =>
Bits := Float'Machine_Mantissa * 3;
when 16 =>
Bits := Float'Machine_Mantissa * 4;
when others =>
return Str;
end case;
----Get the fraction and the exponent.
Fraction_Exponent (Value, Frac, Expo);
----Create the string containing the Machine_Radix version of the string and
-- return it plus the base-10 string.
return Str & " 0."
& Cat (Frac, Bits)
& " *" & Natural32'Image (Float'Machine_Radix)
& " **" & Integer32'Image (Expo);
end Debug_Tools_Float_Image;
procedure Register_Float is
new Debug_Tools.Register (Float,
Debug_Tools_Float_Image);
--/ end if; -- R1000
--\f
begin
----Register our preferred debug image routine.
--/ if R1000 then
Register_Float;
--/ end if;
----Ln of the largest and of the smallest numbers that exist.
Ln_Float_Large := Ln (Float'Last);
Ln_Float_Small := Ln (2.0 ** (Float'Machine_Emin - 1));
----Used in argument reduciton in Tanh.
Tanh_Xbig :=
(Ln_2 +
Float (Float'Machine_Mantissa + 1) * Ln (Float (Float'Machine_Radix)))
/ 2.0;
----Cot_Eps1 is smallest positive number that can be reciprocated without
-- Numeric_Error.
if Float'Machine_Emax < -Float'Machine_Emin then
Cot_Eps1 := Float (Float'Machine_Radix) ** (-Float'Machine_Emax + 1);
else
Cot_Eps1 := Float (Float'Machine_Radix) ** (Float'Machine_Emin - 1);
end if;
----Set up arrays of values for the Expx routine. We must do this dynamicly
-- because this package is intended to be portable across architectures and
-- Ada provides us with no way to do this staticly. See pages 98 and 106 of
-- the William J. Cody book for details of what and why.
declare
type Natural32_Array is array (Positive range <>) of Natural32;
procedure Expx_Stuff (A1 : in out Float;
A2 : in out Float;
N1 : Natural32_Array) is
----N1/2/3 represent a floating point value. There are 3*30=90
-- bits of fraction in there. We take those 90 bits and we
-- place the first Float'Machine_Mantissa worth of them into A1
-- and we stick "the rest" into A2. No way to do this at
-- compile time.
Bits : Integer32;
Mask : Integer32;
Shift : Float;
Tmp : Integer;
begin
if Float'Machine_Radix /= 10 then
----Handle all 2**N-base floating points here.
case Float'Machine_Radix is
when 2 =>
Bits := Float'Machine_Mantissa;
when 4 =>
Bits := Float'Machine_Mantissa * 2;
when 8 =>
Bits := Float'Machine_Mantissa * 3;
when 16 =>
Bits := Float'Machine_Mantissa * 4;
when others =>
raise Program_Error;
end case;
if Bits >= 60 then
A1 := Float (N1 (1)) / 2.0 ** 30 +
Float (N1 (2)) / 2.0 ** 60;
Mask := 2 ** Integer (90 - Bits);
A1 := A1 + Float (N1 (3) - N1 (3) rem Mask) / 2.0 ** 90;
A2 := Float (N1 (3) rem Mask) / 2.0 ** 90;
elsif Bits >= 30 then
A1 := Float (N1 (1)) / 2.0 ** 30;
Mask := 2 ** Integer (60 - Bits);
A1 := A1 + Float (N1 (2) - N1 (2) rem Mask) / 2.0 ** 60;
A2 := Float (N1 (2) rem Mask) / 2.0 ** 60 +
Float (N1 (3)) / 2.0 ** 90;
else
Mask := 2 ** Integer (30 - Bits);
A1 := Float (N1 (1) - N1 (1) rem Mask) / 2.0 ** 30;
A2 := Float (N1 (1) rem Mask) / 2.0 ** 30 +
Float (N1 (2)) / 2.0 ** 60;
end if;
else
----Handle base-10 floating-point here.
Shift := 1.0 / 10.0 ** 5;
Bits := 0;
A1 := 0.0;
for I in 1 .. 6 loop
A1 := A1 + Float (N1 (I)) * Shift;
Shift := Shift / 10.0 ** 5;
Bits := Bits + 5;
if Bits + 5 > Float'Machine_Mantissa then
Tmp := I + 1;
goto Do_A2;
end if;
end loop;
A2 := 0.0;
return;
<<Do_A2>> null;
Bits := Float'Machine_Mantissa - Bits;
Mask := 10 ** Integer (5 - Bits);
A1 := A1 + Float (N1 (Tmp) - N1 (Tmp) rem Mask) * Shift;
A2 := Float (N1 (Tmp) rem Mask) * Shift;
for I in Tmp + 1 .. 6 loop
A2 := A2 + Float (N1 (I)) * Shift;
Shift := Shift / 10.0 ** 5;
end loop;
end if;
end Expx_Stuff;
begin
if Float'Machine_Radix /= 10 then
Expx_A1 (1) := 1.0;
Expx_A1 (3) := 8#0.72540_30671_75644_41622_73201_32727#;
Expx_A1 (5) := 8#0.65642_37462_55323_53257_20715_15057#;
Expx_A1 (7) := 8#0.61263_45204_25240_66655_64761_25503#;
Expx_A1 (9) := 8#0.55202_36314_77473_63110_21313_73047#;
Expx_A1 (11) := 8#0.51377_32652_33052_11616_50345_72776#;
Expx_A1 (13) := 8#0.46033_76024_30667_05226_75065_32214#;
Expx_A1 (15) := 8#0.42712_70170_76521_36556_33737_10612#;
Expx_A1 (17) := 8#0.4#;
Expx_Stuff (Expx_A1 (2), Expx_A2 (1),
(8#75222_57505#, 8#22220_66302#, 8#61734_72062#));
Expx_Stuff (Expx_A1 (4), Expx_A2 (2),
(8#70146_33673#, 8#02522_47021#, 8#04062_61124#));
Expx_Stuff (Expx_A1 (6), Expx_A2 (3),
(8#63422_21405#, 8#21760_44016#, 8#17421_53016#));
Expx_Stuff (Expx_A1 (8), Expx_A2 (4),
(8#57204_24347#, 8#65401_41553#, 8#72504_02177#));
Expx_Stuff (Expx_A1 (10), Expx_A2 (5),
(8#53254_07672#, 8#44124_12254#, 8#31114_01243#));
Expx_Stuff (Expx_A1 (12), Expx_A2 (6),
(8#47572_46230#, 8#11064_10432#, 8#66404_42174#));
Expx_Stuff (Expx_A1 (14), Expx_A2 (7),
(8#44341_72334#, 8#72542_16063#, 8#30176_55544#));
Expx_Stuff (Expx_A1 (16), Expx_A2 (8),
(8#41325_30331#, 8#74611_03661#, 8#23056_22556#));
else
Expx_A1 (1) := 1.0;
Expx_A1 (3) := 0.63095_73444_80193_24943_43601_366;
Expx_A1 (5) := 0.39810_71705_53497_25077_02523_051;
Expx_A1 (7) := 0.25118_86431_50958_01110_85032_068;
Expx_A1 (9) := 0.15848_93192_46111_34852_02101_373;
Expx_A1 (11) := 0.1;
Expx_Stuff (Expx_A1 (2), Expx_A2 (1),
(79432, 82347, 24281, 50206, 59182, 82800));
Expx_Stuff (Expx_A1 (4), Expx_A2 (2),
(50118, 72336, 27272, 28500, 15541, 86900));
Expx_Stuff (Expx_A1 (6), Expx_A2 (3),
(31622, 77660, 16837, 93319, 98893, 54400));
Expx_Stuff (Expx_A1 (8), Expx_A2 (4),
(19952, 62314, 96887, 96013, 52455, 39700));
Expx_Stuff (Expx_A1 (10), Expx_A2 (5),
(12589, 25411, 79416, 72104, 23954, 10600));
end if;
end;
----If this is not true then this module will be producing values that are
-- accurate to at-most 60-bits/18-digits. There aren't too many machines
-- with larger floating-point than that but we definitely won't function
-- properly (ie. with the desired accuracy). If you don't care about this
-- then comment out the Assert.
if ((Float'Machine_Radix = 2 and then Float'Machine_Mantissa <= 60) or else
(Float'Machine_Radix = 4 and then
Float'Machine_Mantissa * 2 <= 60) or else
(Float'Machine_Radix = 8 and then
Float'Machine_Mantissa * 3 <= 60) or else
(Float'Machine_Radix = 16 and then
Float'Machine_Mantissa * 4 <= 60) or else
(Float'Machine_Radix = 10 and then Float'Machine_Mantissa <= 18)) then
null;
else
raise Program_Error;
end if;
end Trig;