Skip site navigation (1)Skip section navigation (2)
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>