|
|
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: 5468 (0x155c)
Types: TextFile
Names: »B«
└─⟦5f3412b64⟧ Bits:30000745 8mm tape, Rational 1000, ENVIRONMENT 12_6_5 TOOLS
└─⟦91c658230⟧ »DATA«
└─⟦458657fb6⟧
└─⟦1472c4407⟧
└─⟦this⟧
└─⟦d10a02448⟧ Bits:30000409 8mm tape, Rational 1000, ENVIRONMENT, D_12_7_3
└─⟦fc9b38f02⟧ »DATA«
└─⟦9b46a407a⟧
└─⟦2e03b931c⟧
└─⟦this⟧
separate (Generic_Elementary_Functions)
function Kf_L1p (Y : Common_Float) return Common_Float is
-- On input, Y is a floating-point value in Common_Float;
-- On output, the value of log(1 + Y) is returned.
-- Except for arguments Y that are near zero, log( 1 + Y ) is
-- calculated by determining M, Z1, and Z2 such that
-- log( 1 + Y ) = M*Log2 + Z1 + Z2. Then, except for arguments Y
-- that are very large numbers, computations needed in order to
-- retrieve the values of M, Z1, and Z2 involve two steps.
-- First, we decompose one plus the argument Y to the form
-- 1 + Y = 2**M * (F1 + F2),
-- where 1 <= F1+F2 < 2, M has the value of an integer,
-- F1 = 1 + j/64, j ranges from 0 to 64, and |F2| <= 1/128.
-- Second, we approximate log( 1 + F2/F1 ) by an odd polynomial
-- in U, where
-- U = 2 F2 / (2 F2 + F1).
-- Note that
-- log( 1 + F2/F1 ) = log( 1 + U/2 ) - log( 1 - U/2 ).
-- The core approximation calculates
-- Poly = [log( 1 + U/2 ) - log( 1 - U/2 )]/U - 1.
-- Note that log(1 + U/2) - log(1 - U/2) = 2 arctanh ( U/2 ),
-- thus,
-- Poly = 2 arctanh( U/2 ) / U - 1.
-- That value is computed by the kernel function KF_Atanh.
-- It is not hard to see that
-- log(Y) = M*log(2) + log(F1) + log( 1 + F2/F1 ).
-- Hence, we return Z1 := log(F1), and Z2 := log( 1 + F2/F1).
-- The values of log(F1) are calculated beforehand and stored in the program.
-- If Y is near zero, satisfying |log(Y)| < 1/16 - 1, then we use
-- an approximation similar to the core approximation in Step 2
-- above to calculate log( 1 + Y ). For details of the
-- computation, refer to the code and comments in the separate
-- body of the function KF_L1pSm.
-- As far as the types used for internal computation are concerned,
-- we use Common_Float to carry out Step 1, and use
-- Working_Float to carry out Step 2. See the code in the separate
-- body for the function KF_Atanh for details about Working_Float.
F, F1, F2, U, M, Z, Z1, Z2, Half_F2, Poly, Result : Common_Float;
Index, I, J : Common_Int;
Thres1 : constant := 16#0.F07D5# - 1.0;
Thres2 : constant := 16#1.1082C# - 1.0;
Base_Digits : constant Common_Float :=
Common_Float (3 * Float_Type'Base'Digits);
Two_To : constant array (Common_Int range -3 .. 3) of Common_Float :=
(0.125, 0.25, 0.5, 1.0, 2.0, 4.0, 8.0);
Log2_Lead : constant Common_Float := 16#0.B17#;
Log2_Trail : constant Common_Float :=
16#0.000217F7D1CF79ABC9E3B39803F2F6AF40#;
begin
-- I. Filter out exceptional case.
if (Y <= -1.0) then
raise Argument_Error;
end if;
-- II. Check if the input argument is near zero.
if (Y >= Thres1 and Y <= Thres2) then
-- Invoke the function KF_L1pSm to compute log(1 + Y).
return (Kf_L1psm (Y));
end if;
-- III. General case.
if (Y >= (0.5 * Float_Type'Safe_Large)) then
Kp_Log (Y, M, Z1, Z2);
else
-- Calculate M, Z1, and Z2 not using KP_Log
-- Step 1. Decomposition.
Z := 1.0 + Y;
-- Use the primitive function to extract M and F where
-- Z = radix**M * F, 1/radix <= F < 1.
Decompose (Z, F, I);
M := Common_Float (I);
J := 0;
if (Common_Float'Machine_Radix = 16) then
M := 4.0 * M;
while F < 0.5 loop
J := J - 1;
M := M - 1.0;
F := F + F;
end loop;
end if;
-- Now, regardless if Radix is 2 or 16, we have
-- Z = 2**M * F = (radix**I) * (2**J) * F, 1/2 <= F < 1.
-- Extract the leading 7 bits of F.
Index := Common_Int (F * 2#1.0#E7);
F1 := Common_Float (Index) * 2#1.0#E-7;
-- We now calculate F2 such that
-- 2**M * (F1 + F2) = 1 + Y accurately.
-- i.e. (radix**I) * (2**J) * (F1 + F2) = 1 + Y accurately.
if (M <= Base_Digits) then
-- F2 = 2**(-J) * ( ( r**(-I) - 2**(J) * F1 ) + r**(-I) * Y )
if (J = 0) then
F2 := Scale (1.0, -I) - F1;
F2 := F2 + Scale (Y, -I);
else
F2 := Scale (1.0, -I) - Two_To (J) * F1;
F2 := (F2 + Scale (Y, -I)) * Two_To (-J);
end if;
else
-- M is large.
-- F2 = 2**(-J) * ( ( r**(-I) * Y - (2**J) * F1 ) + r**(-I) )
if (J = 0) then
F2 := Scale (Y, -I) - F1;
F2 := F2 + Scale (1.0, -I);
else
F2 := Scale (Y, -I) - Two_To (J) * F;
F2 := (F2 + Scale (1.0, -I)) * Two_To (-J);
end if;
end if;
-- Now 2**M * (F1 + F2) = 1 + Y accurately,
-- but F1 = J/128, j = 64, ... , 128 and
-- |F2| < 1/256.
M := M - 1.0;
F1 := F1 + F1;
Half_F2 := F2;
F2 := F2 + F2;
-- Now 2**M * (F1 + F2) = 1 + Y
-- F1 = j/64, j = 64, ... , 128 and
-- |F2| < 1/128.
-- Step 2. Approximation.
-- Calculate U := 2 F2 / ( 2 F1 + F2 ) = F2 / ( F1 + Half_F2 )
U := F2 / (F1 + Half_F2);
-- Approximate [log(1+U/2)-log(1-U/2)]/U - 1.
Poly := Kf_Atanh (U);
Z1 := Log_Of_Jby64 (Index, Lead);
Z2 := U + (Log_Of_Jby64 (Index, Trail) + U * Poly);
end if;
-- Calculate log( 1 + Y ) from M, Z1, and Z2 such that
-- log(1 + Y ) = M*Log2 + Z1 + Z2.
if (M = 0.0) then
Result := Z1 + Z2;
else
Result := M * Log2_Trail + Z2;
Result := (M * Log2_Lead + Z1) + Result;
end if;
return (Result);
end Kf_L1p;