386BSD 0.0 development
authorWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Thu, 29 Nov 1990 18:03:19 +0000 (10:03 -0800)
committerWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Thu, 29 Nov 1990 18:03:19 +0000 (10:03 -0800)
Work on file usr/src/lib/libg++/libg++/dtoa.cc

Co-Authored-By: Lynne Greer Jolitz <ljolitz@cardio.ucsf.edu>
Synthesized-from: 386BSD-0.0/src

usr/src/lib/libg++/libg++/dtoa.cc [new file with mode: 0644]

diff --git a/usr/src/lib/libg++/libg++/dtoa.cc b/usr/src/lib/libg++/libg++/dtoa.cc
new file mode 100644 (file)
index 0000000..25eb7bf
--- /dev/null
@@ -0,0 +1,336 @@
+/* 
+Copyright (C) 1990 Free Software Foundation
+    written by Doug Lea (dl@rocky.oswego.edu)
+
+This file is part of GNU CC.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY.  No author or distributor
+accepts responsibility to anyone for the consequences of using it
+or for whether it serves any particular purpose or works at all,
+unless he says so in writing.  Refer to the GNU CC General Public
+License for full details.
+
+Everyone is granted permission to copy, modify and redistribute
+GNU CC, but only under the conditions described in the
+GNU CC General Public License.   A copy of this license is
+supposed to have been given to you along with GNU CC so you
+can know your rights and responsibilities.  It should be in a
+file named COPYING.  Among other things, the copyright notice
+and this notice must be preserved on all copies.  
+*/
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+#include <builtin.h>
+#include <math.h>
+#include <values.h>
+#include <AllocRing.h>
+
+extern AllocRing _libgxx_fmtq;
+
+char* dtoa(double fpnum,  char cvt, int width, int prec)
+{
+  // set up workspace
+
+  // max possible digits <= those need to show all of prec + exp
+  // <= ceil(log10(HUGE)) plus space for null, etc.
+
+  const int worksiz = int((M_LN2 / M_LN10) * DMAXEXP) + 8; 
+
+  // for fractional part
+  char  fwork[worksiz];
+  char* fw = fwork;
+
+  // for integer part
+  char  iwork[worksiz];
+  char* iworkend = &iwork[sizeof(iwork) - 1];
+  char* iw = iworkend;
+  *iw = 0;
+
+  // for exponent part
+
+  const int eworksiz = int(M_LN2 * _DEXPLEN) + 8;
+  char  ework[eworksiz];
+  char* eworkend = &ework[sizeof(ework) - 1];
+  char* ew = eworkend;
+  *ew = 0;
+
+#if (_IEEE != 0)
+  if (isinf(fpnum))
+  {
+    char* inffmt = (char *) _libgxx_fmtq.alloc(5);
+    char* inffmtp = inffmt;
+    if (fpnum < 0)
+      *inffmtp++ = '-';
+    strcpy(inffmtp, "Inf");
+    return inffmt;
+  }
+
+  if (isnan(fpnum))
+  {
+    char* nanfmt = (char *) _libgxx_fmtq.alloc(4);
+    strcpy(nanfmt, "NaN");
+    return nanfmt;
+  }
+#endif
+
+  // grab sign & make non-negative
+  int is_neg = fpnum < 0;
+  if (is_neg) fpnum = -fpnum;
+
+  // precision matters
+
+  if (prec > worksiz - 2) // can't have more prec than supported
+    prec = worksiz - 2;
+  
+  double powprec;
+  if (prec == 6)
+    powprec = 1.0e6;
+  else
+    powprec = pow(10.0, (long) prec);
+
+  double rounder = 0.5 / powprec;
+
+  int f_fmt = cvt == 'f' ||
+    ((cvt == 'g') && (fpnum == 0.0 || (fpnum >= 1e-4 && fpnum < powprec)));
+
+  int iwidth = 0;
+  int fwidth = 0;
+  int ewidth = 0;
+
+  if (f_fmt)  // fixed format
+  {
+    double ipart;
+    double fpart = modf(fpnum, &ipart);
+
+    // convert fractional part
+
+    if (fpart >= rounder || cvt != 'g')
+    {
+      fpart += rounder;
+      if (fpart >= 1.0)
+      {
+        ipart += 1.0;
+        fpart -= 1.0;
+      }
+      double ffpart = fpart;
+      double ifpart;
+      for (int i = 0; i < prec; ++i)
+      {
+        ffpart = modf(ffpart * 10.0, &ifpart);
+        *fw++ = '0' + int(ifpart);
+        ++fwidth;
+      }
+      if (cvt == 'g')  // inhibit trailing zeroes if g-fmt
+      {
+        for (char* p = fw - 1; p >= fwork && *p == '0'; --p)
+        {
+          *p = 0;
+          --fwidth;
+        }
+      }
+    }
+
+    // convert integer part
+    if (ipart == 0.0)
+    {
+      if (cvt != 'g' || fwidth < prec || fwidth < width)
+      {
+        *--iw = '0'; ++iwidth;
+      }
+    }
+    else if (ipart <= double(MAXLONG)) // a useful speedup
+    {
+      long li = long(ipart);
+      while (li != 0)
+      {
+        *--iw = '0' + (li % 10);
+        li = li / 10;
+        ++iwidth;
+      }
+    }
+    else // the slow way
+    {
+      while (ipart > 0.5)
+      {
+        double ff = modf(ipart / 10.0, &ipart);
+        ff = (ff + 0.05) * 10.0;
+        *--iw = '0' + int(ff);
+        ++iwidth;
+      }
+    }
+
+    // g-fmt: kill part of frac if prec/width exceeded
+    if (cvt == 'g')
+    {
+      int m = prec;
+      if (m < width)
+        m = width;
+      int adj = iwidth + fwidth - m;
+      if (adj > fwidth)
+        adj = fwidth;
+      if (adj > 0)
+      {
+        for (char* f = &fwork[fwidth-1]; f >= fwork && adj > 0; --adj, --f)
+        {
+          --fwidth;
+          char ch = *f;
+          *f = 0;
+          if (ch > '5') // properly round: unavoidable propagation
+          {
+            int carry = 1;
+            for (char* p = f - 1; p >= fwork && carry; --p)
+            {
+              ++*p;
+              if (*p > '9')
+                *p = '0';
+              else
+                carry = 0;
+            }
+            if (carry)
+            {
+              for (p = iworkend - 1; p >= iw && carry; --p)
+              {
+                ++*p;
+                if (*p > '9')
+                  *p = '0';
+                else
+                  carry = 0;
+              }
+              if (carry)
+              {
+                *--iw = '1';
+                ++iwidth;
+                --adj;
+              }
+            }
+          }
+        }
+      }
+    }
+              
+  }
+  else  // e-fmt
+  {
+    
+    // normalize
+    int exp = 0;
+    while (fpnum >= 10.0)
+    {
+      fpnum *= 0.1;
+      ++exp;
+    }
+    while (fpnum > 0.0 && fpnum < 1.0)
+    {
+      fpnum *= 10.0;
+      --exp;
+    }
+    
+    double ipart;
+    double fpart = modf(fpnum, &ipart);
+
+
+    if (cvt == 'g')     // used up one digit for int part...
+    {
+      --prec;
+      powprec /= 10.0;
+      rounder = 0.5 / powprec;
+    }
+
+    // convert fractional part -- almost same as above
+    if (fpart >= rounder || cvt != 'g')
+    {
+      fpart += rounder;
+      if (fpart >= 1.0)
+      {
+        fpart -= 1.0;
+        ipart += 1.0;
+        if (ipart >= 10.0)
+        {
+          ++exp;
+          ipart /= 10.0;
+          fpart /= 10.0;
+        }
+      }
+      double ffpart = fpart;
+      double ifpart;
+      for (int i = 0; i < prec; ++i)
+      {
+        ffpart = modf(ffpart * 10.0, &ifpart);
+        *fw++ = '0' + int(ifpart);
+        ++fwidth;
+      }
+      if (cvt == 'g')  // inhibit trailing zeroes if g-fmt
+      {
+        for (char* p = fw - 1; p >= fwork && *p == '0'; --p)
+        {
+          *p = 0;
+          --fwidth;
+        }
+      }
+    }
+
+    
+    // convert exponent
+
+    char eneg = exp < 0;
+    if (eneg) exp = - exp;
+
+    while (exp > 0)
+    {
+      *--ew = '0' + (exp % 10);
+      exp /= 10;
+      ++ewidth;
+    }
+
+    while (ewidth < 2)  // ensure at least 2 zeroes
+    {
+      *--ew = '0';
+      ++ewidth;
+    }
+
+    *--ew = eneg ? '-' : '+';
+    *--ew = 'e';
+
+    ewidth += 2;
+
+    // convert the one-digit integer part
+    *--iw = '0' + int(ipart);
+    ++iwidth;
+    
+  }
+
+  // arrange everything in returned string
+
+  int showdot = cvt != 'g' || fwidth > 0;
+
+  int fmtwidth = is_neg + iwidth + showdot + fwidth + ewidth;
+  
+  int pad = width - fmtwidth;
+  if (pad < 0) pad = 0;
+  
+  char* fmtbase = (char *) _libgxx_fmtq.alloc(fmtwidth + pad + 1);
+  char* fmt = fmtbase;
+  
+  for (int i = 0; i < pad; ++i) *fmt++ = ' ';
+  
+  if (is_neg) *fmt++ = '-';
+  
+  for (i = 0; i < iwidth; ++i) *fmt++ = *iw++;
+  
+  if (showdot)
+  {
+    *fmt++ = '.';
+    fw = fwork;
+    for (i = 0; i < fwidth; ++i) *fmt++ = *fw++;
+  }
+  
+  for (i = 0; i < ewidth; ++i) *fmt++ = *ew++;
+  
+  *fmt = 0;
+  
+  return fmtbase;
+}
+