use new ecvt.c from C library
authorceriel <none@none>
Wed, 10 Aug 1988 11:21:40 +0000 (11:21 +0000)
committerceriel <none@none>
Wed, 10 Aug 1988 11:21:40 +0000 (11:21 +0000)
lang/pc/libpc/cvt.c

index 07aff23..9867a63 100644 (file)
 /* $Header$ */
-/*
- * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
- *
- *          This product is part of the Amsterdam Compiler Kit.
- *
- * Permission to use, sell, duplicate or disclose this software must be
- * obtained in writing. Requests for such permissions may be sent to
- *
- *      Dr. Andrew S. Tanenbaum
- *      Wiskundig Seminarium
- *      Vrije Universiteit
- *      Postbox 7161
- *      1007 MC Amsterdam
- *      The Netherlands
- *
- */
+#ifndef NOFLOAT
 
-extern double  _fif();
+static char *cvt();
+#define NDIGITS        128
 
-/*
- *     _ecvt converts to decimal
- *     the number of digits is specified by ndigit
- *     decpt is set to the position of the decimal point
- *     sign is set to 0 for positive, 1 for negative
- */
+char *
+_ecvt(value, ndigit, decpt, sign)
+       double value;
+       int ndigit, *decpt, *sign;
+{
+       return cvt(value, ndigit, decpt, sign, 1);
+}
+
+char *
+_fcvt(value, ndigit, decpt, sign)
+       double value;
+       int ndigit, *decpt, *sign;
+{
+       return cvt(value, ndigit, decpt, sign, 0);
+}
 
-#define        NDIG    80
+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*
-cvt(arg, ndigits, decpt, sign, eflag)
-double arg;
-int ndigits, *decpt, *sign, eflag;
+static char *
+cvt(value, ndigit, decpt, sign, ecvtflag)
+       double value;
+       int ndigit, *decpt, *sign;
 {
-       register int r2;
-       double fi, fj;
-       register char *p, *p1;
-       static char buf[NDIG];
-       int i;  /*!*/
+       static char buf[NDIGITS+1];
+       register char *p = buf;
+       register char *pe;
+
+       if (ndigit < 0) ndigit = 0;
+       if (ndigit > NDIGITS) ndigit = NDIGITS;
+       pe = &buf[ndigit];
+       buf[0] = '\0';
 
-       if (ndigits<0)
-               ndigits = 0;
-       if (ndigits>=NDIG-1)
-               ndigits = NDIG-2;
-       r2 = 0;
        *sign = 0;
-       p = &buf[0];
-       if (arg<0) {
+       if (value < 0) {
                *sign = 1;
-               arg = -arg;
+               value = -value;
        }
-       arg = _fif(arg, 1.0, &fi);
-       /*
-        * Do integer part
-        */
-       if (fi != 0) {
-               p1 = &buf[NDIG];
-               while (fi != 0) {
-                       i = (_fif(fi, 0.1, &fi) + 0.03) * 10;
-                       *--p1 = i + '0';
-                       r2++;
-               }
-               while (p1 < &buf[NDIG])
-                       *p++ = *p1++;
-       } else if (arg > 0) {
-               while ((fj = arg*10) < 1) {
-                       arg = fj;
-                       r2--;
-               }
-       }
-       p1 = &buf[ndigits];
-       if (eflag==0)
-               p1 += r2;
-       *decpt = r2;
-       if (p1 < &buf[0]) {
-               buf[0] = '\0';
-               return(buf);
+
+       *decpt = 0;
+       if (value != 0.0) {
+               register struct powers_of_10 *pp = &p10[0];
+
+               if (value >= 10.0) do {
+                       while (value >= pp->pval) {
+                               value *= pp->rpval;
+                               *decpt += pp->exp;
+                       }
+               } while ((++pp)->exp > 0);
+
+               pp = &p10[0];
+               if (value < 1.0) do {
+                       while (value * pp->pval < 10.0) {
+                               value *= pp->pval;
+                               *decpt -= pp->exp;
+                       }
+               } while ((++pp)->exp > 0);
+
+               (*decpt)++;     /* because now value in [1.0, 10.0) */
        }
-       while (p<=p1 && p<&buf[NDIG]) {
-               arg = _fif(arg, 10.0, &fj);
-               i = fj;
-               *p++ = i + '0';
+       if (! ecvtflag) {
+               /* for fcvt() we need ndigit digits behind the dot */
+               pe += *decpt;
+               if (pe > &buf[NDIGITS]) pe = &buf[NDIGITS];
        }
-       if (p1 >= &buf[NDIG]) {
-               buf[NDIG-1] = '\0';
-               return(buf);
+       while (p <= pe) {
+               *p++ = (int)value + '0';
+               value = 10.0 * (value - (int)value);
        }
-       p = p1;
-       *p1 += 5;
-       while (*p1 > '9') {
-               *p1 = '0';
-               if (p1>buf) {
-                       p1--; *p1 += 1;
-               } else {
-                       *p1 = '1';
-                       (*decpt)++;
-                       if (eflag==0) {
-                               if (p>buf)
-                                       *p = '0';
-                               p++;
+       if (pe >= buf) {
+               p = pe;
+               *p += 5;        /* round of at the end */
+               while (*p > '9') {
+                       *p = '0';
+                       if (p > buf) ++*--p;
+                       else {
+                               *p = '1';
+                               ++*decpt;
+                               if (! ecvtflag) {
+                                       /* maybe add another digit at the end,
+                                          because the point was shifted right
+                                       */
+                                       if (pe > buf) *pe = '0';
+                                       pe++;
+                               }
                        }
                }
+               *pe = '\0';
        }
-       *p = '\0';
-       return(buf);
-}
-
-char*
-_ecvt(arg, ndigits, decpt, sign)
-double arg;
-int ndigits, *decpt, *sign;
-{
-       return(cvt(arg, ndigits, decpt, sign, 1));
-}
-
-char*
-_fcvt(arg, ndigits, decpt, sign)
-double arg;
-int ndigits, *decpt, *sign;
-{
-       return(cvt(arg, ndigits, decpt, sign, 0));
+       return buf;
 }
+#endif