1-- CXA5A10.A
2--
3--                             Grant of Unlimited Rights
4--
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
14--     to do so.
15--
16--                                    DISCLAIMER
17--
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.
24--*
25--
26-- OBJECTIVE:
27--      Check that the functions Exp and Sqrt, and the exponentiation
28--      operator "**" provide correct results.
29--
30-- TEST DESCRIPTION:
31--      This test examines both the versions of Exp, Sqrt, and "**"
32--      resulting from the instantiation of the
33--      Ada.Numerics.Generic_Elementary_Functions with a type derived from
34--      type Float, as well as the preinstantiated version of this package
35--      for type Float.
36--      Prescribed results (stated as such in the reference manual),
37--      including instances prescribed to raise exceptions, are examined
38--      in the test cases.  In addition, certain evaluations are performed
39--      for the preinstantiated package where the actual function result is
40--      compared with the expected result (within an epsilon range of
41--      accuracy).
42--
43-- TEST FILES:
44--      The following files comprise this test:
45--
46--         FXA5A00.A   (foundation code)
47--         CXA5A10.A
48--
49--
50-- CHANGE HISTORY:
51--      17 Apr 95   SAIC    Initial prerelease version.
52--      13 Jun 95   SAIC    Incorporated use of Dont_Optimize procedure, and
53--                          use of Result_Within_Range function overloaded for
54--                          FXA5A00.New_Float_Type.
55--      18 Apr 96   SAIC    Incorporated reviewer comments for ACVC 2.1.
56--      01 Oct 01   RLB     Protected Constraint_Error exception tests by
57--                          first testing for 'Machine_Overflows.
58--
59--!
60
61with Ada.Exceptions;
62with Ada.Numerics.Elementary_Functions;
63with Ada.Numerics.Generic_Elementary_Functions;
64with FXA5A00;
65with Report;
66
67procedure CXA5A10 is
68begin
69
70   Report.Test ("CXA5A10", "Check that Exp, Sqrt, and the ""**"" operator " &
71                           "provide correct results");
72
73   Test_Block:
74   declare
75
76      use FXA5A00, Ada.Numerics;
77      use Ada.Exceptions;
78
79      package GEF is new Ada.Numerics.Generic_Elementary_Functions(New_Float);
80      package  EF renames Ada.Numerics.Elementary_Functions;
81
82      use GEF, EF;
83
84      Arg,
85      Float_Result     : Float;
86      New_Float_Result : New_Float;
87
88      Flag_1, Flag_2, Flag_3, Flag_4,
89      Incorrect_Inverse_Base_e,
90      Incorrect_Inverse_Base_2,
91      Incorrect_Inverse_Base_8,
92      Incorrect_Inverse_Base_10,
93      Incorrect_Inverse_Base_16        : Boolean := False;
94
95      procedure Dont_Optimize_Float     is new Dont_Optimize(Float);
96      procedure Dont_Optimize_New_Float is new Dont_Optimize(New_Float);
97
98   begin
99
100      -- Testing of the "**" operator, both instantiated and pre-instantiated
101      -- version.
102
103      -- Check that Argument_Error is raised by the exponentiation operator
104      -- when the value of the Left parameter (operand) is negative.
105
106      begin
107         New_Float_Result := GEF."**"(Left  => -10.0,
108                                      Right =>   2.0);
109         Report.Failed("Argument_Error not raised by the instantiated "   &
110                       "version of the exponentiation operator when the " &
111                       "value of the Left parameter is negative");
112         Dont_Optimize_New_Float(New_Float_Result, 1);
113      exception
114         when Argument_Error => null;  -- OK, expected exception.
115         when others         =>
116            Report.Failed("Unexpected exception raised by the "            &
117                          "instantiated version of the exponentiation "    &
118                          "operator when the value of the Left parameter " &
119                          "is negative");
120      end;
121
122      begin
123         Float_Result := (-FXA5A00.Small) ** 4.0;
124         Report.Failed("Argument_Error not raised by the preinstantiated " &
125                       "version of the exponentiation operator when the "  &
126                       "value of the Left parameter is negative");
127         Dont_Optimize_Float(Float_Result, 2);
128      exception
129         when Argument_Error => null;  -- OK, expected exception.
130         when others         =>
131            Report.Failed("Unexpected exception raised by the "            &
132                          "preinstantiated version of the exponentiation " &
133                          "operator when the value of the Left parameter " &
134                          "is negative");
135      end;
136
137
138      -- Check that Argument_Error is raised by the exponentiation operator
139      -- when both parameters (operands) have the value 0.0.
140
141      begin
142         New_Float_Result := GEF."**"(0.0, Right => 0.0);
143         Report.Failed("Argument_Error not raised by the instantiated " &
144                       "version of the exponentiation operator when "   &
145                       "both operands are zero");
146         Dont_Optimize_New_Float(New_Float_Result, 3);
147      exception
148         when Argument_Error => null;  -- OK, expected exception.
149         when others         =>
150            Report.Failed("Unexpected exception raised by the "         &
151                          "instantiated version of the exponentiation " &
152                          "operator when both operands are zero");
153      end;
154
155      begin
156         Float_Result := 0.0**0.0;
157         Report.Failed("Argument_Error not raised by the preinstantiated " &
158                       "version of the exponentiation operator when both " &
159                       "operands are zero");
160         Dont_Optimize_Float(Float_Result, 4);
161      exception
162         when Argument_Error => null;  -- OK, expected exception.
163         when others         =>
164            Report.Failed("Unexpected exception raised by the "            &
165                          "preinstantiated version of the exponentiation " &
166                          "operator when both operands are zero");
167      end;
168
169
170      -- Check that Constraint_Error is raised by the exponentiation
171      -- operator when the value of the left parameter (operand) is zero,
172      -- and the value of the right parameter (exponent) is negative.
173      -- This check applies only if Machine_Overflows is true [A.5.1(28, 30)].
174
175      if New_Float'Machine_Overflows = True then
176         begin
177            New_Float_Result := GEF."**"(0.0, Right => -2.0);
178            Report.Failed("Constraint_Error not raised by the instantiated " &
179                          "version of the exponentiation operator when "     &
180                          "the left parameter is 0.0, and the right "        &
181                          "parameter is negative");
182            Dont_Optimize_New_Float(New_Float_Result, 5);
183         exception
184            when Constraint_Error => null;  -- OK, expected exception.
185            when others           =>
186               Report.Failed("Unexpected exception raised by the "         &
187                             "instantiated version of the exponentiation " &
188                             "operator when the left parameter is 0.0, "   &
189                             "and the right parameter is negative");
190         end;
191      end if;
192
193      if Float'Machine_Overflows = True then
194         begin
195            Float_Result := 0.0 ** (-FXA5A00.Small);
196            Report.Failed("Constraint_Error not raised by the " &
197                          "preinstantiated version of the exponentiation " &
198                          "operator when the left parameter is 0.0, and the " &
199                          "right parameter is negative");
200            Dont_Optimize_Float(Float_Result, 6);
201         exception
202            when Constraint_Error => null;  -- OK, expected exception.
203            when others           =>
204               Report.Failed("Unexpected exception raised by the "            &
205                             "preinstantiated version of the exponentiation " &
206                             "operator when the left parameter is 0.0, and "  &
207                             "the right parameter is negative");
208         end;
209      end if;
210
211      -- Prescribed results.
212      -- Check that exponentiation by a 0.0 exponent yields the value one.
213
214      if GEF."**"(Left => 10.0,  Right => 0.0) /= 1.0 or
215          EF."**"(FXA5A00.Large, Right => 0.0) /= 1.0 or
216         GEF."**"(3.0, 0.0)                    /= 1.0 or
217          FXA5A00.Small ** 0.0                 /= 1.0
218      then
219         Report.Failed("Incorrect results returned from the ""**"" " &
220                       "operator when the value of the exponent is 0.0");
221      end if;
222
223
224      -- Check that exponentiation by a unit exponent yields the value
225      -- of the left operand.
226
227      if GEF."**"(Left => 50.0,  Right => 1.0) /= 50.0          or
228          EF."**"(FXA5A00.Large, Right => 1.0) /= FXA5A00.Large or
229         GEF."**"(6.0, 1.0)                    /= 6.0           or
230          FXA5A00.Small ** 1.0                 /= FXA5A00.Small
231      then
232         Report.Failed("Incorrect results returned from the ""**"" " &
233                       "operator when the value of the exponent is 1.0");
234      end if;
235
236
237      -- Check that exponentiation of the value 1.0 yields the value 1.0.
238
239      if GEF."**"(Left => 1.0, Right => 16.0)   /=  1.0 or
240          EF."**"(1.0, Right => FXA5A00.Large)  /=  1.0 or
241         GEF."**"(1.0, 3.0)                     /=  1.0 or
242          1.0 ** FXA5A00.Small                  /=  1.0
243      then
244         Report.Failed("Incorrect results returned from the ""**"" " &
245                       "operator when the value of the operand is 1.0");
246      end if;
247
248
249      -- Check that exponentiation of the value 0.0 yields the value 0.0.
250
251      if GEF."**"(Left => 0.0, Right => 10.0)   /=  0.0 or
252          EF."**"(0.0, Right => FXA5A00.Large)  /=  0.0 or
253         GEF."**"(0.0, 4.0)                     /=  0.0 or
254          0.0 ** FXA5A00.Small                  /=  0.0
255      then
256         Report.Failed("Incorrect results returned from the ""**"" " &
257                       "operator when the value of the operand is 0.0");
258      end if;
259
260
261      -- Check that exponentiation of various operands with a variety of
262      -- of exponent values yield correct results.
263
264      if not Result_Within_Range(GEF."**"(5.0,   2.0),  25.0,   0.01)  or
265         not Result_Within_Range(GEF."**"(1.225, 1.5),   1.36,  0.01)  or
266         not Result_Within_Range(GEF."**"(0.26,  2.0),   0.068, 0.001) or
267         not Result_Within_Range( EF."**"(e,     5.0), 148.4,   0.1)   or
268         not Result_Within_Range( EF."**"(10.0,  e),   522.7,   0.1)   or
269         not Result_Within_Range( EF."**"(e,   (-3.0)),  0.050, 0.001) or
270         not Result_Within_Range(GEF."**"(10.0,(-2.0)),  0.010, 0.001)
271      then
272         Report.Failed("Incorrect results returned from the ""**"" "       &
273                       "operator with a variety of  operand and exponent " &
274                       "values");
275      end if;
276
277
278      -- Use the following loops to check for internal consistency between
279      -- inverse functions.
280
281      declare
282         -- Use the relative error value to account for non-exact
283         -- computations.
284         TC_Relative_Error: Float := 0.005;
285      begin
286         for i in 1..5 loop
287            for j in 0..5 loop
288               if not Incorrect_Inverse_Base_e and
289                  not FXA5A00.Result_Within_Range
290                        (Float(i)**Float(j),
291                         e**(Float(j)*EF.Log(Float(i))),
292                         TC_Relative_Error)
293               then
294                  Incorrect_Inverse_Base_e := True;
295                  Report.Failed("Incorrect Log-** Inverse calc for Base e " &
296                                "with i= " & Integer'Image(i) & "  and j= " &
297                                Integer'Image(j));
298               end if;
299               if not Incorrect_Inverse_Base_2 and
300                  not FXA5A00.Result_Within_Range
301                        (Float(i)**Float(j),
302                         2.0**(Float(j)*EF.Log(Float(i),2.0)),
303                         TC_Relative_Error)
304               then
305                  Incorrect_Inverse_Base_2 := True;
306                  Report.Failed("Incorrect Log-** Inverse calc for Base 2 " &
307                                "with i= " & Integer'Image(i) & "  and j= " &
308                                Integer'Image(j));
309               end if;
310               if not Incorrect_Inverse_Base_8 and
311                  not FXA5A00.Result_Within_Range
312                        (Float(i)**Float(j),
313                         8.0**(Float(j)*EF.Log(Float(i),8.0)),
314                         TC_Relative_Error)
315               then
316                  Incorrect_Inverse_Base_8 := True;
317                  Report.Failed("Incorrect Log-** Inverse calc for Base 8 " &
318                                "with i= " & Integer'Image(i) & "  and j= " &
319                                Integer'Image(j));
320               end if;
321               if not Incorrect_Inverse_Base_10 and
322                  not FXA5A00.Result_Within_Range
323                        (Float(i)**Float(j),
324                         10.0**(Float(j)*EF.Log(Float(i),10.0)),
325                         TC_Relative_Error)
326               then
327                  Incorrect_Inverse_Base_10 := True;
328                  Report.Failed("Incorrect Log-** Inverse calc for Base 10 " &
329                                "with i= " & Integer'Image(i) & "   and j= " &
330                                Integer'Image(j));
331               end if;
332               if not Incorrect_Inverse_Base_16 and
333                  not FXA5A00.Result_Within_Range
334                        (Float(i)**Float(j),
335                         16.0**(Float(j)*EF.Log(Float(i),16.0)),
336                         TC_Relative_Error)
337               then
338                  Incorrect_Inverse_Base_16 := True;
339                  Report.Failed("Incorrect Log-** Inverse calc for Base 16 " &
340                                "with i= " & Integer'Image(i) & "   and j= " &
341                                Integer'Image(j));
342               end if;
343            end loop;
344         end loop;
345      end;
346
347      -- Reset Flags.
348      Incorrect_Inverse_Base_e  := False;
349      Incorrect_Inverse_Base_2  := False;
350      Incorrect_Inverse_Base_8  := False;
351      Incorrect_Inverse_Base_10 := False;
352      Incorrect_Inverse_Base_16 := False;
353
354
355      -- Testing of Exp Function, both instantiated and pre-instantiated
356      -- version.
357
358      -- Check that the result of the Exp Function, when provided an X
359      -- parameter value of 0.0, is 1.0.
360
361      if GEF.Exp(X => 0.0) /= 1.0 or
362          EF.Exp(0.0)      /= 1.0
363      then
364         Report.Failed("Incorrect result returned by Function Exp when " &
365                       "given a parameter value of 0.0");
366      end if;
367
368
369      -- Check that the Exp Function provides correct results when provided
370      -- a variety of input parameter values.
371
372      if not Result_Within_Range(GEF.Exp(0.001),    1.01,  0.01)  or
373         not Result_Within_Range( EF.Exp(0.1),      1.11,  0.01)  or
374         not Result_Within_Range(GEF.Exp(1.2697),   3.56,  0.01)  or
375         not Result_Within_Range( EF.Exp(3.2525),  25.9,   0.1)   or
376         not Result_Within_Range(GEF.Exp(-0.2198),  0.803, 0.001) or
377         not Result_Within_Range( EF.Exp(-1.6621),  0.190, 0.001) or
378         not Result_Within_Range(GEF.Exp(-2.3888),  0.092, 0.001) or
379         not Result_Within_Range( EF.Exp(-5.4415),  0.004, 0.001)
380      then
381         Report.Failed("Incorrect result from Function Exp when provided " &
382                       "a variety of input parameter values");
383      end if;
384
385      -- Use the following loops to check for internal consistency between
386      -- inverse functions.
387
388      Arg := 0.01;
389      while Arg < 10.0 loop
390         if not Incorrect_Inverse_Base_e and
391            FXA5A00.Result_Within_Range(EF.Exp(Arg),
392                                        e**(Arg*EF.Log(Arg)),
393                                        0.001)
394         then
395            Incorrect_Inverse_Base_e := True;
396            Report.Failed("Incorrect Exp-** Inverse calc for Base e");
397         end if;
398         if not Incorrect_Inverse_Base_2 and
399            FXA5A00.Result_Within_Range(EF.Exp(Arg),
400                                        2.0**(Arg*EF.Log(Arg,2.0)),
401                                        0.001)
402         then
403            Incorrect_Inverse_Base_2 := True;
404            Report.Failed("Incorrect Exp-** Inverse calc for Base 2");
405         end if;
406         if not Incorrect_Inverse_Base_8 and
407            FXA5A00.Result_Within_Range(EF.Exp(Arg),
408                                        8.0**(Arg*EF.Log(Arg,8.0)),
409                                        0.001)
410         then
411            Incorrect_Inverse_Base_8 := True;
412            Report.Failed("Incorrect Exp-** Inverse calc for Base 8");
413         end if;
414         if not Incorrect_Inverse_Base_10 and
415            FXA5A00.Result_Within_Range(EF.Exp(Arg),
416                                        10.0**(Arg*EF.Log(Arg,10.0)),
417                                        0.001)
418         then
419            Incorrect_Inverse_Base_10 := True;
420            Report.Failed("Incorrect Exp-** Inverse calc for Base 10");
421         end if;
422         if not Incorrect_Inverse_Base_16 and
423            FXA5A00.Result_Within_Range(EF.Exp(Arg),
424                                        16.0**(Arg*EF.Log(Arg,16.0)),
425                                        0.001)
426         then
427            Incorrect_Inverse_Base_16 := True;
428            Report.Failed("Incorrect Exp-** Inverse calc for Base 16");
429         end if;
430         Arg := Arg + 0.01;
431      end loop;
432
433
434      -- Testing of Sqrt Function, both instantiated and pre-instantiated
435      -- version.
436
437      -- Check that Argument_Error is raised by the Sqrt Function when
438      -- the value of the input parameter X is negative.
439
440      begin
441         Float_Result := EF.Sqrt(X => -FXA5A00.Small);
442         Report.Failed("Argument_Error not raised by Function Sqrt "     &
443                       "when provided a small negative input parameter " &
444                       "value");
445         Dont_Optimize_Float(Float_Result, 7);
446      exception
447         when Argument_Error => null;  -- OK, expected exception.
448         when others         =>
449            Report.Failed("Unexpected exception raised by Function Sqrt "   &
450                          "when provided a small negative input parameter " &
451                          "value");
452      end;
453
454      begin
455         New_Float_Result := GEF.Sqrt(X => -64.0);
456         Report.Failed("Argument_Error not raised by Function Sqrt "     &
457                       "when provided a large negative input parameter " &
458                       "value");
459         Dont_Optimize_New_Float(New_Float_Result, 8);
460      exception
461         when Argument_Error => null;  -- OK, expected exception.
462         when others         =>
463            Report.Failed("Unexpected exception raised by Function Sqrt "   &
464                          "when provided a large negative input parameter " &
465                          "value");
466      end;
467
468
469      -- Check that the Sqrt Function, when given an X parameter value of 0.0,
470      -- returns a result of 0.0.
471
472      if GEF.Sqrt(X => 0.0) /= 0.0 or
473          EF.Sqrt(0.0)      /= 0.0
474      then
475         Report.Failed("Incorrect result from Function Sqrt when provided " &
476                       "an input parameter value of 0.0");
477      end if;
478
479
480      -- Check that the Sqrt Function, when given an X parameter input value
481      -- of 1.0, returns a result of 1.0.
482
483      if GEF.Sqrt(X => 1.0) /= 1.0 or
484          EF.Sqrt(1.0)      /= 1.0
485      then
486         Report.Failed("Incorrect result from Function Sqrt when provided " &
487                       "an input parameter value of 1.0");
488      end if;
489
490
491      -- Check that the Sqrt Function provides correct results when provided
492      -- a variety of input parameter values.
493
494      if not FXA5A00.Result_Within_Range(GEF.Sqrt(0.0327),     0.181, 0.001) or
495         not FXA5A00.Result_Within_Range( EF.Sqrt(0.1808),     0.425, 0.001) or
496         not FXA5A00.Result_Within_Range(GEF.Sqrt(1.0556),     1.03,  0.01)  or
497         not FXA5A00.Result_Within_Range( EF.Sqrt(32.8208),    5.73,  0.01)  or
498         not FXA5A00.Result_Within_Range( EF.Sqrt(27851.0),  166.9,   0.1)   or
499         not FXA5A00.Result_Within_Range( EF.Sqrt(61203.4),  247.4,   0.1)   or
500         not FXA5A00.Result_Within_Range( EF.Sqrt(655891.0), 809.9,   0.1)
501      then
502         Report.Failed("Incorrect result from Function Sqrt when provided " &
503                       "a variety of input parameter values");
504      end if;
505
506      -- Check internal consistency between functions.
507
508      Arg := 0.01;
509      while Arg < 10.0 loop
510         if not Flag_1 and
511            not FXA5A00.Result_Within_Range(Arg,
512                                            EF.Sqrt(Arg)*EF.Sqrt(Arg),
513                                            0.01)
514         then
515            Report.Failed("Inconsistency found in Case 1");
516            Flag_1 := True;
517         end if;
518         if not Flag_2 and
519            not FXA5A00.Result_Within_Range(Arg, EF.Sqrt(Arg)**2.0, 0.01)
520         then
521            Report.Failed("Inconsistency found in Case 2");
522            Flag_2 := True;
523         end if;
524         if not Flag_3 and
525            not FXA5A00.Result_Within_Range(EF.Log(Arg),
526                                            EF.Log(Sqrt(Arg)**2.0), 0.01)
527         then
528            Report.Failed("Inconsistency found in Case 3");
529            Flag_3 := True;
530         end if;
531         if not Flag_4 and
532            not FXA5A00.Result_Within_Range(EF.Log(Arg),
533                                            2.00*EF.Log(EF.Sqrt(Arg)),
534                                            0.01)
535         then
536            Report.Failed("Inconsistency found in Case 4");
537            Flag_4 := True;
538         end if;
539         Arg := Arg + 1.0;
540      end loop;
541
542
543   exception
544      when The_Error : others =>
545         Report.Failed ("The following exception was raised in the " &
546                        "Test_Block: " & Exception_Name(The_Error));
547   end Test_Block;
548
549   Report.Result;
550
551end CXA5A10;
552