home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
listings
/
v_09_07
/
9n07077a
< prev
next >
Wrap
Text File
|
1991-02-12
|
5KB
|
141 lines
/* 4.xBSD and AT&T V.3 documented entry points are
** #define ecvt(arg,ndigs,decexp,neg) cvt(arg,ndigs,decexp,neg,0)
** #define fcvt(arg,ndigs,decexp,neg) cvt(arg,ndigs,decexp,neg,1)
** and gcvt, for which a simplified version is given which
** does not strip trailing .0000
** Microsoft gcvt() has only 3 arguments (?)
**
** Nota Bene:
** AT&T sense of 4th argument */
typedef int LOGICAL;
#include <math.h>
#include "float.h"
extern struct {
double n[308];
double p[DBL_MAX_10_EXP];
} dp10_;
char *ecvt(value, ndigit, decpt, sign)
double value;
int ndigit, *decpt, *sign;
{
char *cvt();
return (cvt(value, ndigit, decpt, sign, 0 ));
}
char *fcvt(value, ndigit, decpt, sign)
double value;
int ndigit, *decpt, *sign;
{
char *cvt();
return (cvt(value, ndigit, decpt, sign, 1 ));
}
char *cvt(arg, ndigs, decexp, neg, ffmt)
register double arg;
int ndigs, *decexp;
LOGICAL *neg, ffmt;
{
static char buf[80]; /* shouldn't need more than 25 */
long high, low; /* assumed wide enough for 9+ digits */
#ifdef __STDC__
#include <limits.h>
#if (LONG_MAX < 999999999) /* uncomment #error if possible */
/*#error "code assumes 9 digits fit in long"*/
#endif
#include <stdlib.h>
#define split(a,b) (r=ldiv(a,b))
#else
typedef struct {
long quot;
long rem;
} ldiv_t;
#ifdef sun
#define split(a,b) (r.rem=a-(r.quot=a/b)*b)
#else
#define split(a,b) (r.quot=a/b,r.rem=a%b)
#endif
#endif
ldiv_t r;
int scale, totdigs, scalarg, maxscale;
char *bufptr;
register double x, dri; /* accumulate powers of 10 */
LOGICAL pneg;
register int i;
#define ODD(i) ((i)&1) /* like Pascal */
*decexp = 3; /* so gcvt won't add 0's or exponent */
#define isnan(arg) (arg != arg)
if (isnan(arg))
return "NaN"; /* Sun library has isnan(),isinf() * but IEEE
compliant compiler would recognize defines *
#define isinf(arg) (arg==1/0.) */
arg = (*neg = (arg < 0)) ? -arg : arg; /* only gcvt() actually
inserts '-' */
if (arg >= DBL_MAX*2) {
*decexp = 8;
return "Infinity";
}
if (arg == 0) { /* don't force weird e format for 0 */
*decexp = 1;
return "0";
}
/* search in table can be used instead of log()
** need negative powers in table
** speed up search by using log10() to find approximate index */
scalarg = (int) log10(arg) + (arg > 1); /* ceil() in line */
if (scalarg >= DBL_MIN_10_EXP & scalarg <= DBL_MAX_10_EXP)
scalarg += (arg >= dp10_.p[scalarg]) - (arg < dp10_.p[scalarg - 1]); /* adjust */
if ((scale = ffmt ? ndigs : ndigs - scalarg) > (maxscale = 18 - scalarg)) {
/* reduce ndigs for 18 max */
ndigs += maxscale - scale;
scale = maxscale;
}
if (scale >= 14) { /* extend range by splitting high end off
first */
if (scale - 14 <= DBL_MAX_10_EXP)
arg *= dp10_.p[scale - 14];
else { /* avoid overflow */
arg *= dp10_.p[DBL_MAX_10_EXP / 2];
arg *= dp10_.p[scale - 14 - DBL_MAX_10_EXP / 2];
} /* can't compare accurately with original arg */
low = arg = (arg - (high = arg)) * 1e5; /* split off 4 digits */
high = high * 100000 + low; /* add 5 more */
low = (arg - low) * 1e9 + .5; /* round off last 9 */
} else if (scale < 9) { /* split low end off first */
high = 0;
if ((ndigs > 9) | ffmt) /* prevents violating table
boundary */
arg -= (high = arg / dp10_.p[9 - scale]) * dp10_.p[9 - scale];
low = (scale < 0 ? arg / dp10_.p[-scale] : arg * dp10_.p[scale]) + .5;
} else { /* 9 <= scale < 14 */
arg *= dp10_.p[scale - 9];
low = (arg - (high = arg)) * 1e9 + .5;
}
high += low >= 1000000000; /* carry from rounding */
/* convert high//low to string */
*(bufptr = buf + 19) = '\0';
for (i = 0; ++i <= 9;) {
split(low, 10);
*(--bufptr) = r.rem + '0';
low = r.quot;
split(high, 10);
*(bufptr - 9) = r.rem + '0';
high = r.quot;
}
/* discard leading zero */
for (totdigs = 18, bufptr -= 9; (bufptr[0] == '0') & (bufptr[1] != '\0'); ++bufptr)
--totdigs;
/* one trailing zero ought to be discarded, in the case where it
** is the result of rounding up, so that, if the carry goes all the way
** across, totdigs will not be greater than requested
** also, trailing zeros beyond DBL_DIG can degrade accuracy of conversion back to binary */
*decexp = totdigs - (ffmt ? ndigs : scale);
return bufptr;
}