| -- CXG2001.A |
| -- |
| -- Grant of Unlimited Rights |
| -- |
| -- Under contracts F33600-87-D-0337, F33600-84-D-0280, MDA903-79-C-0687, |
| -- F08630-91-C-0015, and DCA100-97-D-0025, the U.S. Government obtained |
| -- unlimited rights in the software and documentation contained herein. |
| -- Unlimited rights are defined in DFAR 252.227-7013(a)(19). By making |
| -- this public release, the Government intends to confer upon all |
| -- recipients unlimited rights equal to those held by the Government. |
| -- These rights include rights to use, duplicate, release or disclose the |
| -- released technical data and computer software in whole or in part, in |
| -- any manner and for any purpose whatsoever, and to have or permit others |
| -- to do so. |
| -- |
| -- DISCLAIMER |
| -- |
| -- ALL MATERIALS OR INFORMATION HEREIN RELEASED, MADE AVAILABLE OR |
| -- DISCLOSED ARE AS IS. THE GOVERNMENT MAKES NO EXPRESS OR IMPLIED |
| -- WARRANTY AS TO ANY MATTER WHATSOEVER, INCLUDING THE CONDITIONS OF THE |
| -- SOFTWARE, DOCUMENTATION OR OTHER INFORMATION RELEASED, MADE AVAILABLE |
| -- OR DISCLOSED, OR THE OWNERSHIP, MERCHANTABILITY, OR FITNESS FOR A |
| -- PARTICULAR PURPOSE OF SAID MATERIAL. |
| --* |
| -- |
| -- OBJECTIVE: |
| -- Check that the floating point attributes Model_Mantissa, |
| -- Machine_Mantissa, Machine_Radix, and Machine_Rounds |
| -- are properly reported. |
| -- |
| -- TEST DESCRIPTION: |
| -- This test uses a generic package to compute and check the |
| -- values of the Machine_ attributes listed above. The |
| -- generic package is instantiated with the standard FLOAT |
| -- type and a floating point type for the maximum number |
| -- of digits of precision. |
| -- |
| -- APPLICABILITY CRITERIA: |
| -- This test applies only to implementations supporting the |
| -- Numerics Annex. |
| -- |
| -- |
| -- CHANGE HISTORY: |
| -- 26 JAN 96 SAIC Initial Release for 2.1 |
| -- |
| --! |
| |
| -- References: |
| -- |
| -- "Algorithms To Reveal Properties of Floating-Point Arithmetic" |
| -- Michael A. Malcolm; CACM November 1972; pgs 949-951. |
| -- |
| -- Software Manual for Elementary Functions; W. J. Cody and W. Waite; |
| -- Prentice-Hall; 1980 |
| ----------------------------------------------------------------------- |
| -- |
| -- This test relies upon the fact that |
| -- (A+2.0)-A is not necessarily 2.0. If A is large enough then adding |
| -- a small value to A does not change the value of A. Consider the case |
| -- where we have a decimal based floating point representation with 4 |
| -- digits of precision. A floating point number would logically be |
| -- represented as "DDDD * 10 ** exp" where D is a value in the range 0..9. |
| -- The first loop of the test starts A at 2.0 and doubles it until |
| -- ((A+1.0)-A)-1.0 is no longer zero. For our decimal floating point |
| -- number this will be 1638 * 10**1 (the value 16384 rounded or truncated |
| -- to fit in 4 digits). |
| -- The second loop starts B at 2.0 and keeps doubling B until (A+B)-A is |
| -- no longer 0. This will keep looping until B is 8.0 because that is |
| -- the first value where rounding (assuming our machine rounds and addition |
| -- employs a guard digit) will change the upper 4 digits of the result: |
| -- 1638_ |
| -- + 8 |
| -- ------- |
| -- 1639_ |
| -- Without rounding the second loop will continue until |
| -- B is 16: |
| -- 1638_ |
| -- + 16 |
| -- ------- |
| -- 1639_ |
| -- |
| -- The radix is then determined by (A+B)-A which will give 10. |
| -- |
| -- The use of Tmp and ITmp in the test is to force values to be |
| -- stored into memory in the event that register precision is greater |
| -- than the stored precision of the floating point values. |
| -- |
| -- |
| -- The test for rounding is (ignoring the temporary variables used to |
| -- get the stored precision) is |
| -- Rounds := A + Radix/2.0 - A /= 0.0 ; |
| -- where A is the value determined in the first step that is the smallest |
| -- power of 2 such that A + 1.0 = A. This means that the true value of |
| -- A has one more digit in its value than 'Machine_Mantissa. |
| -- This check will detect the case where a value is always rounded. |
| -- There is an additional case where values are rounded to the nearest |
| -- even value. That is referred to as IEEE style rounding in the test. |
| -- |
| ----------------------------------------------------------------------- |
| |
| with System; |
| with Report; |
| with Ada.Numerics.Generic_Elementary_Functions; |
| procedure CXG2001 is |
| Verbose : constant Boolean := False; |
| |
| -- if one of the attribute computation loops exceeds Max_Iterations |
| -- it is most likely due to the compiler reordering an expression |
| -- that should not be reordered. |
| Illegal_Optimization : exception; |
| Max_Iterations : constant := 10_000; |
| |
| generic |
| type Real is digits <>; |
| package Chk_Attrs is |
| procedure Do_Test; |
| end Chk_Attrs; |
| |
| package body Chk_Attrs is |
| package EF is new Ada.Numerics.Generic_Elementary_Functions (Real); |
| function Log (X : Real) return Real renames EF.Log; |
| |
| |
| -- names used in paper |
| Radix : Integer; -- Beta |
| Mantissa_Digits : Integer; -- t |
| Rounds : Boolean; -- RND |
| |
| -- made global to Determine_Attributes to help thwart optimization |
| A, B : Real := 2.0; |
| Tmp, Tmpa, Tmp1 : Real; |
| ITmp : Integer; |
| Half_Radix : Real; |
| |
| -- special constants - not declared as constants so that |
| -- the "stored" precision will be used instead of a "register" |
| -- precision. |
| Zero : Real := 0.0; |
| One : Real := 1.0; |
| Two : Real := 2.0; |
| |
| |
| procedure Thwart_Optimization is |
| -- the purpose of this procedure is to reference the |
| -- global variables used by Determine_Attributes so |
| -- that the compiler is not likely to keep them in |
| -- a higher precision register for their entire lifetime. |
| begin |
| if Report.Ident_Bool (False) then |
| -- never executed |
| A := A + 5.0; |
| B := B + 6.0; |
| Tmp := Tmp + 1.0; |
| Tmp1 := Tmp1 + 2.0; |
| Tmpa := Tmpa + 2.0; |
| One := 12.34; Two := 56.78; Zero := 90.12; |
| end if; |
| end Thwart_Optimization; |
| |
| |
| -- determines values for Radix, Mantissa_Digits, and Rounds |
| -- This is mostly a straight translation of the C code. |
| -- The only significant addition is the iteration count |
| -- to prevent endless looping if things are really screwed up. |
| procedure Determine_Attributes is |
| Iterations : Integer; |
| begin |
| Rounds := True; |
| |
| Iterations := 0; |
| Tmp := Real'Machine (((A + One) - A) - One); |
| while Tmp = Zero loop |
| A := Real'Machine(A + A); |
| Tmp := Real'Machine(A + One); |
| Tmp1 := Real'Machine(Tmp - A); |
| Tmp := Real'Machine(Tmp1 - One); |
| |
| Iterations := Iterations + 1; |
| if Iterations > Max_Iterations then |
| raise Illegal_Optimization; |
| end if; |
| end loop; |
| |
| Iterations := 0; |
| Tmp := Real'Machine(A + B); |
| ITmp := Integer (Tmp - A); |
| while ITmp = 0 loop |
| B := Real'Machine(B + B); |
| Tmp := Real'Machine(A + B); |
| ITmp := Integer (Tmp - A); |
| |
| Iterations := Iterations + 1; |
| if Iterations > Max_Iterations then |
| raise Illegal_Optimization; |
| end if; |
| end loop; |
| |
| Radix := ITmp; |
| |
| Mantissa_Digits := 0; |
| B := 1.0; |
| Tmp := Real'Machine(((B + One) - B) - One); |
| Iterations := 0; |
| while (Tmp = Zero) loop |
| Mantissa_Digits := Mantissa_Digits + 1; |
| B := B * Real (Radix); |
| Tmp := Real'Machine(B + One); |
| Tmp1 := Real'Machine(Tmp - B); |
| Tmp := Real'Machine(Tmp1 - One); |
| |
| Iterations := Iterations + 1; |
| if Iterations > Max_Iterations then |
| raise Illegal_Optimization; |
| end if; |
| end loop; |
| |
| Rounds := False; |
| Half_Radix := Real (Radix) / Two; |
| Tmp := Real'Machine(A + Half_Radix); |
| Tmp1 := Real'Machine(Tmp - A); |
| if (Tmp1 /= Zero) then |
| Rounds := True; |
| end if; |
| Tmpa := Real'Machine(A + Real (Radix)); |
| Tmp := Real'Machine(Tmpa + Half_Radix); |
| if not Rounds and (Tmp - TmpA /= Zero) then |
| Rounds := True; |
| if Verbose then |
| Report.Comment ("IEEE style rounding"); |
| end if; |
| end if; |
| |
| exception |
| when others => |
| Thwart_Optimization; |
| raise; |
| end Determine_Attributes; |
| |
| |
| procedure Do_Test is |
| Show_Results : Boolean := Verbose; |
| Min_Mantissa_Digits : Integer; |
| begin |
| -- compute the actual Machine_* attribute values |
| Determine_Attributes; |
| |
| if Real'Machine_Radix /= Radix then |
| Report.Failed ("'Machine_Radix incorrectly reports" & |
| Integer'Image (Real'Machine_Radix)); |
| Show_Results := True; |
| end if; |
| |
| if Real'Machine_Mantissa /= Mantissa_Digits then |
| Report.Failed ("'Machine_Mantissa incorrectly reports" & |
| Integer'Image (Real'Machine_Mantissa)); |
| Show_Results := True; |
| end if; |
| |
| if Real'Machine_Rounds /= Rounds then |
| Report.Failed ("'Machine_Rounds incorrectly reports " & |
| Boolean'Image (Real'Machine_Rounds)); |
| Show_Results := True; |
| end if; |
| |
| if Show_Results then |
| Report.Comment ("computed Machine_Mantissa is" & |
| Integer'Image (Mantissa_Digits)); |
| Report.Comment ("computed Radix is" & |
| Integer'Image (Radix)); |
| Report.Comment ("computed Rounds is " & |
| Boolean'Image (Rounds)); |
| end if; |
| |
| -- check the model attributes against the machine attributes |
| -- G.2.2(3)/3;6.0 |
| if Real'Model_Mantissa > Real'Machine_Mantissa then |
| Report.Failed ("model mantissa > machine mantissa"); |
| end if; |
| |
| -- G.2.2(3)/2;6.0 |
| -- 'Model_Mantissa >= ceiling(d*log(10)/log(radix))+1 |
| Min_Mantissa_Digits := |
| Integer ( |
| Real'Ceiling ( |
| Real(Real'Digits) * Log(10.0) / Log(Real(Real'Machine_Radix)) |
| ) ) + 1; |
| if Real'Model_Mantissa < Min_Mantissa_Digits then |
| Report.Failed ("Model_Mantissa [" & |
| Integer'Image (Real'Model_Mantissa) & |
| "] < minimum mantissa digits [" & |
| Integer'Image (Min_Mantissa_Digits) & |
| "]"); |
| end if; |
| |
| exception |
| when Illegal_Optimization => |
| Report.Failed ("illegal optimization of" & |
| " floating point expression"); |
| end Do_Test; |
| end Chk_Attrs; |
| |
| package Chk_Float is new Chk_Attrs (Float); |
| |
| -- check the floating point type with the most digits |
| type A_Long_Float is digits System.Max_Digits; |
| package Chk_A_Long_Float is new Chk_Attrs (A_Long_Float); |
| begin |
| Report.Test ("CXG2001", |
| "Check the attributes Model_Mantissa," & |
| " Machine_Mantissa, Machine_Radix," & |
| " and Machine_Rounds"); |
| |
| Report.Comment ("checking Standard.Float"); |
| Chk_Float.Do_Test; |
| |
| Report.Comment ("checking a digits" & |
| Integer'Image (System.Max_Digits) & |
| " floating point type"); |
| Chk_A_Long_Float.Do_Test; |
| |
| Report.Result; |
| end CXG2001; |