|
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 - download
Length: 9216 (0x2400) Types: Ada Source Notes: 03_class, FILE, R1k_Segment, e3_tag, function Kf_L1p, seg_0130d2, separate Generic_Elementary_Functions
└─⟦8527c1e9b⟧ Bits:30000544 8mm tape, Rational 1000, Arrival backup of disks in PAM's R1000 └─ ⟦5a81ac88f⟧ »Space Info Vol 1« └─⟦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;
nblk1=8 nid=0 hdr6=10 [0x00] rec0=19 rec1=00 rec2=01 rec3=048 [0x01] rec0=15 rec1=00 rec2=02 rec3=04e [0x02] rec0=27 rec1=00 rec2=03 rec3=000 [0x03] rec0=01 rec1=00 rec2=08 rec3=002 [0x04] rec0=24 rec1=00 rec2=04 rec3=080 [0x05] rec0=01 rec1=00 rec2=07 rec3=000 [0x06] rec0=25 rec1=00 rec2=05 rec3=020 [0x07] rec0=20 rec1=00 rec2=06 rec3=001 tail 0x2150db59682b1519e9baf 0x42a00066462061e03