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 */
41static 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 */
117static 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 */
154static 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 */
168static 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 */
181static 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 */
210static 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 */
224static 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 */
256static 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 */
277void *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:
348file_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