Home | History | Annotate | Download | only in float
      1 /*
      2  * Copyright (C) Bull S.A. 2001
      3  * Copyright (c) International Business Machines  Corp., 2001
      4  *
      5  *   This program is free software;  you can redistribute it and/or modify
      6  *   it under the terms of the GNU General Public License as published by
      7  *   the Free Software Foundation; either version 2 of the License, or
      8  *   (at your option) any later version.
      9  *
     10  *   This program is distributed in the hope that it will be useful,
     11  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
     12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
     13  *   the GNU General Public License for more details.
     14  *
     15  *   You should have received a copy of the GNU General Public License
     16  *   along with this program;  if not, write to the Free Software
     17  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     18  */
     19 
     20 /******************************************************************************/
     21 /*                                                                            */
     22 /* Dec-03-2001  Created: Jacky Malcles & Jean Noel Cordenner                  */
     23 /*              These tests are adapted from AIX float PVT tests.             */
     24 /*                                                                            */
     25 /******************************************************************************/
     26 #include "tfloat.h"
     27 
     28 #define SAFE_FREE(p) { if (p) { free(p); (p)=NULL; } }
     29 /*
     30  * allocates a buffer and read a file to it
     31  * input parameters:
     32  *	fname: name of the file to read
     33  *	data:  pointer where buffer addr. will be returned
     34  *
     35  * uses also external variable datadir to build file pathname
     36  *
     37  * returns:
     38  *	0 in case of failure
     39  *	# of bytes read elsewhere
     40  */
     41 static size_t read_file(char *fname, void **data)
     42 {
     43 	struct stat bufstat;
     44 	char path[PATH_MAX];
     45 	size_t fsize;
     46 	void *buffer;
     47 	int fd;
     48 	int maxretries = 1;
     49 
     50 	(void)sprintf(path, "%s/%s", datadir, fname);
     51 
     52 	errno = 0;
     53 
     54 	while (stat(path, &bufstat)) {
     55 		if (errno == ETIMEDOUT || errno == EINTR || errno == 0) {
     56 			printf("Error stat'ing %s: %s\n",
     57 			       path, strerror(errno));
     58 			pthread_testcancel();
     59 			/* retrying... */
     60 			if (maxretries--)
     61 				continue;
     62 		}
     63 		return (size_t) 0;
     64 	}
     65 
     66 	fsize = bufstat.st_size;
     67 	if (!fsize) {
     68 		errno = ENOENT;
     69 		return (size_t) 0;
     70 	}
     71 
     72 	while ((buffer = malloc(fsize)) == NULL) {
     73 		if (errno == EINTR || errno == 0) {
     74 			printf("Error malloc'ing: %s\n", strerror(errno));
     75 			pthread_testcancel();
     76 			/* retrying... */
     77 			if (maxretries--)
     78 				continue;
     79 		}
     80 		return (size_t) 0;
     81 	}
     82 
     83 	while ((fd = open(path, O_RDONLY)) < 0) {
     84 		if (errno == ETIMEDOUT || errno == EINTR || errno == 0) {
     85 			printf("Error opening %s: %s\n", path, strerror(errno));
     86 			pthread_testcancel();
     87 			/* retrying... */
     88 			if (maxretries--)
     89 				continue;
     90 		}
     91 		SAFE_FREE(buffer);
     92 		return (size_t) 0;
     93 	}
     94 
     95 	while (read(fd, buffer, fsize) != fsize) {
     96 		if (errno == ETIMEDOUT || errno == EINTR || errno == 0) {
     97 			printf("Error reading %s: %s\n", path, strerror(errno));
     98 			pthread_testcancel();
     99 			/* retrying... */
    100 			if (lseek(fd, (off_t) 0, SEEK_SET) == (off_t) 0) {
    101 				if (maxretries--)
    102 					continue;
    103 			}
    104 		}
    105 		(void)close(fd);
    106 		SAFE_FREE(buffer);
    107 		return (size_t) 0;
    108 	}
    109 
    110 	(void)close(fd);
    111 	*data = buffer;
    112 	return fsize;
    113 }
    114 
    115 /* this subroutine is used in compute_xxx functions to check results
    116    and record errors if appropriate */
    117 static void check_error(TH_DATA * th_data, double e, double r, int index)
    118 {
    119 	double x;
    120 	int pe, pr, px;
    121 	static const char errtmplt[] =
    122 	    "%s failed at index %d: OLD: %2.18e NEW: %2.18e DIFF: %2.18e\n";
    123 
    124 	x = fabs(r - e);	/* diff expected/computed */
    125 
    126 	if (x > EPS) {		/* error ? */
    127 		/* compute exponent parts */
    128 		(void)frexp(r, &pr);	/* for computed */
    129 		(void)frexp(x, &px);	/* for difference */
    130 		(void)frexp(e, &pe);	/* for dexected */
    131 
    132 		if (abs(pe - px) < th_data->th_func.precision ||
    133 		    abs(pr - px) < th_data->th_func.precision) {
    134 			/* not a rounding error */
    135 			++th_data->th_nerror;
    136 			/* record first error only ! */
    137 			if (th_data->th_result == 0) {
    138 				sprintf(th_data->detail_data,
    139 					errtmplt,
    140 					th_data->th_func.fident,
    141 					index, e, r, x);
    142 				th_data->th_result = 1;
    143 			}
    144 		}
    145 	}
    146 }
    147 
    148 /*
    149  * these functions handle the various cases of computation
    150  * they are called by pthread_code
    151  */
    152 
    153 /* normal case: compares f(input data) to expected data */
    154 static void compute_normal(TH_DATA * th_data, double *din, double *dex,
    155 			   int index)
    156 {
    157 	double d, r, e;
    158 
    159 	d = din[index];
    160 	e = dex[index];
    161 	r = (*(th_data->th_func.funct)) (d);
    162 
    163 	check_error(th_data, e, r, index);
    164 }
    165 
    166 /* atan2 and hypot case: compares f(sin(input data),cos(input data))
    167    to expected data */
    168 static void compute_atan2_hypot(TH_DATA * th_data, double *din, double *dex,
    169 				int index)
    170 {
    171 	double d, r, e;
    172 
    173 	d = din[index];
    174 	e = dex[index];
    175 	r = (*(th_data->th_func.funct)) (sin(d), cos(d));
    176 
    177 	check_error(th_data, e, r, index);
    178 }
    179 
    180 /* modf case: compares integral and fractional parts to expected datas */
    181 static void compute_modf(TH_DATA * th_data, double *din, double *dex,
    182 			 double *dex2, int index)
    183 {
    184 	static const char errtmplt1[] =
    185 	    "%s failed at index %d: OLD integral part: %f NEW: %f\n";
    186 	double d, r, e;
    187 	double tmp;
    188 
    189 	d = din[index];
    190 	e = dex[index];
    191 	r = (*(th_data->th_func.funct)) (d, &tmp);
    192 
    193 	if (tmp != dex2[index]) {	/* bad integral part! */
    194 		++th_data->th_nerror;
    195 		/* record first error only ! */
    196 		if (th_data->th_result == 0) {
    197 			sprintf(th_data->detail_data,
    198 				errtmplt1,
    199 				th_data->th_func.fident,
    200 				index, dex2[index], tmp);
    201 			th_data->th_result = 1;
    202 		}
    203 		return;
    204 	}
    205 
    206 	check_error(th_data, e, r, index);
    207 }
    208 
    209 /* fmod and pow case: compares f(input data, input data2) to expected data */
    210 static void compute_fmod_pow(TH_DATA * th_data, double *din, double *dex,
    211 			     double *dex2, int index)
    212 {
    213 	double d, r, e;
    214 
    215 	d = din[index];
    216 	e = dex[index];
    217 	r = (*(th_data->th_func.funct)) (d, dex2[index]);
    218 
    219 	check_error(th_data, e, r, index);
    220 }
    221 
    222 /* frexp case: compares mantissa and exponent to expected datas */
    223 /* lgamma case: compares result and signgam to expected datas */
    224 static void compute_frexp_lgamma(TH_DATA * th_data, double *din, double *dex,
    225 				 int *dex2, int index)
    226 {
    227 	static const char errtmplt2[] =
    228 	    "%s failed at index %d: OLD (exp. or sign): %d NEW: %d\n";
    229 	double d, r, e;
    230 	int tmp;
    231 	static const char xinf[8] = "lgamma";
    232 
    233 	d = din[index];
    234 	e = dex[index];
    235 	r = (*(th_data->th_func.funct)) (d, &tmp);
    236 
    237 	if (strcmp(th_data->th_func.fident, xinf) != 0) {
    238 		if (tmp != dex2[index]) {	/* bad exponent! */
    239 			++th_data->th_nerror;
    240 			/* record first error only ! */
    241 			if (th_data->th_result == 0) {
    242 				sprintf(th_data->detail_data,
    243 					errtmplt2,
    244 					th_data->th_func.fident,
    245 					index, dex2[index], tmp);
    246 				th_data->th_result = 1;
    247 			}
    248 			return;
    249 		}
    250 	}
    251 
    252 	check_error(th_data, e, r, index);
    253 }
    254 
    255 /* ldexp case: compares f(input data, input data2) to expected data */
    256 static void compute_ldexp(TH_DATA * th_data, double *din, double *dex,
    257 			  int *din2, int index)
    258 {
    259 	double d, r, e;
    260 
    261 	d = din[index];
    262 	e = dex[index];
    263 	r = (*(th_data->th_func.funct)) (d, din2[index]);
    264 
    265 	check_error(th_data, e, r, index);
    266 }
    267 
    268 /*
    269  * Function which does the job, to be called as the
    270  * "start routine" parameter of pthread_create subroutine.
    271  * Uses the compute_xxx subroutines above.
    272  *
    273  * input parameters ("arg" parameter of pthread_create subroutine):
    274  *	pointer to a TH_DATA structure.
    275  *
    276  */
    277 void *thread_code(void *arg)
    278 {
    279 	TH_DATA *th_data = (TH_DATA *) arg;
    280 	size_t fsize, fsize2, fsize3;
    281 	double *din, *dex, *dex2 = NULL;
    282 	int imax, index;
    283 
    284 	fsize = read_file(th_data->th_func.din_fname, (void **)&din);
    285 	if (fsize == (size_t) 0) {
    286 		sprintf(th_data->detail_data,
    287 			"FAIL: %s: reading %s, %s\n",
    288 			th_data->th_func.fident,
    289 			th_data->th_func.din_fname, strerror(errno));
    290 		th_data->th_result = 1;
    291 		SAFE_FREE(din);
    292 		pthread_exit((void *)1);
    293 	}
    294 	fsize2 = read_file(th_data->th_func.dex_fname, (void **)&dex);
    295 	if (fsize2 == (size_t) 0) {
    296 		sprintf(th_data->detail_data,
    297 			"FAIL: %s: reading %s, %s\n",
    298 			th_data->th_func.fident,
    299 			th_data->th_func.dex_fname, strerror(errno));
    300 		th_data->th_result = 1;
    301 		SAFE_FREE(din);
    302 		SAFE_FREE(dex);
    303 		pthread_exit((void *)1);
    304 	}
    305 
    306 	fsize3 = (size_t) 0;
    307 	switch (th_data->th_func.code_funct) {
    308 	case FUNC_MODF:
    309 	case FUNC_FMOD:
    310 	case FUNC_POW:
    311 	case FUNC_FREXP:
    312 	case FUNC_LDEXP:
    313 	case FUNC_GAM:
    314 		fsize3 = read_file(th_data->th_func.dex2_fname, (void **)&dex2);
    315 		if (fsize3 == (size_t) 0) {
    316 			sprintf(th_data->detail_data,
    317 				"FAIL: %s: reading %s, %s\n",
    318 				th_data->th_func.fident,
    319 				th_data->th_func.dex2_fname, strerror(errno));
    320 			th_data->th_result = 1;
    321 			SAFE_FREE(din);
    322 			SAFE_FREE(dex);
    323 			pthread_exit((void *)1);
    324 		}
    325 	}
    326 
    327 	switch (th_data->th_func.code_funct) {
    328 	case FUNC_NORMAL:
    329 	case FUNC_ATAN2:
    330 	case FUNC_HYPOT:
    331 		if (fsize2 != fsize)
    332 			goto file_size_error;
    333 		break;
    334 	case FUNC_MODF:
    335 	case FUNC_FMOD:
    336 	case FUNC_POW:
    337 		if (fsize2 != fsize || fsize3 != fsize)
    338 			goto file_size_error;
    339 		break;
    340 	case FUNC_FREXP:
    341 	case FUNC_LDEXP:
    342 	case FUNC_GAM:
    343 		if (fsize2 != fsize ||
    344 		    (sizeof(double) / sizeof(int)) * fsize3 != fsize)
    345 			goto file_size_error;
    346 		break;
    347 	default:
    348 file_size_error:
    349 		sprintf(th_data->detail_data,
    350 			"FAIL: %s: file sizes don't match\n",
    351 			th_data->th_func.fident);
    352 		th_data->th_result = 1;
    353 		SAFE_FREE(din);
    354 		SAFE_FREE(dex);
    355 		if (fsize3)
    356 			SAFE_FREE(dex2);
    357 		pthread_exit((void *)1);
    358 	}
    359 
    360 	imax = fsize / sizeof(double);
    361 
    362 	while (th_data->th_nloop <= num_loops) {
    363 		/* loop stopped by pthread_cancel */
    364 
    365 		for (index = th_data->th_num; index < imax; index += num_threads) {	/* computation loop */
    366 			switch (th_data->th_func.code_funct) {
    367 			case FUNC_NORMAL:
    368 				compute_normal(th_data, din, dex, index);
    369 				break;
    370 			case FUNC_ATAN2:
    371 			case FUNC_HYPOT:
    372 				compute_atan2_hypot(th_data, din, dex, index);
    373 				break;
    374 			case FUNC_MODF:
    375 				compute_modf(th_data, din, dex, dex2, index);
    376 				break;
    377 			case FUNC_FMOD:
    378 			case FUNC_POW:
    379 				compute_fmod_pow(th_data,
    380 						 din, dex, dex2, index);
    381 				break;
    382 			case FUNC_FREXP:
    383 			case FUNC_GAM:
    384 				compute_frexp_lgamma(th_data,
    385 						     din, dex, (int *)dex2,
    386 						     index);
    387 				break;
    388 			case FUNC_LDEXP:
    389 				compute_ldexp(th_data,
    390 					      din, dex, (int *)dex2, index);
    391 				break;
    392 			default:
    393 				sprintf(th_data->detail_data,
    394 					"FAIL: %s: unexpected function type\n",
    395 					th_data->th_func.fident);
    396 				th_data->th_result = 1;
    397 				SAFE_FREE(din);
    398 				SAFE_FREE(dex);
    399 				if (fsize3)
    400 					SAFE_FREE(dex2);
    401 				pthread_exit((void *)1);
    402 			}
    403 			pthread_testcancel();
    404 		}		/* end of computation loop */
    405 		++th_data->th_nloop;
    406 	}			/* end of loop */
    407 	SAFE_FREE(din);
    408 	SAFE_FREE(dex);
    409 	if (fsize3)
    410 		SAFE_FREE(dex2);
    411 	pthread_exit(NULL);
    412 }
    413