diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
commit | d6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch) | |
tree | ece253b876159b39c620e62b6c9b1174642e070e /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.cc | 335 |
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 |