|
|
DataMuseum.dkPresents historical artifacts from the history of: Rational R1000/400 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Rational R1000/400 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 57344 (0xe000)
Types: Ada Source
Notes: 03_class, FILE, R1k_Segment, e3_tag, package body Generic_Elementary_Functions, seg_0069cf
└─⟦8527c1e9b⟧ Bits:30000544 8mm tape, Rational 1000, Arrival backup of disks in PAM's R1000
└─⟦5a81ac88f⟧ »Space Info Vol 1«
└─⟦this⟧
-- This package body contains an implementation of the proposed standard for
-- elementary mathematical functions, as defined by the ISO-IEC/JTC1/SC22/WG9
-- (Ada) committee (draft 1.2, December 1990)
--
-- Users recognize that the Math Support packages provided as part of the
-- Rational Environment are delivered "AS IS". No warranties are given,
-- whether express, implied, or statutory, including implied warranties of
-- fitness for a particular purpose or mechantability. In no event will
-- Rational be liable in tort, negligence, or other liability incurred as a
-- result of the use of this Math Support packages.
--
-- In addition, Rational does not guarantee conformance to the proposed
-- standards, especially in the accuracy of the results of the various math
-- functions.
--
-- This code can be distributed and modified freely, although Rational
-- would be happy to receive comments, bug reports, and suggestions for
-- improvements at:
-- Rational
-- 3320 Scott Boulevard
-- Santa Clara, CA 95054 USA
-- or by e-mail at:
-- Support@Rational.COM
--
with Primitive_Functions;
package body Generic_Elementary_Functions is
Pi : constant :=
3.1415926535897932384626433832795028841971693993750990042;
Pi_Over_2 : constant := Pi / 2.0;
Pi_Over_4 : constant := Pi / 4.0;
Two_Pi : constant := Pi * 2.0;
One_Over_Pi : constant := 1.0 / Pi;
One_Over_Two_Pi : constant := 1.0 / Two_Pi;
Two_Over_Pi : constant := 2.0 / Pi;
High_Threshold : constant Float :=
Float (Float'Machine_Radix) ** (Float'Machine_Mantissa / 2);
Low_Threshold : constant Float :=
Float (Float'Machine_Radix) ** (-Float'Machine_Mantissa / 2);
Log_Float_Large : constant := 141.402024;-- Log(float'large);
Log_2 : constant Float :=
0.693147180559945309417232121458176568075500133107812;
-- constants for "**"
--
type Float_Array is array (Natural range <>) of Float;
Expx_A1 : Float_Array (1 .. 17);
Expx_A2 : Float_Array (1 .. 8);
Sqrt_One_Half : constant Float :=
0.7071067811865475244008443621048490392848359375608;
------------------------------------------------------------------------------
use Primitive_Functions;
function Is_Odd (F : Float) return Boolean is
-- assume F is already an integer !!
F_Over_2 : Float := F / 2.0;
begin
return (Truncate (F_Over_2) /= F_Over_2);
end Is_Odd;
-------------------------------------------------------------------------------
function Sqrt (X : Float_Type) return Float_Type is
-- Cody & Waite, pp.17-34
-- Hart & al., pp.89-96
A : Float := Float (X);
Adj : Float;
F : Float;
N : Integer;
Y : Float;
Bits : Natural;
begin
if X < 0.0 then
raise Argument_Error;
elsif X = 0.0 then
return 0.0;
end if;
----Break A into a fraction and an exponent.
Decompose (A, F, N);
----Compute an approximation of the answer for sqrt(f).
Y := 0.41731 + 0.59016 * F;
----Now we put back the exponential information.
if N rem 2 /= 0 then
Y := Y * 8#0.55202_36314_77473_63110#;
N := N + 1;
end if;
N := N / 2;
Y := Y * Float (Float'Machine_Radix) ** 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) ** (N - Float'Machine_Mantissa);
----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 | Constraint_Error =>
----We got an agument that was at/close-to Float'Large
-- Reduce Y back by Adj and return it.
Y := Y - Adj;
return Float_Type (Y);
end;
while F > A loop
Y := Y - Adj;
F := Y * Y;
end loop;
end if;
----Return the correct result.
return Float_Type (Y);
end Sqrt;
function Log (X : Float_Type) return Float_Type is
-- Cody & Waite, pp.35-48
A : Float := Float (X);
F : Float;
N : Integer;
Znum : Float;
Zden : Float;
begin
if X < 0.0 then
raise Argument_Error;
end if;
if X = 0.0 then
raise Constraint_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.
Decompose (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_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;
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);
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 Float_Type (F);
end Log;
function Log (X, Base : Float_Type) return Float_Type is
begin
if X < 0.0 or Base <= 0.0 or Base = 1.0 then
raise Argument_Error;
end if;
if X = 0.0 then
raise Constraint_Error;
end if;
return Log (X) / Log (Base);
end Log;
function Exp (X : Float_Type) return Float_Type is
-- Hart et. al., pp.97-105
A : Float := Float (X);
N : Integer;
Xn : Float;
G : Float;
Xi : Integer;
X1 : Float;
X2 : Float;
Pz : Float;
Qz : Float;
Ln_Float_Large : constant := 141.402024;-- Log(float'large);
Ln_Float_Small : constant := -711.169; -- log(float'safe_small);
begin
----Make sure that it is possible to represent the result. (too big/small)
if A > Ln_Float_Large then
raise Constraint_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;
----Perform argument range reduction.
N := Integer (A * 1.44269504088896340735992468100189213742664595602385);
Xn := Float (N);
Xi := Integer (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;
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;
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 ** Xi;
G := G * 2.0 ** N;
return Float_Type (G);
end Exp;
function "**" (X, Y : Float_Type) return Float_Type is
M : Integer;
F : Float;
P : Integer;
Z : Float;
Rv : Float;
U1 : Float;
U2 : Float; Y1 : Float;
Y2 : Float;
Iw1 : Integer;
W : Float;
W1 : Float;
W2 : Float;
I : Integer;
begin
if X = 0.0 and Y /= 0.0 then
raise Constraint_Error;
end if;
if X < 0.0 then
raise Argument_Error;
end if;
if Y = 0.0 then
return 1.0;
end if;
Decompose (Float (X), F, M);
----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.
Z := F - Expx_A1 (P + 1);
Z := Z - Expx_A2 ((P + 1) / 2);
Z := Z / (F + Expx_A1 (P + 1));
Z := Z + Z;
----Now compute the z*P(z**2) approximation.
F := Z * Z;
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;
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.
U1 := Float (M * 16 - P) * 0.0625;
Y1 := Truncate (Float (Y) * 16.0) * 0.0625;
Y2 := Float (Y) - Y1;
W := U2 * Float (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 := Integer (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.
M := Iw1 / 16 + I;
P := 16 * M - Iw1;
----Now do Z.
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;
----Nearly there; one more step.
Z := Expx_A1 (P + 1) + Expx_A1 (P + 1) * Z;
I := M / 2;
M := M - I;
Z := Z * Float (Float'Machine_Radix) ** I;
Z := Z * Float (Float'Machine_Radix) ** M;
return Float_Type (Z);
end "**";
function Sin (X : Float_Type) return Float_Type is
R : Float;
F : Float;
G : Float;
Y : Float := Float (X);
Xn : Float;
Tmp : Float;
Sign : Boolean;
begin
if Y < 0.0 then
Y := -Y;
Sign := True;
else
Sign := False;
end if;
----Check for ridiculously large values of Y.
if Y >= Pi * High_Threshold then
return 0.0;
end if;
----Form XN and check for even/odd-ness.
Xn := Round (Y * One_Over_Pi);
if Is_Odd (Xn) then
Sign := not Sign;
end if;
----Compute the f portion of the argument.
Tmp := Truncate (Y);
F := ((Tmp - Xn * 8#3.1104#) + (Y - Tmp)) +
Xn * 8.9089_10206_76153_73566_17E-06;
----See if there is no point to computing sin(x).
if abs F < Low_Threshold then
if Sign then
F := -F;
end if;
return Float_Type (F);
end if;
----Compute an answer.
G := F * F;
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;
----Now finish off the result.
R := F + F * R;
if Sign then
R := -R;
end if;
return Float_Type (R);
end Sin;
function Sin (X, Cycle : Float_Type) return Float_Type is
begin
if Cycle <= 0.0 then
raise Argument_Error;
end if;
return Sin ((Two_Pi * X) / Cycle);
end Sin;
function Cos (X : Float_Type) return Float_Type is
R : Float;
F : Float;
G : Float;
Y : Float;
Xn : Float;
Tmp : Float;
Sign : Boolean;
begin
Y := Float (abs X) + 1.57079_63267_94896_61923;
Sign := False;
----Check for ridiculously large values of Y.
if Y >= Pi * High_Threshold then
return 0.0;
end if;
----Form XN and check for even/odd-ness.
Xn := Round (Y * One_Over_Pi);
if Is_Odd (Xn) then
Sign := not Sign;
end if;
Xn := Xn - 0.5;
----Compute the f portion of the argument.
Tmp := Truncate (Float (abs X));
F := ((Tmp - Xn * 8#3.1104#) + (Float (abs X) - Tmp)) +
Xn * 8.9089_10206_76153_73566_17E-06;
----See if there is no point to computing cos(x).
if abs F < Low_Threshold then
if Sign then
F := -F;
end if;
return Float_Type (F);
end if;
----Compute an answer.
G := F * F;
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;
----Now finish off the result.
R := F + F * R;
if Sign then
R := -R;
end if;
return Float_Type (R);
end Cos;
function Cos (X, Cycle : Float_Type) return Float_Type is
begin
if Cycle <= 0.0 then
raise Argument_Error;
end if;
return Cos ((Two_Pi * X) / Cycle);
end Cos;
function Tan (X : Float_Type) return Float_Type is
A : Float := Float (X);
F : Float;
X1 : Float;
Xnum : Float;
Xden : Float;
Even : Boolean;
Xn : Float;
begin
F := abs A;
----See if our argument is much too large to make any sense.
if F > Truncate (High_Threshold * Pi_Over_2) then
return 0.0;
end if;
----Form XN and check for even/odd-ness.
Xn := Round (A * Two_Over_Pi);
Even := not Is_Odd (Xn);
----Compute f.
X1 := Truncate (A);
F := ((X1 - Xn * 1.57079) + (A - X1)) +
Xn * 6.32679489661923132169163975144E-06;
----See if f is very very small.
if abs F < Low_Threshold then
Xnum := F;
Xden := 1.0;
else
X1 := F * F;
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;
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 Float_Type (Xnum);
end Tan;
function Tan (X, Cycle : Float_Type) return Float_Type is
begin
if Cycle <= 0.0 then
raise Argument_Error;
end if;
return Tan (Two_Pi * X / Cycle);
end Tan;
function Cot (X : Float_Type) return Float_Type is
A : Float := Float (X);
F : Float;
X1 : Float;
Xnum : Float;
Xden : Float;
Even : Boolean;
Xn : Float;
----Cot_Eps1 is smallest positive number that can be reciprocated without
-- Numeric_Error.
Cot_Eps1 : constant Float :=
Float (Float'Machine_Radix) ** (Float'Machine_Emin - 1);
begin
F := abs A;
----See if our argument is much too small to handle.
if F < Cot_Eps1 then
if A = 0.0 then
raise Constraint_Error;
elsif A < 0.0 then
return Float_Type (Float'First);
else
return Float_Type (Float'Last);
end if;
end if;
----See if our argument is much too large to make any sense.
if F > Truncate (High_Threshold * Pi_Over_2) then
return 0.0;
end if;
----Form XN and check for even/odd-ness.
Xn := Round (A * Two_Over_Pi);
Even := not Is_Odd (Xn);
----Compute f.
X1 := Truncate (A);
F := ((X1 - Xn * 8#1.4442#) + (A - X1)) +
Xn * 4.4544_55103_38706_86783_08E-06;
----See if f is very very small.
if abs F < Low_Threshold then
Xnum := F;
Xden := 1.0;
else
X1 := F * F;
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;
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 Float_Type (Xnum);
end Cot;
function Cot (X, Cycle : Float_Type) return Float_Type is
begin
if Cycle <= 0.0 then
raise Argument_Error;
end if;
return Cot (Two_Pi * X / Cycle);
end Cot;
function Arcsin (X : Float_Type) return Float_Type is
Y : Float := Float (abs X);
F : Float;
G : Float;
I : Integer;
begin
if abs X > 1.0 then
raise Argument_Error;
end if;
----Very small arguments are equal to the answer.
if Y < Low_Threshold 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;
F := ((0.5 - Y) + 0.5) / 2.0;
Y := Float (Sqrt (Float_Type (F)));
Y := -(Y + Y);
G := F;
else
I := 0;
G := Y * Y;
end if;
----Approximate our result.
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);
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 X < 0.0 then
G := -G;
end if;
return Float_Type (G);
end Arcsin;
function Arcsin (X, Cycle : Float_Type) return Float_Type is
begin
if Cycle <= 0.0 then
raise Argument_Error;
end if;
return Arcsin (X) * Cycle * One_Over_Two_Pi;
end Arcsin;
function Arccos (X : Float_Type) return Float_Type is
A : Float := Float (X);
Y : Float := Float (abs X);
F : Float;
G : Float;
I : Integer;
begin
if Y > 1.0 then
raise Argument_Error;
end if;
----Very small arguments are equal to the answer.
if Y < Low_Threshold 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;
F := ((0.5 - Y) + 0.5) / 2.0;
Y := Float (Sqrt (Float_Type (F)));
Y := -(Y + Y);
G := F;
else
I := 1;
G := Y * Y;
end if;
----Approximate our result.
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);
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.
return Float_Type (G);
end Arccos;
function Arccos (X, Cycle : Float_Type) return Float_Type is
begin
if (abs X > 1.0) or (Cycle <= 0.0) then
raise Argument_Error;
end if;
return Arccos (X) * Cycle * One_Over_Two_Pi;
end Arccos;
function Arctan (Y : Float_Type;
X : Float_Type := 1.0) return Float_Type is
A : Float;
F : Float;
G : Float;
R : Float;
N : Natural range 0 .. 3;
begin
if X = 0.0 then
if Y = 0.0 then
raise Argument_Error;
elsif Y > 0.0 then
return Pi_Over_2;
else
return -Pi_Over_2;
end if;
end if;
if Y = 0.0 then
if X > 0.0 then
return 0.0;
else
return Pi;
end if;
end if;
----Reduce the argument to a small value close to zero.
if X = 1.0 then
A := Float (Y);
else
A := Float (Y) / Float (X);
end if;
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 >= Low_Threshold then
G := F * F;
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);
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 A < 0.0 then
F := -F;
end if;
return Float_Type (F);
end Arctan;
function Arctan (Y : Float_Type;
X : Float_Type := 1.0;
Cycle : Float_Type) return Float_Type is
begin
if Cycle <= 0.0 then
raise Argument_Error;
end if;
return Arctan (Y, X) * Cycle * One_Over_Two_Pi;
end Arctan;
function Arccot (X : Float_Type;
Y : Float_Type := 1.0) return Float_Type is
begin
return Arctan (Y => Y, X => X);
end Arccot;
function Arccot (X : Float_Type;
Y : Float_Type := 1.0;
Cycle : Float_Type) return Float_Type is
begin
if Cycle <= 0.0 then
raise Argument_Error;
end if;
return Arccot (X, Y) * Cycle * One_Over_Two_Pi;
end Arccot;
function Sinh (X : Float_Type) return Float_Type is
A : Float := Float (X);
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 Y <= Log_Float_Large then
Z := Float (Exp (Float_Type (Y)));
Z := (Z * 0.5 - 0.5 / Z);
if A < 0.0 then
Z := -Z;
end if;
return Float_Type (Z);
end if;
----Reduce the argument.
W := Y - 8#0.542714#;
if W > Log_Float_Large then
raise Constraint_Error;
end if;
----Now take the EXP of the argument and compute the result with corrections
-- based on the machine radix.
Z := Float (Exp (Float_Type (W)));
Z := Z + 0.13830_27787_96019_02638E-04 * Z;
----Return the result with the correct sign.
if A < 0.0 then
Z := -Z;
end if;
return Float_Type (Z);
----Compute the result for "small" arguments here.
else
if Y < Low_Threshold then
return Float_Type (A);
end if;
Y := A * A;
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);
W := A + A * W;
return Float_Type (W);
end if;
end Sinh;
function Cosh (X : Float_Type) return Float_Type is
A : Float := Float (X);
Y : Float := abs A;
W : Float;
Z : Float;
begin
----Base-2 machines can compute things the easy way for "small" arguments.
if Y <= Log_Float_Large then
Z := Float (Exp (Float_Type (Y)));
Z := (Z * 0.5 + 0.5 / Z);
return Float_Type (Z);
end if;
----Reduce the argument.
W := Y - 8#0.542714#;
if W > Log_Float_Large then
raise Constraint_Error;
end if;
----Now take the EXP of the argument and compute the result
Z := Float (Exp (Float_Type (W)));
Z := Z + 0.13830_27787_96019_02638E-04 * Z;
----Return the result.
return Float_Type (Z);
end Cosh;
function Tanh (X : Float_Type) return Float_Type is
A : Float := Float (X);
F : Float := abs A;
G : Float;
Result : Float;
Tanh_Xbig : constant Float := 1.90615474653985E+01;
-- Tanh_Xbig :=
-- (Ln_2 +
-- Float (Float'Machine_Mantissa + 1) * Ln (Float (Float'Machine_Radix)))
-- / 2.0;
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 / Float (Exp (Float_Type (F + F)) + 1.0);
Result := Result + Result;
----Very small arguments result in themselves.
elsif F < Low_Threshold then
Result := F;
----All other arguments get approximated here.
else
G := F * F;
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);
Result := F + F * Result;
end if;
----Return a result with the correct sign.
if A < 0.0 then
Result := -Result;
end if;
return Float_Type (Result);
end Tanh;
function Coth (X : Float_Type) return Float_Type is
begin
return 1.0 / Tanh (X);
end Coth;
function Arcsinh (X : Float_Type) return Float_Type is
begin
return Log (X + Sqrt (X * X + 1.0));
end Arcsinh;
function Arccosh (X : Float_Type) return Float_Type is
begin
return Log (X + Sqrt (X * X - 1.0));
end Arccosh;
function Arctanh (X : Float_Type) return Float_Type is
begin
return Log ((1.0 + X) / (1.0 - X)) / 2.0;
end Arctanh;
function Arccoth (X : Float_Type) return Float_Type is
begin
return Arctanh (1.0 / X);
end Arccoth;
begin
----Set up arrays of values for the Expx routine. See pages 98 and 106 of
-- the William J. Cody book for details of what and why.
declare
type Natural_Array is array (Positive range <>) of Natural;
procedure Expx_Stuff (A1 : in out Float;
A2 : in out Float;
N1 : Natural_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 : Integer;
Mask : Integer;
begin
Bits := Float'Machine_Mantissa;
A1 := Float (N1 (1)) / 2.0 ** 30;
Mask := 2 ** (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;
end Expx_Stuff;
begin
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#));
end;
end Generic_Elementary_Functions;
nblk1=37
nid=0
hdr6=6e
[0x00] rec0=14 rec1=00 rec2=01 rec3=02a
[0x01] rec0=1a rec1=00 rec2=02 rec3=04a
[0x02] rec0=03 rec1=00 rec2=37 rec3=01c
[0x03] rec0=22 rec1=00 rec2=03 rec3=03a
[0x04] rec0=01 rec1=00 rec2=36 rec3=012
[0x05] rec0=20 rec1=00 rec2=04 rec3=022
[0x06] rec0=00 rec1=00 rec2=35 rec3=006
[0x07] rec0=1b rec1=00 rec2=05 rec3=034
[0x08] rec0=2b rec1=00 rec2=06 rec3=05e
[0x09] rec0=01 rec1=00 rec2=34 rec3=000
[0x0a] rec0=22 rec1=00 rec2=07 rec3=02e
[0x0b] rec0=01 rec1=00 rec2=33 rec3=000
[0x0c] rec0=20 rec1=00 rec2=08 rec3=07e
[0x0d] rec0=04 rec1=00 rec2=32 rec3=00a
[0x0e] rec0=29 rec1=00 rec2=09 rec3=00a
[0x0f] rec0=01 rec1=00 rec2=31 rec3=002
[0x10] rec0=2c rec1=00 rec2=0a rec3=09c
[0x11] rec0=01 rec1=00 rec2=2f rec3=008
[0x12] rec0=21 rec1=00 rec2=30 rec3=02a
[0x13] rec0=02 rec1=00 rec2=0b rec3=00e
[0x14] rec0=22 rec1=00 rec2=0c rec3=014
[0x15] rec0=01 rec1=00 rec2=2e rec3=024
[0x16] rec0=26 rec1=00 rec2=0d rec3=016
[0x17] rec0=00 rec1=00 rec2=2d rec3=008
[0x18] rec0=2a rec1=00 rec2=0e rec3=028
[0x19] rec0=02 rec1=00 rec2=2c rec3=000
[0x1a] rec0=21 rec1=00 rec2=0f rec3=01a
[0x1b] rec0=00 rec1=00 rec2=2b rec3=008
[0x1c] rec0=2c rec1=00 rec2=10 rec3=034
[0x1d] rec0=02 rec1=00 rec2=2a rec3=004
[0x1e] rec0=1f rec1=00 rec2=11 rec3=024
[0x1f] rec0=00 rec1=00 rec2=29 rec3=008
[0x20] rec0=29 rec1=00 rec2=12 rec3=010
[0x21] rec0=00 rec1=00 rec2=28 rec3=010
[0x22] rec0=21 rec1=00 rec2=13 rec3=020
[0x23] rec0=00 rec1=00 rec2=27 rec3=00c
[0x24] rec0=2d rec1=00 rec2=14 rec3=008
[0x25] rec0=1b rec1=00 rec2=15 rec3=072
[0x26] rec0=2e rec1=00 rec2=16 rec3=02a
[0x27] rec0=1b rec1=00 rec2=17 rec3=00e
[0x28] rec0=26 rec1=00 rec2=18 rec3=054
[0x29] rec0=29 rec1=00 rec2=19 rec3=04e
[0x2a] rec0=1f rec1=00 rec2=1a rec3=012
[0x2b] rec0=28 rec1=00 rec2=1b rec3=01e
[0x2c] rec0=25 rec1=00 rec2=1c rec3=03a
[0x2d] rec0=22 rec1=00 rec2=1d rec3=010
[0x2e] rec0=27 rec1=00 rec2=1e rec3=040
[0x2f] rec0=00 rec1=00 rec2=26 rec3=05a
[0x30] rec0=22 rec1=00 rec2=1f rec3=00a
[0x31] rec0=00 rec1=00 rec2=25 rec3=00a
[0x32] rec0=2d rec1=00 rec2=20 rec3=01e
[0x33] rec0=15 rec1=00 rec2=21 rec3=010
[0x34] rec0=00 rec1=00 rec2=24 rec3=004
[0x35] rec0=11 rec1=00 rec2=22 rec3=088
[0x36] rec0=09 rec1=00 rec2=23 rec3=000
tail 0x215016e8481c04de3c61d 0x42a00066462061e03