new, much faster version

This commit is contained in:
ceriel 1988-08-10 09:14:43 +00:00
parent e6d132830a
commit d388145dce

View file

@ -1,6 +1,6 @@
/* $Header$ */ /* $Header$ */
#ifndef NOFLOAT #ifndef NOFLOAT
extern double modf();
static char *cvt(); static char *cvt();
#define NDIGITS 128 #define NDIGITS 128
@ -20,21 +20,32 @@ fcvt(value, ndigit, decpt, sign)
return cvt(value, ndigit, decpt, sign, 0); return cvt(value, ndigit, decpt, sign, 0);
} }
static struct powers_of_10 {
double pval;
double rpval;
int exp;
} p10[] = {
1.0e32, 1.0e-32, 32,
1.0e16, 1.0e-16, 16,
1.0e8, 1.0e-8, 8,
1.0e4, 1.0e-4, 4,
1.0e2, 1.0e-2, 2,
1.0e1, 1.0e-1, 1,
1.0e0, 1.0e0, 0
};
static char * static char *
cvt(value, ndigit, decpt, sign, ecvtflag) cvt(value, ndigit, decpt, sign, ecvtflag)
double value; double value;
int ndigit, *decpt, *sign; int ndigit, *decpt, *sign;
{ {
double intpart, fractpart;
static char buf[NDIGITS+1]; static char buf[NDIGITS+1];
char buf1[NDIGITS+1]; register char *p = buf;
register char *pe = buf1; register char *pe;
register char *pb;
int pointpos = 0;
if (ndigit < 0) ndigit = 0; if (ndigit < 0) ndigit = 0;
if (ndigit >= NDIGITS - 10) ndigit = NDIGITS - 11; if (ndigit > NDIGITS) ndigit = NDIGITS;
pe = &buf[ndigit];
*sign = 0; *sign = 0;
if (value < 0) { if (value < 0) {
@ -42,60 +53,44 @@ cvt(value, ndigit, decpt, sign, ecvtflag)
value = -value; value = -value;
} }
fractpart = modf(value, &intpart); *decpt = 0;
if (intpart != 0) { if (value != 0.0) {
do { /* get digits of integer part, low order digit register struct powers_of_10 *pp = &p10[0];
first
*/ if (value >= 10.0) do {
value = modf(intpart/10.0, &intpart); while (value >= pp->pval) {
/* compensate for rounding errors, because value *= pp->rpval;
the conversion to "int" truncates *decpt += pp->exp;
*/
if (pe >= &buf1[NDIGITS]) {
pb = &buf1[10];
pe = &buf1[0];
while (pb < &buf1[NDIGITS]) *pe++ = *pb++;
} }
*pe++ = (int)((value+.05) * 10.0) + '0'; } while ((++pp)->exp > 0);
pointpos++;
} while (intpart != 0); pp = &p10[0];
pb = buf; if (value < 1.0) do {
while (pe > buf1) *pb++ = *--pe; while (value * pp->pval < 10.0) {
} value *= pp->pval;
else { *decpt -= pp->exp;
pb = &buf[0];
if (value > 0) {
fractpart = value;
while ((value = value*10.0) < 1) {
fractpart = value;
pointpos--;
} }
} } while ((++pp)->exp > 0);
(*decpt)++; /* because now value in [1.0, 10.0) */
} }
pe = &buf[ndigit];
if (! ecvtflag) { if (! ecvtflag) {
/* for fcvt() we need ndigit digits behind the dot */ /* for fcvt() we need ndigit digits behind the dot */
pe += pointpos; pe += *decpt;
if (pe < buf) {
/* pointpos was too far left of the beginning */
buf[0] = 0;
*decpt = pointpos;
return buf;
}
if (pe > &buf[NDIGITS]) pe = &buf[NDIGITS]; if (pe > &buf[NDIGITS]) pe = &buf[NDIGITS];
} }
while (pb <= pe) { while (p <= pe) {
fractpart = modf(fractpart * 10.0, &value); *p++ = (int)value + '0';
*pb++ = (int)value + '0'; value = 10.0 * (value - (int)value);
} }
pb = pe; p = pe;
*pb += 5; /* round of at the end */ *p += 5; /* round of at the end */
while (*pb > '9') { while (*p > '9') {
*pb = '0'; *p = '0';
if (pb > buf) ++*--pb; if (p > buf) ++*--p;
else { else {
*pb = '1'; *p = '1';
pointpos++; ++*decpt;
if (! ecvtflag) { if (! ecvtflag) {
/* maybe add another digit at the end, /* maybe add another digit at the end,
because the point was shifted right because the point was shifted right
@ -105,7 +100,6 @@ cvt(value, ndigit, decpt, sign, ecvtflag)
} }
} }
} }
*decpt = pointpos;
*pe = '\0'; *pe = '\0';
return buf; return buf;
} }