1/*
2 *
3 *   Copyright (c) International Business Machines  Corp., 2002
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/* 01/02/2003	Port to LTP	avenkat@us.ibm.com */
21/* 06/30/2001	Port to Linux	nsharoff@us.ibm.com */
22
23/*
24 * NAME
25 *	atof1 -- ascii to floating point test
26 *
27 * CALLS
28 *	atof(3), sprintf(3), ( doprnt.s )
29 *
30 * ALGORITHM
31 *	Do some checks of floating point to ascii and back, arbitrate
32 *	with a 3rd algorithm written in C.
33 *
34 * RESTRICTIONS
35 */
36
37#include <stdio.h>
38#include <ctype.h>
39#include <math.h>
40#include <stdlib.h>
41#include <errno.h>
42
43/**	LTP Port	**/
44#include "test.h"
45
46#define FAILED 0
47#define PASSED 1
48
49/*****		*****/
50#define ERR		0.0000001
51
52double pi;
53
54/*char progname[]= "atof1()"; */
55/**	LTP Port	**/
56char *TCID = "atof01";		/* Test program identifier */
57
58int local_flag = PASSED;
59int block_number;
60FILE *temp;
61int TST_TOTAL = 1;
62
63static void setup(void);
64static void blenter(void);
65static void blexit(void);
66static int numin(char *, double *);
67static int checkbuf(char *, int, int);
68
69/*--------------------------------------------------------------*/
70int main(int argc, char *argv[])
71{
72	register int i, j;
73	double r1, r2, x;
74	char buf[100];
75
76	setup();		/* temp file is now open        */
77	pi = 4.0 * atan(1.0);
78
79/*--------------------------------------------------------------*/
80	blenter();
81
82	for (i = 0; i < 30; i++)
83		for (j = 0; j < 30; j++) {
84			sprintf(buf, "%*.*f", i, j, pi);
85			if (checkbuf(buf, i, j)) {
86				fprintf(temp, "output conversion incorrect.");
87				fprintf(temp, "%*.*f = '%s'", i, j, pi, buf);
88				local_flag = FAILED;
89			}
90			r1 = atof(buf);
91			if (numin(buf, &r2)) {
92				fprintf(temp, "\tnumin('%s') failed\n", buf);
93				local_flag = FAILED;
94			}
95			x = fabs(r1 - r2);
96			if (x > ERR) {
97				fprintf(temp, "\tcompare fails, %f vs %f\n",
98					r1, r2);
99				fprintf(temp, "\terr value is %f\n", x);
100				local_flag = FAILED;
101			}
102			if (local_flag == FAILED)
103				break;
104		}
105
106	blexit();
107/*--------------------------------------------------------------*/
108	blenter();
109
110	x = 1.0 - exp(-100.0);	/* 1.0 - very small number */
111	sprintf(buf, "%f", x);
112	r1 = atof(buf);
113	if (r1 != 1.0) {
114		fprintf(temp, "\tsprintf small # failed\n");
115		fprintf(temp, "\t printed '%s', expected 1.0\n", buf);
116		local_flag = FAILED;
117	}
118
119	blexit();
120/*--------------------------------------------------------------*/
121	blenter();
122
123	for (i = 1; i < 200; i++) {
124		x = 100.0 / (double)i;
125		sprintf(buf, "%f", x);
126		r1 = atof(buf);
127		if (numin(buf, &r2)) {
128			fprintf(temp, "\tnumin('%s') failed\n", buf);
129			local_flag = FAILED;
130		}
131		/*
132		 * Order subtraction  to produce a positive number.
133		 * Then subtrace "fudge" factor which should give us
134		 * a negative number, as the result fo subtraction should
135		 * always be smaller than the fudge factor.
136		 */
137		if (r1 > r2)
138			x = r1 - r2 - 1e-10;
139		else
140			x = r2 - r1 - 1e-10;
141		if (x > 0.0) {
142			fprintf(temp, "\tx = %.15f = %e\n", x, x);
143			fprintf(temp, "\titeration %d\n", i);
144			fprintf(temp, "\tcompare fails, %f vs %f\n", r1, r2);
145			fprintf(temp, "\tcompare fails, %.15f vs %.15f\n",
146				r1, r2);
147			fprintf(temp, "\tbuf = '%s'\n", buf);
148			x = r1 - r2;
149			if (x == 0.0)
150				fprintf(temp, "\tx == 0.0\n");
151			else
152				fprintf(temp, "\tx != 0.0\n");
153			fprintf(temp, "\tx = %.15f = %e\n", x, x);
154			local_flag = FAILED;
155		}
156		if (local_flag == FAILED)
157			break;
158	}
159
160	blexit();
161/*--------------------------------------------------------------*/
162	blenter();
163
164	for (i = -1; i > -200; i--) {
165		x = 100.0 / (double)i;
166		sprintf(buf, "%f", x);
167		r1 = atof(buf);
168		if (numin(buf, &r2)) {
169			fprintf(temp, "\tnumin('%s') failed\n", buf);
170			local_flag = FAILED;
171		}
172		/*
173		 * Same ordering of subtraction as above.
174		 */
175		if (r1 > r2)
176			x = r1 - r2 - 1e-10;
177		else
178			x = r2 - r1 - 1e-10;
179		if (x > 0.0) {
180			fprintf(temp, "\tcompare fails, %f vs %f\n", r1, r2);
181			fprintf(temp, "\tcompare fails, %.15f vs %.15f\n",
182				r1, r2);
183			x = r1 - r2;
184			if (x == 0.0)
185				fprintf(temp, "\tx == 0.0)\n");
186			else
187				fprintf(temp, "\tx != 0.0\n");
188			fprintf(temp, "\tx = %.15f = %e\n", x, x);
189			local_flag = FAILED;
190		}
191		if (local_flag == FAILED)
192			break;
193	}
194
195	blexit();
196/*--------------------------------------------------------------*/
197	tst_exit();
198}
199
200/* FUNCTIONS GO HERE */
201
202static int numin(char *str, double *rval)
203{
204	register int i, v3, e_flag;
205	register char c;
206	double val, v1, v2, k;
207	int neg_flag = 0;
208
209	val = v1 = v2 = 0.0;
210	v3 = 0;
211	k = 0.1;
212
213	while (*str == ' ')	/* scan past white space */
214		str++;
215
216	if (*str == '-') {	/* negitive value test */
217		neg_flag++;
218		str++;
219	}
220
221	for (;;) {
222		c = *str;
223		if (!isdigit(c))
224			break;
225		v1 *= 10.0;
226		v1 += (double)(c - '0');
227		str++;
228	}
229
230	val = v1;
231
232#ifdef DEBUG
233	printf("First conversion, val = %f = %e\n", val, val);
234#endif
235
236	if (*str == '.') {
237		str++;
238		for (;;) {
239			c = *str;
240			if (!isdigit(c))
241				break;
242			v2 += k * (double)(c - '0');
243			k /= 10.0;
244			str++;
245		}
246		val += v2;
247	}
248#ifdef DEBUG
249	printf("Second conversion, val = %f = %e\n", val, val);
250#endif
251
252	if (*str == 'e') {
253		str++;
254		switch (*str) {
255		case '+':
256			e_flag = 1;
257			break;
258		case '-':
259			e_flag = -1;
260			break;
261		default:
262			fprintf(temp, "\tbad char '%c' after 'e'\n", *str);
263			printf("bad char '%c' after 'e'\n", *str);
264			return (-1);
265		}
266		str++;
267		if (!isdigit(*str)) {
268			fprintf(temp, "\tbad exponent field\n");
269			printf("bad exponent field\n");
270			return (-1);
271		}
272		v3 = 10 * (int)(*str - '0');
273		str++;
274		if (!isdigit(*str)) {
275			fprintf(temp, "\tbad exponent field\n");
276			printf("bad exponent field\n");
277			return (-1);
278		}
279		v3 += (int)(*str - '0');
280		str++;
281		for (i = 0; i < v3; i++) {
282			if (e_flag > 0)
283				val *= 10.0;
284			else
285				val *= 0.1;
286		}
287	}
288
289	if (neg_flag)
290		val *= -1.0;
291
292#ifdef DEBUG
293	printf("Third conversion, val = %f = %e\n", val, val);
294	printf("v1 = %f, v2 = %f, v3 = %d\n", v1, v2, v3);
295#endif
296
297	switch (*str) {
298	case '\0':
299	case ' ':
300	case '\t':
301	case '\n':
302		break;
303	default:
304		printf("unexpected char '%c'\n", *str);
305		return (-1);
306	}
307
308	*rval = val;
309	return (0);
310}
311
312static int checkbuf(char *str, int n1, int n2)
313{
314	register int bd;	/* before decimal point */
315	register int ad;	/* after decimal point */
316	register int tw;	/* total width */
317	register int dp;	/* decimal point */
318	char *buf;
319
320	bd = ad = dp = 0;
321	buf = str;
322
323	while (*str && *str != '.') {
324		bd++;
325		str++;
326	}
327	if (*str == '.') {
328		dp++;
329		str++;
330		if (*str) {
331			while (*str) {
332				ad++;
333				str++;
334			}
335		}
336	}
337
338	tw = bd + dp + ad;
339	if (!n1)
340		n1++;
341	if (tw < n1) {
342		fprintf(temp, "\tWidth too small.\n");
343		fprintf(temp, "\tn1 = %d, n2 = %d, buf= '%s'\n", n1, n2, buf);
344		return (-1);
345	}
346
347	if (ad != n2) {
348		fprintf(temp, "\tNumber after decimal wrong.\n");
349		fprintf(temp, "\tn1 = %d, n2 = %d, buf= '%s'\n", n1, n2, buf);
350		return (-1);
351	}
352
353	if (n2 && !dp) {
354		fprintf(temp, "\tMissed decimal point.\n");
355		fprintf(temp, "\tn1 = %d, n2 = %d, buf= '%s'\n", n1, n2, buf);
356		return (-1);
357	}
358
359	return (0);
360}
361
362/**	LTP Port	**/
363static void setup(void)
364{
365	temp = stderr;
366}
367
368static void blenter(void)
369{
370	local_flag = PASSED;
371}
372
373static void blexit(void)
374{
375	if (local_flag == PASSED)
376		tst_resm(TPASS, "Test passed");
377	else
378		tst_resm(TFAIL, "Test failed");
379}
380