Date: Mon, 26 Jan 1998 11:02:04 -0600 (CST) From: Dave Bodenstab <imdave@mcs.net> To: albast@xs4all.nl, questions@FreeBSD.ORG Subject: Re: Where's gcvt(3) ?? Message-ID: <199801261702.LAA18553@base486.home.org>
next in thread | raw e-mail | index | archive | help
> From: albast <albast@xs4all.nl> > Why doesn't FreeBSD (2.2.5) include gcvt(3), which converts > a floating-point number to a string? > > I need this one in order to use YACL (http://www.cs.sc.edu/~sridhar/yacl.html) > on my FreeBSD system. As others have mentioned, you can usually use sprintf to accomplish the same thing. It is a pain, tho, to have to figure out the appropriate fix each time it arises -- there is more that one software package that assumes that the *cvt() family of functions exist. To solve this at one point in the past, I ported versions from Linux's 5.4.7 libc. I also have a man page, but I don't remember where I got that -- I probably found it via Altavista when I was trying to find *cvt. Anyway, here are the RCS files for cvt.c and gcvt.c, and the man page. Compile with -DTEST to get an interactive test driver. Dave Bodenstab imdave@mcs.net ---- Cut Here and feed the following to sh ---- #!/bin/sh # This is a shell archive (produced by GNU sharutils 4.2). # To extract the files from this archive, save it to some FILE, remove # everything before the `!/bin/sh' line above, then type `sh FILE'. # # Made on 1998-01-26 10:52 CST by <imdave@base486.home.org>. # Source directory was `/usr/local/src/lib/liblocal'. # # existing files WILL be overwritten # # This shar contains: # length mode name # ------ ---------- ------------------------------------------ # 3841 -r--r--r-- cvt.c,v # 1498 -rw-r--r-- ecvt.3 # 1517 -r--r--r-- gcvt.c,v # echo=echo # ============= cvt.c,v ============== $echo 'x -' extracting 'cvt.c,v' '(text)' sed 's/^X//' << 'SHAR_EOF' > 'cvt.c,v' && Xhead 54.7; Xbranch 54.7.1; Xaccess; Xsymbols; Xlocks; strict; Xcomment @ * @; X X X54.7 Xdate 96.11.08.21.07.45; author Linux; state Exp; Xbranches X 54.7.1.1; Xnext ; X X54.7.1.1 Xdate 96.11.08.21.07.45; author bin; state Exp; Xbranches; Xnext ; X X Xdesc X@Ecvt(), Fcvt() and Gcvt() Library Routines X@ X X X54.7 Xlog X@Linux libc-5.4.7/libc/cvt X@ Xtext X@#include <stdlib.h> X#include <math.h> X#include <ieee754.h> X X#define IEEE 1 X X/* X * ecvt converts to decimal X * the number of digits is specified by ndigit X * decpt is set to the position of the decimal point X * sign is set to 0 for positive, 1 for negative X */ X X#ifdef IEEE X Xstatic inline int X__isspecial(double f, char *bp) X{ X union ieee754_double *ip = (union ieee754_double *) &f; X X if ((ip->ieee.exponent & 0x7ff) != 0x7ff) X return(0); X if (ip->ieee.mantissa0 || ip->ieee.mantissa1) X strcpy(bp, "NaN"); X else if (ip->ieee.negative) X strcpy(bp, "-Infinity"); X else X strcpy(bp, "Infinity"); X return(1); X} X X#define NDIG 512 X#else X#define NDIG 80 X#endif X Xstatic char* Xcvt(double arg, size_t ndigits, int *decpt, int *sign, int eflag) X{ X register int r2; X double fi, fj; X register char *p, *p1; X static char buf[NDIG]; X X#ifdef IEEE X /* XXX */ X if (__isspecial(arg, buf)) X return(buf); X#endif X if (ndigits>=NDIG-1) X ndigits = NDIG-2; X r2 = 0; X *sign = 0; X p = &buf[0]; X if (arg<0) { X *sign = 1; X arg = -arg; X } X arg = modf(arg, &fi); X p1 = &buf[NDIG]; X /* X * Do integer part X */ X if (fi != 0) { X p1 = &buf[NDIG]; X while (fi != 0) { X fj = modf(fi/10, &fi); X *--p1 = (int)((fj+.03)*10) + '0'; X r2++; X } X while (p1 < &buf[NDIG]) X *p++ = *p1++; X } else if (arg > 0) { X while ((fj = arg*10) < 1) { X arg = fj; X r2--; X } X } X p1 = &buf[ndigits]; X if (eflag==0) X p1 += r2; X *decpt = r2; X if (p1 < &buf[0]) { X buf[0] = '\0'; X return(buf); X } X while (p<=p1 && p<&buf[NDIG]) { X arg *= 10; X arg = modf(arg, &fj); X *p++ = (int)fj + '0'; X } X if (p1 >= &buf[NDIG]) { X buf[NDIG-1] = '\0'; X return(buf); X } X p = p1; X *p1 += 5; X while (*p1 > '9') { X *p1 = '0'; X if (p1>buf) X ++*--p1; X else { X *p1 = '1'; X (*decpt)++; X if (eflag==0) { X if (p>buf) X *p = '0'; X p++; X } X } X } X *p = '\0'; X return(buf); X} X Xchar* Xecvt(double arg, size_t ndigits, int *decpt, int *sign) X{ X return(cvt(arg, ndigits, decpt, sign, 1)); X} X Xchar* Xfcvt(double arg, size_t ndigits, int *decpt, int *sign) X{ X return(cvt(arg, ndigits, decpt, sign, 0)); X} X X@ X X X54.7.1.1 Xlog X@Port to FreeBSD X@ Xtext X@d26 1 Xa26 1 X strcpy(bp, "-Inf"); Xd28 1 Xa28 1 X strcpy(bp, "Inf"); Xd47 1 Xa47 3 X if (__isspecial(arg, buf)) { X *sign = *buf == '-'; X *decpt = ndigits; Xa48 1 X } Xa127 60 X X#ifdef TEST X#include <stdio.h> X Xchar *gcvt(double,size_t,char*); X X int Xmain( int argc, char **argv ) X{ X char *(*f)(double,size_t,int*,int*), *p; X char buf[512]; X int i, width, decpt, ndigits, sign; X X switch( argv[0][0] ) X { X case 'e': X f = ecvt; X break; X case 'f': X f = fcvt; X break; X case 'g': X f = NULL; X break; X default: X fprintf( stderr, "Usage: [efg]cvt ndigits number...\n" ); X exit( 1 ); X } X X if ( --argc <= 1 || (ndigits = atoi(*++argv)) <= 0 ) X { X fprintf( stderr, "Usage: [efg]cvt ndigits number...\n" ); X exit( 1 ); X } X X width = 0; X for( i = 1; i < argc; ++i ) X if ( width < strlen(argv[i]) ) X width = strlen( argv[i] ); X X while( --argc > 0 ) X { X if (f) X { X p = (*f)( atof(*++argv), ndigits, &decpt, &sign ); X if ( f == fcvt ) X printf( "%-*s:\tsign=%d decpt=%d '%s'\t%.*f\n", width, *argv, sign, decpt, p, ndigits, atof(*argv) ); X else X printf( "%-*s:\tsign=%d decpt=%d '%s'\t%.*e\n", width, *argv, sign, decpt, p, ndigits-1, atof(*argv) ); X } X else X { X p = gcvt( atof(*++argv), ndigits, buf ); X printf( "%-*s:\t'%s'\t%.*g\n", width, *argv, p, ndigits, atof(*argv) ); X } X } X X return 0; X} X#endif X@ SHAR_EOF chmod 0444 'cvt.c,v' || $echo 'restore of' 'cvt.c,v' 'failed' shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'cvt.c,v'`" test 3841 -eq "$shar_count" || $echo 'cvt.c,v:' 'original size' '3841,' 'current size' "$shar_count!" # ============= ecvt.3 ============== $echo 'x -' extracting 'ecvt.3' '(text)' sed 's/^X//' << 'SHAR_EOF' > 'ecvt.3' && X.\" @(#)ecvt.3 6.3 (Berkeley) 5/17/89 X.\" X.TH ECVT 3 "May 17, 1989" X.AT 3 X.SH NAME Xecvt, fcvt, gcvt \- output conversion X.SH SYNOPSIS X.nf X.B char *ecvt(value, ndigit, decpt, sign) X.B double value; X.B int ndigit, *decpt, *sign; X.PP X.B char *fcvt(value, ndigit, decpt, sign) X.B double value; X.B int ndigit, *decpt, *sign; X.PP X.B char *gcvt(value, ndigit, buf) X.B double value; X.B char *buf; X.fi X.SH DESCRIPTION X.ft B XThese interfaces are obsoleted by printf(3). X.br XThey are available from liblocal. X.ft R X.PP X.I Ecvt Xconverts the X.I value Xto a null-terminated string of X.I ndigit XASCII digits and returns a pointer thereto. XThe position of the decimal point relative to the Xbeginning of the string is stored indirectly through X.IR decpt "" X(negative means to the left of the returned digits). XIf the sign of the result is negative, the word pointed to by X.IR sign "" Xis non-zero, otherwise it is zero. The low-order digit is rounded. X.PP X.IR Fcvt " is identical to " "ecvt\fR, except that the correct digit" Xhas been rounded for Fortran F-format output of the number Xof digits specified by X.IR \(*_ndigits . X.PP X.I Gcvt Xconverts the X.I value Xto a null-terminated ASCII string in X.I buf Xand returns a pointer to X.I buf. XIt attempts to produce X.I ndigit Xsignificant digits in Fortran F format if possible, otherwise E format, Xready for printing. Trailing zeros may be suppressed. X.SH "SEE ALSO" Xprintf(3) X.SH BUGS XThe return values point to static data Xwhose content is overwritten by each call. SHAR_EOF chmod 0644 'ecvt.3' || $echo 'restore of' 'ecvt.3' 'failed' shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'ecvt.3'`" test 1498 -eq "$shar_count" || $echo 'ecvt.3:' 'original size' '1498,' 'current size' "$shar_count!" # ============= gcvt.c,v ============== $echo 'x -' extracting 'gcvt.c,v' '(text)' sed 's/^X//' << 'SHAR_EOF' > 'gcvt.c,v' && Xhead 54.7; Xbranch 54.7.1; Xaccess; Xsymbols; Xlocks; strict; Xcomment @ * @; X X X54.7 Xdate 96.11.08.21.07.49; author Linux; state Exp; Xbranches X 54.7.1.1; Xnext ; X X54.7.1.1 Xdate 96.11.08.21.07.50; author bin; state Exp; Xbranches; Xnext ; X X Xdesc X@Ecvt(), Fcvt() and Gcvt() Library Routines X@ X X X54.7 Xlog X@Linux libc-5.4.7/libc/cvt X@ Xtext X@#include <stdlib.h> X X/* X * gcvt - Floating output conversion to X * minimal length string X */ X Xchar * Xgcvt(double number, size_t ndigit, char *buf) X{ X int sign, decpt; X register char *p1, *p2; X register int i; X X p1 = ecvt(number, ndigit, &decpt, &sign); X p2 = buf; X if (sign) X *p2++ = '-'; X for (i=ndigit-1; i>0 && p1[i]=='0'; i--) X ndigit--; X if ((decpt >= 0 && decpt > ndigit + 4) X || (decpt < 0 && decpt < -3)) { /* use E-style */ X decpt--; X *p2++ = *p1++; X *p2++ = '.'; X for (i=1; i<ndigit; i++) X *p2++ = *p1++; X *p2++ = 'e'; X if (decpt<0) { X decpt = -decpt; X *p2++ = '-'; X } else X *p2++ = '+'; X if (decpt/100 > 0) X *p2++ = decpt/100 + '0'; X if (decpt/10 > 0) X *p2++ = (decpt%100)/10 + '0'; X *p2++ = decpt%10 + '0'; X } else { X if (decpt<=0) { X if (*p1!='0') X *p2++ = '.'; X while (decpt<0) { X decpt++; X *p2++ = '0'; X } X } X for (i=1; i<=ndigit; i++) { X *p2++ = *p1++; X if (i==decpt) X *p2++ = '.'; X } X if (ndigit<decpt) { X while (ndigit++<decpt) X *p2++ = '0'; X *p2++ = '.'; X } X } X if (p2[-1]=='.') X p2--; X *p2 = '\0'; X return(buf); X} X@ X X X54.7.1.1 Xlog X@Port to FreeBSD X@ Xtext X@a2 2 Xchar *ecvt(double, size_t, int*, int*); X X@ SHAR_EOF chmod 0444 'gcvt.c,v' || $echo 'restore of' 'gcvt.c,v' 'failed' shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'gcvt.c,v'`" test 1517 -eq "$shar_count" || $echo 'gcvt.c,v:' 'original size' '1517,' 'current size' "$shar_count!" exit 0
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199801261702.LAA18553>
