]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/language/c/libm/v2_0/tests/vectors/vector_support.h
Initial revision
[karo-tx-redboot.git] / packages / language / c / libm / v2_0 / tests / vectors / vector_support.h
1 #ifndef CYGONCE_LIBM_VECTOR_SUPPORT_H
2 #define CYGONCE_LIBM_VECTOR_SUPPORT_H
3 //========================================================================
4 //
5 //      vector_support.h
6 //
7 //      Support for testing of the math library using test vectors
8 //
9 //========================================================================
10 //####ECOSGPLCOPYRIGHTBEGIN####
11 // -------------------------------------------
12 // This file is part of eCos, the Embedded Configurable Operating System.
13 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
14 //
15 // eCos is free software; you can redistribute it and/or modify it under
16 // the terms of the GNU General Public License as published by the Free
17 // Software Foundation; either version 2 or (at your option) any later version.
18 //
19 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
20 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
22 // for more details.
23 //
24 // You should have received a copy of the GNU General Public License along
25 // with eCos; if not, write to the Free Software Foundation, Inc.,
26 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
27 //
28 // As a special exception, if other files instantiate templates or use macros
29 // or inline functions from this file, or you compile this file and link it
30 // with other works to produce a work based on this file, this file does not
31 // by itself cause the resulting work to be covered by the GNU General Public
32 // License. However the source code for this file must still be made available
33 // in accordance with section (3) of the GNU General Public License.
34 //
35 // This exception does not invalidate any other reasons why a work based on
36 // this file might be covered by the GNU General Public License.
37 //
38 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
39 // at http://sources.redhat.com/ecos/ecos-license/
40 // -------------------------------------------
41 //####ECOSGPLCOPYRIGHTEND####
42 //========================================================================
43 //#####DESCRIPTIONBEGIN####
44 //
45 // Author(s):     jlarmour
46 // Contributors:  jlarmour
47 // Date:          1999-01-21
48 // Purpose:     
49 // Description: 
50 // Usage:         #include "vectors/vector_support.h"
51 //
52 //####DESCRIPTIONEND####
53 //
54 //========================================================================
55
56 // CONFIGURATION
57
58 #include <pkgconf/libm.h>      // Configuration header
59 #include <pkgconf/isoinfra.h>  // CYGINT_ISO_MAIN_STARTUP
60
61 // INCLUDES
62
63 #include <cyg/infra/cyg_type.h>   // Common type definitions and support
64 #include <cyg/infra/testcase.h>   // Test infrastructure
65 #include <math.h>                 // Header for this package
66 #include <sys/ieeefp.h>           // Cyg_libm_ieee_double_shape_type
67 #include <cyg/infra/diag.h>
68
69 #ifndef CYGSEM_LIBM_COMPAT_IEEE_ONLY
70 # include <errno.h>                // For Cyg_ErrNo
71 #endif
72
73 // CONSTANTS
74
75 #define PROBLEM_THRESHOLD 10      // Number of test vectors allowed to fail
76                                   // before we give up completely
77
78 // HOW TO START TESTS
79
80 #if CYGINT_ISO_MAIN_STARTUP
81
82 # define START_TEST( test ) test(0)
83
84 #elif defined(CYGFUN_KERNEL_API_C)
85
86 # include <cyg/hal/hal_arch.h>
87 # include <cyg/kernel/kapi.h>
88
89 # define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
90
91 static cyg_uint8 stack[STACKSIZE];
92 static cyg_handle_t thr_handle;
93 static cyg_thread thr;
94
95 # define START_TEST( test ) CYG_MACRO_START \
96     cyg_thread_create( 4, &test, (cyg_addrword_t)0, "test", \
97                        &stack[0],  STACKSIZE, &thr_handle, &thr ); \
98     cyg_thread_resume( thr_handle ); \
99     cyg_scheduler_start(); \
100     CYG_MACRO_END
101
102 externC int main( int, char ** );
103
104 externC void
105 cyg_user_start( void )
106 {
107     (void) main(0, NULL);
108 } // cyg_user_start()
109
110 #else // !defined(CYGFUN_KERNEL_API_C)
111
112 externC int main( int, char ** );
113
114 externC void
115 cyg_user_start( void )
116 {
117     (void) main(0, NULL);
118 } // cyg_user_start()
119
120 # define START_TEST( test ) test(0)
121
122 #endif
123
124 // TYPE DEFINITIONS
125
126
127 typedef enum {
128     CYG_LIBM_TEST_VEC_NONE,         // this indicates whether the "double"
129     CYG_LIBM_TEST_VEC_INT,          // is being used to store a double, an
130     CYG_LIBM_TEST_VEC_DOUBLE,       // int, or its not being used at all!
131     CYG_LIBM_TEST_VEC_INT_P,        // int pointer
132     CYG_LIBM_TEST_VEC_DOUBLE_P      // double pointer
133 } Cyg_libm_test_arg_type;
134                               
135
136 // Define a type for a test vector record
137
138 typedef struct {
139     cyg_ucount32 vector_num;        // id number of this test vector record
140     
141     // if any of the following arguments are ints rather than doubles, then
142     // use the lsw part to store it
143
144     cyg_uint32 arg1_msw;   // first argument
145     cyg_uint32 arg1_lsw;
146     cyg_uint32 arg2_msw;   // second argument
147     cyg_uint32 arg2_lsw;
148     cyg_uint32 result_msw; // expected return value
149     cyg_uint32 result_lsw;
150
151 #ifndef CYGSEM_LIBM_COMPAT_IEEE_ONLY
152     Cyg_ErrNo errno_val;           // expected value of errno. 0==unchanged
153 #else
154     cyg_uint32 errno_val;
155 #endif
156
157     double tolerance;              // relative amount that it is allowed
158                                    // to vary. i.e. the value should be
159                                    // plus or minus result*tolerance
160
161     int matherr_type;              // if testing the matherr() function,
162                                    // what type should the exception be
163 } Cyg_libm_test_double_vec_t;
164
165
166 // types to cope with the different forms of function to be called by the
167 // test vector
168
169 typedef double (*ddfn)( double, double );
170 typedef double (*difn)( double, int );
171 typedef double (*dfn)( double );
172 typedef double (*ddpfn)( double, double *);
173 typedef double (*dipfn)( double, int *);
174
175
176 // STATIC FUNCTIONS
177
178 // equivalent of abs() for doubles. We want to be independent of fabs()
179
180 static double
181 my_abs_d( double x )
182 {
183     Cyg_libm_ieee_double_shape_type t;
184
185     t.value = x;
186
187     t.number.sign = 0;
188
189     return t.value;
190 } // my_abs_d()
191
192
193 static cyg_bool
194 checkErrorAcceptable( Cyg_libm_ieee_double_shape_type is,
195                       Cyg_libm_ieee_double_shape_type shouldbe,
196                       double tolerance) // _relative_ amount it can vary
197 {
198     Cyg_libm_ieee_double_shape_type temp_doub;
199
200     // first do a short-circuit check if its identical
201     if ( (is.parts.lsw == shouldbe.parts.lsw) &&
202          (is.parts.msw == shouldbe.parts.msw) )
203         return false;
204     
205     // now check special cases
206     
207     // +0 == -0
208     if ( (is.parts.lsw == 0) && (shouldbe.parts.lsw == 0) &&
209          ((is.parts.msw & 0x7fffffff) == 0) &&
210          ((shouldbe.parts.msw & 0x7fffffff) == 0) )
211         return false;
212
213     // +-infinity == +-infinity
214     if ((is.parts.lsw == 0) && (shouldbe.parts.lsw == 0) &&
215         (is.number.fraction0 == 0) && (shouldbe.number.fraction0 == 0) &&
216         (is.number.exponent == 2047) && (shouldbe.number.exponent == 2047))
217     {
218         return (is.number.sign != shouldbe.number.sign);
219     } // if
220
221     // both NaN. Assumes isnan works, but its pretty safe
222     if ( isnan(is.value) && isnan(shouldbe.value) )
223         return false;
224     else if (isnan(is.value) || isnan(shouldbe.value) )
225         return true;
226
227     // check same sign. Even around small values close to 0 we would want
228     // it to be on the right _side_ of 0
229     if ( is.number.sign != shouldbe.number.sign )
230         return true;
231
232     // okay, now work out what tolerance means for us
233
234     // find out what the difference is in the first place
235     temp_doub.value = my_abs_d( shouldbe.value - is.value );
236
237     // Check "both ways round" to deal with both under and overflow cases
238     if ( ((temp_doub.value / tolerance) < my_abs_d(shouldbe.value)) ||
239          (temp_doub.value < (my_abs_d(shouldbe.value) * tolerance)) )
240         return false;
241     else
242         return true; // so its not close enough
243     
244 } // checkErrorAcceptable()
245
246
247 // This allows us to run through any test vectors of form:
248 // double = fn(double, double)
249 // double = fn(double)
250 // double = fn(double, int)
251 // double = fn(double, int *)
252 // double = fn(double, double *)
253 //
254 // result type being non-double is left as a future enhancement
255 //
256 // This returns true if the tests all succeeded and false if any failed
257 //
258 static cyg_bool
259 doTestVec( CYG_ADDRESS func_ptr,
260            Cyg_libm_test_arg_type arg1_type,
261            Cyg_libm_test_arg_type arg2_type,
262            Cyg_libm_test_arg_type result_type,
263            const Cyg_libm_test_double_vec_t *vectors,
264            cyg_ucount32 num_vectors )
265 {
266     cyg_ucount32 problems=0;
267     cyg_ucount32 i;
268     Cyg_libm_ieee_double_shape_type arg1, arg2, result_wanted, ret;
269     cyg_ucount32 alive_count = num_vectors / 10;
270
271     if ((arg1_type != CYG_LIBM_TEST_VEC_DOUBLE) ||
272         (result_type != CYG_LIBM_TEST_VEC_DOUBLE) ) {
273         CYG_TEST_FAIL("Test vector arguments are not correct type!");
274         return false;
275     } // if
276
277     switch (arg2_type) {
278     case CYG_LIBM_TEST_VEC_DOUBLE:
279
280         {
281             ddfn fn = (ddfn) func_ptr;
282
283             for (i=0;
284                  (i < num_vectors) && (problems < PROBLEM_THRESHOLD);
285                  i++) {
286
287                 if (0 == i % alive_count)
288                     CYG_TEST_STILL_ALIVE(i, "Still crunching, please wait...");
289
290                 arg1.parts.msw = vectors[i].arg1_msw;
291                 arg1.parts.lsw = vectors[i].arg1_lsw;
292
293                 arg2.parts.msw = vectors[i].arg2_msw;
294                 arg2.parts.lsw = vectors[i].arg2_lsw;
295
296                 result_wanted.parts.msw = vectors[i].result_msw;
297                 result_wanted.parts.lsw = vectors[i].result_lsw;
298
299                 ret.value = (*fn)( arg1.value, arg2.value );
300
301                 if ((vectors[i].errno_val) != 0) {
302
303 #ifndef CYGSEM_LIBM_COMPAT_IEEE_ONLY
304                     // In IEEE-mode we can't check the answer if this
305                     // is an error case
306
307                     if ((cyg_libm_get_compat_mode() !=
308                         CYGNUM_LIBM_COMPAT_IEEE) &&
309                         (errno != vectors[i].errno_val)) {
310
311                         ++problems;
312                         diag_printf("Vector #%d\n", i+1);
313                         CYG_TEST_FAIL( "error not set correctly");
314
315                     } // if
316 #endif
317
318                     continue; // no point checking value in an error case
319                 } // if
320                 if (checkErrorAcceptable( ret, result_wanted,
321                                           vectors[i].tolerance) ) {
322                     ++problems;
323                     diag_printf("Vector #%d\n", i+1);
324                     CYG_TEST_FAIL( "Result out of tolerance");
325                 } // if
326             } // for
327             
328         } // compound
329             
330         break;
331
332     case CYG_LIBM_TEST_VEC_INT:
333
334         {
335             difn fn = (difn) func_ptr;
336         
337             for (i=0;
338                  (i < num_vectors) && (problems < PROBLEM_THRESHOLD);
339                  i++) {
340
341                 if (0 == i % alive_count)
342                     CYG_TEST_STILL_ALIVE(i, "Still crunching, please wait...");
343
344                 arg1.parts.msw = vectors[i].arg1_msw;
345                 arg1.parts.lsw = vectors[i].arg1_lsw;
346
347                 result_wanted.parts.msw = vectors[i].result_msw;
348                 result_wanted.parts.lsw = vectors[i].result_lsw;
349
350                 ret.value = (*fn)( arg1.value, vectors[i].arg2_lsw );
351                 if (checkErrorAcceptable( ret, result_wanted,
352                                           vectors[i].tolerance) ) {
353                     ++problems;
354                     diag_printf("Vector #%d\n", i+1);
355                     CYG_TEST_FAIL( "Result out of tolerance");
356                 } // if
357             } // for
358             
359         } // compound
360             
361         break;
362
363     case CYG_LIBM_TEST_VEC_INT_P:
364
365         {
366             dipfn fn = (dipfn) func_ptr;
367             int my_int;
368             Cyg_libm_ieee_double_shape_type my_doub1, my_doub2;
369         
370             for (i=0;
371                  (i < num_vectors) && (problems < PROBLEM_THRESHOLD);
372                  i++) {
373
374                 if (0 == i % alive_count)
375                     CYG_TEST_STILL_ALIVE(i, "Still crunching, please wait...");
376
377                 arg1.parts.msw = vectors[i].arg1_msw;
378                 arg1.parts.lsw = vectors[i].arg1_lsw;
379
380
381                 result_wanted.parts.msw = vectors[i].result_msw;
382                 result_wanted.parts.lsw = vectors[i].result_lsw;
383
384                 ret.value = (*fn)( arg1.value, &my_int );
385                 if (checkErrorAcceptable( ret, result_wanted,
386                                           vectors[i].tolerance) ) {
387                     ++problems;
388                     diag_printf("Vector #%d\n", i+1);
389                     CYG_TEST_FAIL( "Result out of tolerance");
390                 } // if
391
392                 my_doub1.value = (double) my_int;
393                 my_doub2.value = (double) (signed)vectors[i].arg2_lsw;
394                 
395                 if (checkErrorAcceptable( my_doub1, my_doub2,
396                                           vectors[i].tolerance) ) {
397                     ++problems;
398                     diag_printf("Vector #%d\n", i+1);
399                     CYG_TEST_FAIL( "Integer result out of tolerance");
400                 } // if
401
402                 
403             } // for
404             
405         } // compound
406             
407         break;
408
409     case CYG_LIBM_TEST_VEC_DOUBLE_P:
410
411         {
412             ddpfn fn = (ddpfn) func_ptr;
413             Cyg_libm_ieee_double_shape_type my_doub1;
414         
415             for (i=0;
416                  (i < num_vectors) && (problems < PROBLEM_THRESHOLD);
417                  i++) {
418
419                 if (0 == i % alive_count)
420                     CYG_TEST_STILL_ALIVE(i, "Still crunching, please wait...");
421
422                 arg1.parts.msw = vectors[i].arg1_msw;
423                 arg1.parts.lsw = vectors[i].arg1_lsw;
424
425                 arg2.parts.msw = vectors[i].arg2_msw;
426                 arg2.parts.lsw = vectors[i].arg2_lsw;
427
428
429                 result_wanted.parts.msw = vectors[i].result_msw;
430                 result_wanted.parts.lsw = vectors[i].result_lsw;
431
432                 ret.value = (*fn)( arg1.value, &my_doub1.value );
433                 if (checkErrorAcceptable( ret, result_wanted,
434                                           vectors[i].tolerance) ) {
435                     ++problems;
436                     diag_printf("Vector #%d\n", i+1);
437                     CYG_TEST_FAIL( "Result out of tolerance");
438                 } // if
439
440                 if (checkErrorAcceptable( my_doub1, arg2,
441                                           vectors[i].tolerance) ) {
442                     ++problems;
443                     diag_printf("Vector #%d\n", i+1);
444                     CYG_TEST_FAIL( "Returned double result out of "
445                                    "tolerance");
446                 } // if
447
448                 
449             } // for
450             
451         } // compound
452             
453         break;
454
455     case CYG_LIBM_TEST_VEC_NONE:
456
457         {
458             dfn fn = (dfn) func_ptr;
459         
460             for (i=0;
461                  (i < num_vectors) && (problems < PROBLEM_THRESHOLD);
462                  i++) {
463
464                 if (0 == i % alive_count)
465                     CYG_TEST_STILL_ALIVE(i, "Still crunching, please wait...");
466
467                 arg1.parts.msw = vectors[i].arg1_msw;
468                 arg1.parts.lsw = vectors[i].arg1_lsw;
469
470                 result_wanted.parts.msw = vectors[i].result_msw;
471                 result_wanted.parts.lsw = vectors[i].result_lsw;
472
473                 ret.value = (*fn)( arg1.value );
474                 if (checkErrorAcceptable( ret, result_wanted,
475                                           vectors[i].tolerance) ) {
476                     ++problems;
477                     diag_printf("Vector #%d\n", i+1);
478                     CYG_TEST_FAIL( "Result out of tolerance");
479                 } // if
480             } // for
481             
482         } // compound
483             
484         break;
485
486     default:
487         CYG_TEST_FAIL("Second argument of unknown type!");
488         return false;
489     } // switch
490
491     if (problems != 0)
492         return false;
493     else
494         return true;
495
496 } // doTestVec()
497
498 #endif // CYGONCE_LIBM_VECTOR_SUPPORT_H multiple inclusion protection
499
500 // EOF vector_support.h