home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
listings
/
v_09_07
/
9n07086a
< prev
next >
Wrap
Text File
|
1991-02-13
|
3KB
|
90 lines
#include <ctype.h>
#include <errno.h>
#include <math.h>
#include "float.h"
#ifndef errno
extern int errno;
#endif
extern struct {
double n[308];
double p[DBL_MAX_10_EXP + 1];
} dp10_;
double atof(dstr)
char *dstr; /* any correctly working atof() may be used */
{
int c, /* difference from exponent of accumulated
integer to final value */
exp = 0, neg_val = 0, /* leading negative sign ? */
e_exp = 0, /* number after e/E +/- */
neg_exp = 0, /* - after E/e ? */
fdig = 0;
#ifdef __STDC__
long double x, retval = 0, r = 0;
#else
register double x, retval = 0, r = 0;
#endif
while (isspace(c = *dstr)) /* skip leading space */
dstr++;
switch (c) { /* optional sign */
case '-':
neg_val = 1;
case '+': /* fall-through */
dstr++;
}
if (isdigit(c = *dstr++))
/* add up converted values before dec point */
do /* changed from while to do while for optimization */
retval = 10 * retval + (double) (c - '0' while (isdigit(c = *dstr++));
if (c == '.')
#if LDBL_DIG > DBL_DIG
while (isdigit(c = *dstr++)) /* and after dec pt */
retval += (c - '0') * dp10_.p[--fdig];
#else
if (isdigit(c = *dstr++))
for (;;) { /* and after dec pt, order of operations
must be as shown */
retval = (x = retval) + (r += (c - '0') * dp10_.p[--fdig]);
if (!isdigit(c = *dstr++))
break;
r += x -= retval; /* numerical error correction term */
}
#endif
if ((c | ' ') == 'e') { /* found an exponent lead-in */
switch (*dstr) { /* sign field */
case '-':
neg_exp = 1;
case '+': /* fall-through */
case ' ': /* many FORTRAN environments generate this! */
dstr++;
default:
; /* fall-through */
}
if (isdigit(c = *dstr)) /* found exponent digit */
do
e_exp = 10 * e_exp + (int) (c - '0');
while (isdigit(c = *++dstr));
}
if ((exp += neg_exp ? -e_exp : e_exp) >= 0)
if (exp <= DBL_MAX_10_EXP)
retval *= dp10_.p[exp];
else {
errno = ERANGE;
retval = HUGE_VAL;
}
else if ((exp = -exp) <= DBL_MAX_10_EXP)
retval /= dp10_.p[exp];
else if (exp - DBL_MAX_10_EXP / 2 <= DBL_MAX_10_EXP) {
retval /= dp10_.p[DBL_MAX_10_EXP / 2];
retval /= dp10_.p[exp - DBL_MAX_10_EXP / 2];
} else {
retval = 0;
errno = ERANGE;
}
return (neg_val ? -retval : retval); /* apply sign */
}