3 -- Grant of Unlimited Rights
5 -- Under contracts F33600-87-D-0337, F33600-84-D-0280, MDA903-79-C-0687,
6 -- F08630-91-C-0015, and DCA100-97-D-0025, the U.S. Government obtained
7 -- unlimited rights in the software and documentation contained herein.
8 -- Unlimited rights are defined in DFAR 252.227-7013(a)(19). By making
9 -- this public release, the Government intends to confer upon all
10 -- recipients unlimited rights equal to those held by the Government.
11 -- These rights include rights to use, duplicate, release or disclose the
12 -- released technical data and computer software in whole or in part, in
13 -- any manner and for any purpose whatsoever, and to have or permit others
18 -- ALL MATERIALS OR INFORMATION HEREIN RELEASED, MADE AVAILABLE OR
19 -- DISCLOSED ARE AS IS. THE GOVERNMENT MAKES NO EXPRESS OR IMPLIED
20 -- WARRANTY AS TO ANY MATTER WHATSOEVER, INCLUDING THE CONDITIONS OF THE
21 -- SOFTWARE, DOCUMENTATION OR OTHER INFORMATION RELEASED, MADE AVAILABLE
22 -- OR DISCLOSED, OR THE OWNERSHIP, MERCHANTABILITY, OR FITNESS FOR A
23 -- PARTICULAR PURPOSE OF SAID MATERIAL.
27 -- Check that the ARCTAN function returns a
28 -- result that is within the error bound allowed.
31 -- This test consists of a generic package that is
32 -- instantiated to check both Float and a long float type.
33 -- The test for each floating point type is divided into
35 -- Special value checks where the result is a known constant.
38 -- SPECIAL REQUIREMENTS
39 -- The Strict Mode for the numerical accuracy must be
40 -- selected. The method by which this mode is selected
41 -- is implementation dependent.
43 -- APPLICABILITY CRITERIA:
44 -- This test applies only to implementations supporting the
46 -- This test only applies to the Strict Mode for numerical
51 -- 19 Mar 96 SAIC Initial release for 2.1
52 -- 30 APR 96 SAIC Fixed optimization issue
53 -- 17 AUG 96 SAIC Incorporated Reviewer's suggestions.
54 -- 12 OCT 96 SAIC Incorporated Reviewer's suggestions.
55 -- 02 DEC 97 EDS Remove procedure Identity_1_Test and calls to
57 -- 29 JUN 98 EDS Replace -0.0 with call to ImpDef.Annex_G.Negative_Zero
58 -- 28 APR 99 RLB Replaced comma accidentally deleted in above change.
59 -- 15 DEC 99 RLB Added model range checking to "exact" results,
60 -- in order to avoid too strictly requiring a specific
67 -- Software Manual for the Elementary Functions
68 -- William J. Cody, Jr. and William Waite
69 -- Prentice-Hall, 1980
71 -- CRC Standard Mathematical Tables
74 -- Implementation and Testing of Function Software
76 -- Problems and Methodologies in Mathematical Software Production
77 -- editors P. C. Messina and A. Murli
78 -- Lecture Notes in Computer Science Volume 142
79 -- Springer Verlag, 1982
84 with Ada
.Numerics
.Generic_Elementary_Functions
;
87 Verbose
: constant Boolean := False;
88 Max_Samples
: constant := 1000;
90 -- CRC Standard Mathematical Tables; 23rd Edition; pg 738
92 1.41421_35623_73095_04880_16887_24209_69807_85696_71875_37695
;
94 1.73205_08075_68877_29352_74463_41505_87236_69428_05253_81039
;
96 Pi
: constant := Ada
.Numerics
.Pi
;
99 type Real
is digits <>;
100 Half_PI_Low
: in Real
; -- The machine number closest to, but not greater
102 Half_PI_High
: in Real
;-- The machine number closest to, but not less
104 PI_Low
: in Real
; -- The machine number closest to, but not greater
106 PI_High
: in Real
; -- The machine number closest to, but not less
108 package Generic_Check
is
112 package body Generic_Check
is
113 package Elementary_Functions
is new
114 Ada
.Numerics
.Generic_Elementary_Functions
(Real
);
116 function Arctan
(Y
: Real
;
117 X
: Real
:= 1.0) return Real
renames
118 Elementary_Functions
.Arctan
;
119 function Arctan
(Y
: Real
;
121 Cycle
: Real
) return Real
renames
122 Elementary_Functions
.Arctan
;
124 -- flag used to terminate some tests early
125 Accuracy_Error_Reported
: Boolean := False;
127 -- The following value is a lower bound on the accuracy
128 -- required. It is normally 0.0 so that the lower bound
129 -- is computed from Model_Epsilon. However, for tests
130 -- where the expected result is only known to a certain
131 -- amount of precision this bound takes on a non-zero
132 -- value to account for that level of precision.
133 Error_Low_Bound
: Real
:= 0.0;
135 procedure Check
(Actual
, Expected
: Real
;
142 -- In the case where the expected result is very small or 0
143 -- we compute the maximum error as a multiple of Model_Epsilon
144 -- instead of Model_Epsilon and Expected.
145 Rel_Error
:= MRE
* abs Expected
* Real
'Model_Epsilon;
146 Abs_Error
:= MRE
* Real
'Model_Epsilon;
147 if Rel_Error
> Abs_Error
then
148 Max_Error
:= Rel_Error
;
150 Max_Error
:= Abs_Error
;
153 -- take into account the low bound on the error
154 if Max_Error
< Error_Low_Bound
then
155 Max_Error
:= Error_Low_Bound
;
158 if abs (Actual
- Expected
) > Max_Error
then
159 Accuracy_Error_Reported
:= True;
160 Report
.Failed
(Test_Name
&
161 " actual: " & Real
'Image (Actual
) &
162 " expected: " & Real
'Image (Expected
) &
163 " difference: " & Real
'Image (Actual
- Expected
) &
164 " max err:" & Real
'Image (Max_Error
) );
166 if Actual
= Expected
then
167 Report
.Comment
(Test_Name
& " exact result");
169 Report
.Comment
(Test_Name
& " passed");
175 procedure Special_Value_Test
is
176 -- If eta is very small, arctan(x + eta) ~= arctan(x) + eta/(1+x*x).
178 -- For tests 4 and 5, there is an error of 4.0ME for arctan + an
179 -- additional error of 1.0ME because pi is not exact for a total of 5.0ME.
181 -- In test 3 there is the error for pi plus an additional error
182 -- of (1.0ME)/4 since sqrt3 is not exact, for a total of 5.25ME.
184 -- In test 2 there is the error for pi plus an additional error
185 -- of (3/4)(1.0ME) since sqrt3 is not exact, for a total of 5.75ME.
193 Allowed_Error
: Real
;
196 type Test_Data_Type
is array (Positive range <>) of Data_Point
;
198 -- the values in the following table only involve static
199 -- expressions so no additional loss of precision occurs.
200 Test_Data
: constant Test_Data_Type
:= (
201 -- degrees radians tangent error test #
202 ( 0.0, 0.0, 0.0, 4.0 ), -- 1
203 ( 30.0, Pi
/6.0, Sqrt3
/3.0, 5.75), -- 2
204 ( 60.0, Pi
/3.0, Sqrt3
, 5.25), -- 3
205 ( 45.0, Pi
/4.0, 1.0, 5.0 ), -- 4
206 (-45.0, -Pi
/4.0, -1.0, 5.0 ) ); -- 5
209 for I
in Test_Data
'Range loop
210 Check
(Arctan
(Test_Data
(I
).Tangent
),
211 Test_Data
(I
).Radians
,
212 "special value test" & Integer'Image (I
) &
214 Real
'Image (Test_Data
(I
).Tangent
) &
216 Test_Data
(I
).Allowed_Error
);
217 Check
(Arctan
(Test_Data
(I
).Tangent
, Cycle
=> 360.0),
218 Test_Data
(I
).Degrees
,
219 "special value test" & Integer'Image (I
) &
221 Real
'Image (Test_Data
(I
).Tangent
) &
223 Test_Data
(I
).Allowed_Error
);
227 when Constraint_Error
=>
228 Report
.Failed
("Constraint_Error raised in special value test");
230 Report
.Failed
("exception in special value test");
231 end Special_Value_Test
;
235 procedure Check_Exact
(Actual
, Expected_Low
, Expected_High
: Real
;
236 Test_Name
: String) is
237 -- If the expected result is not a model number, then Expected_Low is
238 -- the first machine number less than the (exact) expected
239 -- result, and Expected_High is the first machine number greater than
240 -- the (exact) expected result. If the expected result is a model
241 -- number, Expected_Low = Expected_High = the result.
242 Model_Expected_Low
: Real
:= Expected_Low
;
243 Model_Expected_High
: Real
:= Expected_High
;
245 -- Calculate the first model number nearest to, but below (or equal)
246 -- to the expected result:
247 while Real
'Model (Model_Expected_Low
) /= Model_Expected_Low
loop
248 -- Try the next machine number lower:
249 Model_Expected_Low
:= Real
'Adjacent(Model_Expected_Low
, 0.0);
251 -- Calculate the first model number nearest to, but above (or equal)
252 -- to the expected result:
253 while Real
'Model (Model_Expected_High
) /= Model_Expected_High
loop
254 -- Try the next machine number higher:
255 Model_Expected_High
:= Real
'Adjacent(Model_Expected_High
, 100.0);
258 if Actual
< Model_Expected_Low
or Actual
> Model_Expected_High
then
259 Accuracy_Error_Reported
:= True;
260 if Actual
< Model_Expected_Low
then
261 Report
.Failed
(Test_Name
&
262 " actual: " & Real
'Image (Actual
) &
263 " expected low: " & Real
'Image (Model_Expected_Low
) &
264 " expected high: " & Real
'Image (Model_Expected_High
) &
265 " difference: " & Real
'Image (Actual
- Expected_Low
));
267 Report
.Failed
(Test_Name
&
268 " actual: " & Real
'Image (Actual
) &
269 " expected low: " & Real
'Image (Model_Expected_Low
) &
270 " expected high: " & Real
'Image (Model_Expected_High
) &
271 " difference: " & Real
'Image (Expected_High
- Actual
));
274 Report
.Comment
(Test_Name
& " passed");
279 procedure Exact_Result_Test
is
282 Check_Exact
(Arctan
(0.0, 1.0), 0.0, 0.0, "arctan(0,1)");
283 Check_Exact
(Arctan
(0.0, 1.0, 27.0), 0.0, 0.0, "arctan(0,1,27)");
287 Check_Exact
(Arctan
(1.0, 0.0), Half_PI_Low
, Half_PI_High
,
289 Check_Exact
(Arctan
(1.0, 0.0, 360.0), 90.0, 90.0, "arctan(1,0,360)");
291 Check_Exact
(Arctan
(-1.0, 0.0), -Half_PI_High
, -Half_PI_Low
,
293 Check_Exact
(Arctan
(-1.0, 0.0, 360.0), -90.0, -90.0,
296 if Real
'Signed_Zeros then
297 Check_Exact
(Arctan
(0.0, -1.0), PI_Low
, PI_High
, "arctan(+0,-1)");
298 Check_Exact
(Arctan
(0.0, -1.0, 360.0), 180.0, 180.0,
299 "arctan(+0,-1,360)");
300 Check_Exact
(Arctan
( Real
( ImpDef
.Annex_G
.Negative_Zero
), -1.0),
301 -PI_High
, -PI_Low
, "arctan(-0,-1)");
302 Check_Exact
(Arctan
( Real
( ImpDef
.Annex_G
.Negative_Zero
), -1.0,
303 360.0), -180.0, -180.0, "arctan(-0,-1,360)");
305 Check_Exact
(Arctan
(0.0, -1.0), PI_Low
, PI_High
, "arctan(0,-1)");
306 Check_Exact
(Arctan
(0.0, -1.0, 360.0), 180.0, 180.0,
310 when Constraint_Error
=>
311 Report
.Failed
("Constraint_Error raised in Exact_Result Test");
313 Report
.Failed
("Exception in Exact_Result Test");
314 end Exact_Result_Test
;
317 procedure Taylor_Series_Test
is
318 -- This test checks the Arctan by using a taylor series expansion that
319 -- will produce a result accurate to 19 decimal digits for
320 -- the range under test.
322 -- The maximum relative error bound for this test is
323 -- 4 for the arctan operation and 2 for the Taylor series
324 -- for a total of 6 * Model_Epsilon
326 A
: constant := -1.0/16.0;
327 B
: constant := 1.0/16.0;
329 Actual
, Expected
: Real
;
330 Sum
, Em
, X_Squared
: Real
;
332 if Real
'Digits > 19 then
333 -- Taylor series calculation produces result accurate to 19
334 -- digits. If type being tested has more digits then set
335 -- the error low bound to account for this.
336 -- The error low bound is conservatively set to 6*10**-19
337 Error_Low_Bound
:= 0.00000_00000_00000_0006
;
338 Report
.Comment
("arctan accuracy checked to 19 digits");
341 Accuracy_Error_Reported
:= False; -- reset
342 for I
in 0..Max_Samples
loop
343 X
:= (B
- A
) * Real
(I
) / Real
(Max_Samples
) + A
;
346 Sum
:= X_Squared
/ Em
;
348 for II
in 1 .. 7 loop
350 Sum
:= (1.0 / Em
- Sum
) * X_Squared
;
354 Sum
:= (X
- Expected
) + Sum
;
355 if not Real
'Machine_Rounds then
356 Expected
:= Expected
+ (Sum
+ Sum
);
359 Actual
:= Arctan
(X
);
361 Check
(Actual
, Expected
,
362 "Taylor_Series_Test " & Integer'Image (I
) & ": arctan(" &
363 Real
'Image (X
) & ") ",
366 if Accuracy_Error_Reported
then
367 -- only report the first error in this test in order to keep
368 -- lots of failures from producing a huge error log
373 Error_Low_Bound
:= 0.0; -- reset
375 when Constraint_Error
=>
377 ("Constraint_Error raised in Taylor_Series_Test");
379 Report
.Failed
("exception in Taylor_Series_Test");
380 end Taylor_Series_Test
;
383 procedure Exception_Test
is
384 X1
, X2
, X3
: Real
:= 0.0;
387 begin -- A.5.1(20);6.0
388 X1
:= Arctan
(0.0, Cycle
=> 0.0);
389 Report
.Failed
("no exception for cycle = 0.0");
391 when Ada
.Numerics
.Argument_Error
=> null;
393 Report
.Failed
("wrong exception for cycle = 0.0");
396 begin -- A.5.1(20);6.0
397 X2
:= Arctan
(0.0, Cycle
=> -1.0);
398 Report
.Failed
("no exception for cycle < 0.0");
400 when Ada
.Numerics
.Argument_Error
=> null;
402 Report
.Failed
("wrong exception for cycle < 0.0");
405 begin -- A.5.1(25);6.0
406 X3
:= Arctan
(0.0, 0.0);
407 Report
.Failed
("no exception for arctan(0,0)");
409 when Ada
.Numerics
.Argument_Error
=> null;
411 Report
.Failed
("wrong exception for arctan(0,0)");
414 -- optimizer thwarting
415 if Report
.Ident_Bool
(False) then
416 Report
.Comment
(Real
'Image (X1
+ X2
+ X3
));
430 -----------------------------------------------------------------------
431 -----------------------------------------------------------------------
432 -- These expressions must be truly static, which is why we have to do them
433 -- outside of the generic, and we use the named numbers. Note that we know
434 -- that PI is not a machine number (it is irrational), and it should be
435 -- represented to more digits than supported by the target machine.
436 Float_Half_PI_Low
: constant := Float'Adjacent(PI
/2.0, 0.0);
437 Float_Half_PI_High
: constant := Float'Adjacent(PI
/2.0, 10.0);
438 Float_PI_Low
: constant := Float'Adjacent(PI
, 0.0);
439 Float_PI_High
: constant := Float'Adjacent(PI
, 10.0);
440 package Float_Check
is new Generic_Check
(Float,
441 Half_PI_Low
=> Float_Half_PI_Low
,
442 Half_PI_High
=> Float_Half_PI_High
,
443 PI_Low
=> Float_PI_Low
,
444 PI_High
=> Float_PI_High
);
446 -- check the Floating point type with the most digits
447 type A_Long_Float
is digits System
.Max_Digits
;
448 A_Long_Float_Half_PI_Low
: constant := A_Long_Float
'Adjacent(PI
/2.0, 0.0);
449 A_Long_Float_Half_PI_High
: constant := A_Long_Float
'Adjacent(PI
/2.0, 10.0);
450 A_Long_Float_PI_Low
: constant := A_Long_Float
'Adjacent(PI
, 0.0);
451 A_Long_Float_PI_High
: constant := A_Long_Float
'Adjacent(PI
, 10.0);
452 package A_Long_Float_Check
is new Generic_Check
(A_Long_Float
,
453 Half_PI_Low
=> A_Long_Float_Half_PI_Low
,
454 Half_PI_High
=> A_Long_Float_Half_PI_High
,
455 PI_Low
=> A_Long_Float_PI_Low
,
456 PI_High
=> A_Long_Float_PI_High
);
458 -----------------------------------------------------------------------
459 -----------------------------------------------------------------------
463 Report
.Test
("CXG2016",
464 "Check the accuracy of the ARCTAN function");
467 Report
.Comment
("checking Standard.Float");
473 Report
.Comment
("checking a digits" &
474 Integer'Image (System
.Max_Digits
) &
475 " floating point type");
478 A_Long_Float_Check
.Do_Test
;