ack/lang/cem/libcc/gen/strtod.c
1988-08-11 15:59:35 +00:00

98 lines
1.7 KiB
C

/* $Header$ */
#ifndef NOFLOAT
#include <ctype.h>
extern double ldexp();
#define MAX (0x7fffffffL/10)
double
strtod(p, pp)
register char *p;
char **pp;
{
register int c;
int exp = 0, sign = 1, expsign = 0;
double fl;
long lowl = 0, highl = 0, pos = 1;
int dotseen = 0;
int digit_seen = 0;
if (pp) *pp = p;
while (isspace(*p)) p++;
c = *p;
switch (c) {
case '-':
sign = -1;
case '+':
p++;
}
while (isdigit(c = *p++) || (c == '.' && ! dotseen++)) {
if (c == '.') continue;
digit_seen = 1;
if (highl < MAX) {
highl = (highl << 3) + (highl << 1) + (c - '0');
}
else if (pos < MAX) {
pos = (pos << 3) + (pos << 1);
lowl = (lowl << 3) + (lowl << 1) + (c - '0');
}
else exp++;
if (dotseen) exp--;
}
if (! digit_seen) return 0.0;
fl = highl;
if (pos > 1) {
fl = pos * fl + lowl;
}
if (pp) *pp = p-1;
if (c == 'E' || c == 'e') {
int exp1 = 0;
int sign = 1;
switch (*p) {
case '-':
sign = -1;
case '+':
p++;
}
if (isdigit(c = *p)) {
do {
exp1 = 10 * exp1 + c - '0';
} while (isdigit(c = *++p));
if (pp) *pp = p;
}
exp += sign * exp1;
}
if (fl == 0.0) return 0.0;
if (exp < 0) {
expsign = 1;
exp = -exp;
}
if (exp != 0) {
int oldexp = exp;
double exp5 = 5.0;
double correction = 1.0;
while (exp) {
if (exp % 2) correction *= exp5;
exp /= 2;
if (exp != 0) exp5 *= exp5;
}
if (expsign) fl = fl / correction;
else fl = fl * correction;
fl = ldexp(fl, expsign ? -oldexp : oldexp);
}
return sign * fl;
}
#endif