summaryrefslogtreecommitdiff
path: root/gnu/lib/libg++/g++-include/dtoa.cc
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
commitd6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch)
treeece253b876159b39c620e62b6c9b1174642e070e /gnu/lib/libg++/g++-include/dtoa.cc
initial import of NetBSD tree
Diffstat (limited to 'gnu/lib/libg++/g++-include/dtoa.cc')
-rw-r--r--gnu/lib/libg++/g++-include/dtoa.cc335
1 files changed, 335 insertions, 0 deletions
diff --git a/gnu/lib/libg++/g++-include/dtoa.cc b/gnu/lib/libg++/g++-include/dtoa.cc
new file mode 100644
index 00000000000..81d7551daae
--- /dev/null
+++ b/gnu/lib/libg++/g++-include/dtoa.cc
@@ -0,0 +1,335 @@
+/*
+Copyright (C) 1990 Free Software Foundation
+ written by Doug Lea (dl@rocky.oswego.edu)
+
+This file is part of the GNU C++ Library. This library is free
+software; you can redistribute it and/or modify it under the terms of
+the GNU Library General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version. This library is distributed in the hope
+that it will be useful, but WITHOUT ANY WARRANTY; without even the
+implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+PURPOSE. See the GNU Library General Public License for more details.
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifdef __GNUG__
+#pragma implementation
+#endif
+#include <builtin.h>
+#include <math.h>
+#include <values.h>
+#include <AllocRing.h>
+
+extern AllocRing _libgxx_fmtq;
+
+#ifdef __GNUC__ /* cfront cannot compile this routine */
+// OBSOLETE ROUTINE!
+
+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;
+ }
+ double almost_one = 1.0 - rounder;
+ while (fpnum > 0.0 && fpnum < almost_one)
+ {
+ 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;
+}
+#endif