1 #ifndef CYGONCE_LIBM_VECTOR_SUPPORT_H
2 #define CYGONCE_LIBM_VECTOR_SUPPORT_H
3 //========================================================================
7 // Support for testing of the math library using test vectors
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.
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.
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
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.
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.
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.
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####
45 // Author(s): jlarmour
46 // Contributors: jlarmour
50 // Usage: #include "vectors/vector_support.h"
52 //####DESCRIPTIONEND####
54 //========================================================================
58 #include <pkgconf/libm.h> // Configuration header
59 #include <pkgconf/isoinfra.h> // CYGINT_ISO_MAIN_STARTUP
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>
69 #ifndef CYGSEM_LIBM_COMPAT_IEEE_ONLY
70 # include <errno.h> // For Cyg_ErrNo
75 #define PROBLEM_THRESHOLD 10 // Number of test vectors allowed to fail
76 // before we give up completely
80 #if CYGINT_ISO_MAIN_STARTUP
82 # define START_TEST( test ) test(0)
84 #elif defined(CYGFUN_KERNEL_API_C)
86 # include <cyg/hal/hal_arch.h>
87 # include <cyg/kernel/kapi.h>
89 # define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
91 static cyg_uint8 stack[STACKSIZE];
92 static cyg_handle_t thr_handle;
93 static cyg_thread thr;
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(); \
102 externC int main( int, char ** );
105 cyg_user_start( void )
107 (void) main(0, NULL);
108 } // cyg_user_start()
110 #else // !defined(CYGFUN_KERNEL_API_C)
112 externC int main( int, char ** );
115 cyg_user_start( void )
117 (void) main(0, NULL);
118 } // cyg_user_start()
120 # define START_TEST( test ) test(0)
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;
136 // Define a type for a test vector record
139 cyg_ucount32 vector_num; // id number of this test vector record
141 // if any of the following arguments are ints rather than doubles, then
142 // use the lsw part to store it
144 cyg_uint32 arg1_msw; // first argument
146 cyg_uint32 arg2_msw; // second argument
148 cyg_uint32 result_msw; // expected return value
149 cyg_uint32 result_lsw;
151 #ifndef CYGSEM_LIBM_COMPAT_IEEE_ONLY
152 Cyg_ErrNo errno_val; // expected value of errno. 0==unchanged
154 cyg_uint32 errno_val;
157 double tolerance; // relative amount that it is allowed
158 // to vary. i.e. the value should be
159 // plus or minus result*tolerance
161 int matherr_type; // if testing the matherr() function,
162 // what type should the exception be
163 } Cyg_libm_test_double_vec_t;
166 // types to cope with the different forms of function to be called by the
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 *);
178 // equivalent of abs() for doubles. We want to be independent of fabs()
183 Cyg_libm_ieee_double_shape_type t;
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
198 Cyg_libm_ieee_double_shape_type temp_doub;
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) )
205 // now check special cases
208 if ( (is.parts.lsw == 0) && (shouldbe.parts.lsw == 0) &&
209 ((is.parts.msw & 0x7fffffff) == 0) &&
210 ((shouldbe.parts.msw & 0x7fffffff) == 0) )
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))
218 return (is.number.sign != shouldbe.number.sign);
221 // both NaN. Assumes isnan works, but its pretty safe
222 if ( isnan(is.value) && isnan(shouldbe.value) )
224 else if (isnan(is.value) || isnan(shouldbe.value) )
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 )
232 // okay, now work out what tolerance means for us
234 // find out what the difference is in the first place
235 temp_doub.value = my_abs_d( shouldbe.value - is.value );
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)) )
242 return true; // so its not close enough
244 } // checkErrorAcceptable()
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 *)
254 // result type being non-double is left as a future enhancement
256 // This returns true if the tests all succeeded and false if any failed
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 )
266 cyg_ucount32 problems=0;
268 Cyg_libm_ieee_double_shape_type arg1, arg2, result_wanted, ret;
269 cyg_ucount32 alive_count = num_vectors / 10;
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!");
278 case CYG_LIBM_TEST_VEC_DOUBLE:
281 ddfn fn = (ddfn) func_ptr;
284 (i < num_vectors) && (problems < PROBLEM_THRESHOLD);
287 if (0 == i % alive_count)
288 CYG_TEST_STILL_ALIVE(i, "Still crunching, please wait...");
290 arg1.parts.msw = vectors[i].arg1_msw;
291 arg1.parts.lsw = vectors[i].arg1_lsw;
293 arg2.parts.msw = vectors[i].arg2_msw;
294 arg2.parts.lsw = vectors[i].arg2_lsw;
296 result_wanted.parts.msw = vectors[i].result_msw;
297 result_wanted.parts.lsw = vectors[i].result_lsw;
299 ret.value = (*fn)( arg1.value, arg2.value );
301 if ((vectors[i].errno_val) != 0) {
303 #ifndef CYGSEM_LIBM_COMPAT_IEEE_ONLY
304 // In IEEE-mode we can't check the answer if this
307 if ((cyg_libm_get_compat_mode() !=
308 CYGNUM_LIBM_COMPAT_IEEE) &&
309 (errno != vectors[i].errno_val)) {
312 diag_printf("Vector #%d\n", i+1);
313 CYG_TEST_FAIL( "error not set correctly");
318 continue; // no point checking value in an error case
320 if (checkErrorAcceptable( ret, result_wanted,
321 vectors[i].tolerance) ) {
323 diag_printf("Vector #%d\n", i+1);
324 CYG_TEST_FAIL( "Result out of tolerance");
332 case CYG_LIBM_TEST_VEC_INT:
335 difn fn = (difn) func_ptr;
338 (i < num_vectors) && (problems < PROBLEM_THRESHOLD);
341 if (0 == i % alive_count)
342 CYG_TEST_STILL_ALIVE(i, "Still crunching, please wait...");
344 arg1.parts.msw = vectors[i].arg1_msw;
345 arg1.parts.lsw = vectors[i].arg1_lsw;
347 result_wanted.parts.msw = vectors[i].result_msw;
348 result_wanted.parts.lsw = vectors[i].result_lsw;
350 ret.value = (*fn)( arg1.value, vectors[i].arg2_lsw );
351 if (checkErrorAcceptable( ret, result_wanted,
352 vectors[i].tolerance) ) {
354 diag_printf("Vector #%d\n", i+1);
355 CYG_TEST_FAIL( "Result out of tolerance");
363 case CYG_LIBM_TEST_VEC_INT_P:
366 dipfn fn = (dipfn) func_ptr;
368 Cyg_libm_ieee_double_shape_type my_doub1, my_doub2;
371 (i < num_vectors) && (problems < PROBLEM_THRESHOLD);
374 if (0 == i % alive_count)
375 CYG_TEST_STILL_ALIVE(i, "Still crunching, please wait...");
377 arg1.parts.msw = vectors[i].arg1_msw;
378 arg1.parts.lsw = vectors[i].arg1_lsw;
381 result_wanted.parts.msw = vectors[i].result_msw;
382 result_wanted.parts.lsw = vectors[i].result_lsw;
384 ret.value = (*fn)( arg1.value, &my_int );
385 if (checkErrorAcceptable( ret, result_wanted,
386 vectors[i].tolerance) ) {
388 diag_printf("Vector #%d\n", i+1);
389 CYG_TEST_FAIL( "Result out of tolerance");
392 my_doub1.value = (double) my_int;
393 my_doub2.value = (double) (signed)vectors[i].arg2_lsw;
395 if (checkErrorAcceptable( my_doub1, my_doub2,
396 vectors[i].tolerance) ) {
398 diag_printf("Vector #%d\n", i+1);
399 CYG_TEST_FAIL( "Integer result out of tolerance");
409 case CYG_LIBM_TEST_VEC_DOUBLE_P:
412 ddpfn fn = (ddpfn) func_ptr;
413 Cyg_libm_ieee_double_shape_type my_doub1;
416 (i < num_vectors) && (problems < PROBLEM_THRESHOLD);
419 if (0 == i % alive_count)
420 CYG_TEST_STILL_ALIVE(i, "Still crunching, please wait...");
422 arg1.parts.msw = vectors[i].arg1_msw;
423 arg1.parts.lsw = vectors[i].arg1_lsw;
425 arg2.parts.msw = vectors[i].arg2_msw;
426 arg2.parts.lsw = vectors[i].arg2_lsw;
429 result_wanted.parts.msw = vectors[i].result_msw;
430 result_wanted.parts.lsw = vectors[i].result_lsw;
432 ret.value = (*fn)( arg1.value, &my_doub1.value );
433 if (checkErrorAcceptable( ret, result_wanted,
434 vectors[i].tolerance) ) {
436 diag_printf("Vector #%d\n", i+1);
437 CYG_TEST_FAIL( "Result out of tolerance");
440 if (checkErrorAcceptable( my_doub1, arg2,
441 vectors[i].tolerance) ) {
443 diag_printf("Vector #%d\n", i+1);
444 CYG_TEST_FAIL( "Returned double result out of "
455 case CYG_LIBM_TEST_VEC_NONE:
458 dfn fn = (dfn) func_ptr;
461 (i < num_vectors) && (problems < PROBLEM_THRESHOLD);
464 if (0 == i % alive_count)
465 CYG_TEST_STILL_ALIVE(i, "Still crunching, please wait...");
467 arg1.parts.msw = vectors[i].arg1_msw;
468 arg1.parts.lsw = vectors[i].arg1_lsw;
470 result_wanted.parts.msw = vectors[i].result_msw;
471 result_wanted.parts.lsw = vectors[i].result_lsw;
473 ret.value = (*fn)( arg1.value );
474 if (checkErrorAcceptable( ret, result_wanted,
475 vectors[i].tolerance) ) {
477 diag_printf("Vector #%d\n", i+1);
478 CYG_TEST_FAIL( "Result out of tolerance");
487 CYG_TEST_FAIL("Second argument of unknown type!");
498 #endif // CYGONCE_LIBM_VECTOR_SUPPORT_H multiple inclusion protection
500 // EOF vector_support.h