1/****************************************************************
2
3The author of this software is David M. Gay.
4
5Copyright (C) 1998 by Lucent Technologies
6All Rights Reserved
7
8Permission to use, copy, modify, and distribute this software and
9its documentation for any purpose and without fee is hereby
10granted, provided that the above copyright notice appear in all
11copies and that both that the copyright notice and this
12permission notice and warranty disclaimer appear in supporting
13documentation, and that the name of Lucent or any of its entities
14not be used in advertising or publicity pertaining to
15distribution of the software without specific, written prior
16permission.
17
18LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
19INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
20IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
21SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
22WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
23IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
24ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
25THIS SOFTWARE.
26
27****************************************************************/
28
29/* Please send bug reports to David M. Gay (dmg at acm dot org,
30 * with " at " changed at "@" and " dot " changed to ".").	*/
31
32/* Test program for strtod and dtoa.
33 *
34 * Inputs (on stdin):
35 *		number[: mode [ndigits]]
36 * or
37 *		#hex0 hex1[: mode [ndigits]]
38 * where number is a decimal floating-point number,
39 * hex0 is a string of Hex digits for the most significant
40 * word of the number, hex1 is a similar string for the other
41 * (least significant) word, and mode and ndigits are
42 * parameters to dtoa.
43 */
44
45#include <stdio.h>
46#include "gdtoa.h"
47int STRTOD_DIGLIM = 24;
48#ifdef KR_headers
49#define Void /*void*/
50#else
51#define Void void
52#endif
53
54#ifdef __STDC__
55#include <stdlib.h>
56#else
57#ifdef __cplusplus
58extern "C" double atof(const char*);
59#else
60extern double atof ANSI((char*));
61#endif
62#endif
63
64typedef union { double d; ULong L[2]; } U;
65
66#ifdef IEEE_8087
67#define word0(x) (x)->L[1]
68#define word1(x) (x)->L[0]
69#else
70#define word0(x) (x)->L[0]
71#define word1(x) (x)->L[1]
72#endif
73#define dval(x) (x)->d
74
75#include "errno.h"
76
77#ifdef __cplusplus
78extern "C" char *dtoa(double, int, int, int*, int*, char **);
79#else
80extern char *dtoa ANSI((double, int, int, int*, int*, char **));
81#endif
82
83 static void
84#ifdef KR_headers
85g_fmt(b, x) char *b; double x;
86#else
87g_fmt(char *b, double x)
88#endif
89{
90	char *s, *se;
91	int decpt, i, j, k, sign;
92
93	if (!x) {
94		*b++ = '0';
95		*b = 0;
96		return;
97		}
98	s = dtoa(x, 0, 0, &decpt, &sign, &se);
99	if (sign)
100		*b++ = '-';
101	if (decpt == 9999) /* Infinity or Nan */ {
102		while((*b++ = *s++));
103		return;
104		}
105	if (decpt <= -4 || decpt > se - s + 5) {
106		*b++ = *s++;
107		if (*s) {
108			*b++ = '.';
109			while((*b = *s++))
110				b++;
111			}
112		*b++ = 'e';
113		/* sprintf(b, "%+.2d", decpt - 1); */
114		if (--decpt < 0) {
115			*b++ = '-';
116			decpt = -decpt;
117			}
118		else
119			*b++ = '+';
120		for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10){};
121		for(;;) {
122			i = decpt / k;
123			*b++ = i + '0';
124			if (--j <= 0)
125				break;
126			decpt -= i*k;
127			decpt *= 10;
128			}
129		*b = 0;
130		}
131	else if (decpt <= 0) {
132		*b++ = '.';
133		for(; decpt < 0; decpt++)
134			*b++ = '0';
135		while((*b++ = *s++));
136		}
137	else {
138		while((*b = *s++)) {
139			b++;
140			if (--decpt == 0 && *s)
141				*b++ = '.';
142			}
143		for(; decpt > 0; decpt--)
144			*b++ = '0';
145		*b = 0;
146		}
147	}
148
149 static void
150baderrno(Void)
151{
152	fflush(stdout);
153	perror("\nerrno strtod");
154	fflush(stderr);
155	}
156
157#define UL (unsigned long)
158
159 static void
160#ifdef KR_headers
161check(d) U *d;
162#else
163check(U *d)
164#endif
165{
166	char buf[64];
167	int decpt, sign;
168	char *s, *se;
169	U d1;
170
171	s = dtoa(dval(d), 0, 0, &decpt, &sign, &se);
172	sprintf(buf, "%s%s%se%d", sign ? "-" : "",
173		decpt == 9999 ? "" : ".", s, decpt);
174	errno = 0;
175	dval(&d1) = strtod(buf, (char **)0);
176	if (errno)
177		baderrno();
178	if (dval(d) != dval(&d1)) {
179		printf("sent d = %.17g = 0x%lx %lx, buf = %s\n",
180			dval(d), UL word0(d), UL word1(d), buf);
181		printf("got d1 = %.17g = 0x%lx %lx\n",
182			dval(&d1), UL word0(&d1), UL word1(&d1));
183		}
184	}
185
186 int
187main(Void)
188{
189	U d, d1;
190	char buf[2048], buf1[32];
191	char *fmt, *s, *s1, *se;
192	int decpt, sign;
193	int mode = 0, ndigits = 17;
194	ULong x, y;
195#ifdef VAX
196	ULong z;
197#endif
198
199	while(fgets(buf, sizeof(buf), stdin)) {
200		if (*buf == '*') {
201			printf("%s", buf);
202			continue;
203			}
204		printf("Input: %s", buf);
205		if (*buf == '#') {
206			x = word0(&d);
207			y = word1(&d);
208			/* sscanf(buf+1, "%lx %lx:%d %d", &x, &y, &mode, &ndigits); */
209			x = (ULong)strtoul(s1 = buf+1, &se, 16);
210			if (se > s1) {
211				y = (ULong)strtoul(s1 = se, &se, 16);
212				if (se > s1)
213					sscanf(se, ":%d %d", &mode, &ndigits);
214				}
215			word0(&d) = x;
216			word1(&d) = y;
217			fmt = "Output: d =\n%.17g = 0x%lx %lx\n";
218			}
219		else if (*buf == '*') {
220			x = strtoul(buf,&s,10);
221			if (!*s && x > 18)
222				STRTOD_DIGLIM = (int)x;
223			printf("STRTOD_DIGLIM = %lu\n", UL x);
224			continue;
225			}
226		else {
227			errno = 0;
228			dval(&d) = strtod(buf,&se);
229			if (*se == ':')
230				sscanf(se+1,"%d %d", &mode, &ndigits);
231			dval(&d1) = atof(buf);
232			fmt = "Output: d =\n%.17g = 0x%lx %lx, se = %s";
233			if (errno)
234				baderrno();
235			}
236		printf(fmt, dval(&d), UL word0(&d), UL word1(&d), se);
237		g_fmt(buf1, dval(&d));
238		printf("\tg_fmt gives \"%s\"\n", buf1);
239		if (*buf != '#' && dval(&d) != dval(&d1))
240			printf("atof gives\n\
241	d1 = %.17g = 0x%lx %lx\nversus\n\
242	d  = %.17g = 0x%lx %lx\n", dval(&d1), UL word0(&d1), UL word1(&d1),
243				dval(&d), UL word0(&d), UL word1(&d));
244		check(&d);
245		s = dtoa(dval(&d), mode, ndigits, &decpt, &sign, &se);
246		printf("\tdtoa(mode = %d, ndigits = %d):\n", mode, ndigits);
247		printf("\tdtoa returns sign = %d, decpt = %d, %d digits:\n%s\n",
248			sign, decpt, (int)(se-s), s);
249		x = word1(&d);
250		if (x != 0xffffffff
251		 && (word0(&d) & 0x7ff00000) != 0x7ff00000) {
252#ifdef VAX
253			z = x << 16 | x >> 16;
254			z++;
255			z = z << 16 | z >> 16;
256			word1(&d) = z;
257#else
258			word1(&d) = x + 1;
259#endif
260			printf("\tnextafter(d,+Inf) = %.17g = 0x%lx %lx:\n",
261				dval(&d), UL word0(&d), UL word1(&d));
262			g_fmt(buf1, dval(&d));
263			printf("\tg_fmt gives \"%s\"\n", buf1);
264			s = dtoa(dval(&d), mode, ndigits, &decpt, &sign, &se);
265			printf(
266		"\tdtoa returns sign = %d, decpt = %d, %d digits:\n%s\n",
267				sign, decpt, (int)(se-s), s);
268			check(&d);
269			}
270		if (x) {
271#ifdef VAX
272			z = x << 16 | x >> 16;
273			z--;
274			z = z << 16 | z >> 16;
275			word1(&d) = z;
276#else
277			word1(&d) = x - 1;
278#endif
279			printf("\tnextafter(d,-Inf) = %.17g = 0x%lx %lx:\n",
280				dval(&d), UL word0(&d), UL word1(&d));
281			g_fmt(buf1, dval(&d));
282			printf("\tg_fmt gives \"%s\"\n", buf1);
283			s = dtoa(dval(&d), mode, ndigits, &decpt, &sign, &se);
284			printf(
285		"\tdtoa returns sign = %d, decpt = %d, %d digits:\n%s\n",
286				sign, decpt, (int)(se-s), s);
287			check(&d);
288			}
289		}
290	return 0;
291	}
292