mirror of
https://github.com/GnoConsortium/gno.git
synced 2024-12-22 14:30:29 +00:00
04ed2e0e19
Fix for PR#56 -- there is a kludge to modify the exponent for a converted value of zero, due to the way that SANE special- cases it. This kludge was applied for all values that had a zero exponent; now do it only for the value zero.
153 lines
3.6 KiB
C
153 lines
3.6 KiB
C
/*
|
|
* Floating point conversion routines.
|
|
* Devin Reade, 1997.
|
|
*
|
|
* $Id: cvt.c,v 1.4 1998/03/28 16:42:32 gdr-ftp Exp $
|
|
*
|
|
* This file is formatted with tab stops every 8 columns.
|
|
*/
|
|
|
|
#ifdef __ORCAC__
|
|
segment "libc_stdlb";
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sane.h>
|
|
#include <math.h>
|
|
|
|
static char *
|
|
_cvt (double number, size_t ndigits, int *decpt, int *sign, short style)
|
|
{
|
|
static DecForm convert;
|
|
static Decimal d;
|
|
int i;
|
|
char *p;
|
|
|
|
convert.style = style;
|
|
if (ndigits > SIGDIGLEN) {
|
|
ndigits = SIGDIGLEN;
|
|
}
|
|
if (!number) {
|
|
/*
|
|
* special case zero, for which SANE doesn't give the
|
|
* documented format.
|
|
*/
|
|
p = d.sig.text;
|
|
for (i=0; i<ndigits; i++) {
|
|
*p++ = '0';
|
|
}
|
|
*p = '\0';
|
|
*decpt = *sign = 0;
|
|
return d.sig.text;
|
|
}
|
|
convert.digits = ndigits;
|
|
s_num2dec(&convert, number, &d);
|
|
*decpt = (int)d.sig.length + d.exp;
|
|
*sign = d.sgn;
|
|
*(d.sig.text + (int)d.sig.length) = '\0'; /* depends on d.sig.unused */
|
|
return d.sig.text;
|
|
}
|
|
|
|
char *
|
|
ecvt (double number, size_t ndigits, int *decpt, int *sign) {
|
|
return _cvt (number, ndigits, decpt, sign, FLOATDECIMAL);
|
|
}
|
|
|
|
char *
|
|
fcvt (double number, size_t ndigits, int *decpt, int *sign) {
|
|
return _cvt (number, ndigits, decpt, sign, FIXEDDECIMAL);
|
|
}
|
|
|
|
/* __dtoa: These are the comments from the BSD implementation of
|
|
this routine. Whether or not we have achieved compatibility
|
|
remains to be seen.
|
|
|
|
Arguments ndigits, decpt, sign are similar to those
|
|
of ecvt and fcvt; trailing zeros are suppressed from
|
|
the returned string. If not null, *rve is set to point
|
|
to the end of the return value. If d is +-Infinity or NaN,
|
|
then *decpt is set to 9999.
|
|
|
|
mode:
|
|
0 ==> shortest string that yields d when read in
|
|
and rounded to nearest.
|
|
1 ==> like 0, but with Steele & White stopping rule;
|
|
e.g. with IEEE P754 arithmetic , mode 0 gives
|
|
1e23 whereas mode 1 gives 9.999999999999999e22.
|
|
2 ==> max(1,ndigits) significant digits. This gives a
|
|
return value similar to that of ecvt, except
|
|
that trailing zeros are suppressed.
|
|
3 ==> through ndigits past the decimal point. This
|
|
gives a return value similar to that from fcvt,
|
|
except that trailing zeros are suppressed, and
|
|
ndigits can be negative.
|
|
4-9 should give the same return values as 2-3, i.e.,
|
|
4 <= mode <= 9 ==> same return as mode
|
|
2 + (mode & 1). These modes are mainly for
|
|
debugging; often they run slower but sometimes
|
|
faster than modes 2-3.
|
|
4,5,8,9 ==> left-to-right digit generation.
|
|
6-9 ==> don't try fast floating-point estimate
|
|
(if applicable).
|
|
|
|
Values of mode other than 0-9 are treated as mode 0.
|
|
|
|
Sufficient space is allocated to the return value
|
|
to hold the suppressed trailing zeros.
|
|
*/
|
|
|
|
#undef MAX
|
|
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
|
|
|
|
char *
|
|
__dtoa (double number, int mode, int ndigits, int *decpt, int *sign,
|
|
char **rve)
|
|
{
|
|
char *result, *p;
|
|
|
|
switch(mode) {
|
|
case 2:
|
|
case 4:
|
|
case 6:
|
|
case 8:
|
|
mode0: /* this label doesn't belong here */
|
|
result = ecvt(number, MAX(1, ndigits), decpt, sign);
|
|
break;
|
|
case 3:
|
|
case 5:
|
|
case 7:
|
|
case 9:
|
|
result = fcvt(number, ndigits, decpt, sign);
|
|
break;
|
|
|
|
case 0:
|
|
case 1:
|
|
default:
|
|
goto mode0; /* TEMP KLUDGE */
|
|
}
|
|
|
|
/* special case the exponent for 0.0 */
|
|
if (number == 0) {
|
|
*decpt = 1;
|
|
}
|
|
|
|
/* truncate trailing zeros */
|
|
if (rve != NULL) {
|
|
p = result;
|
|
while (*p) p++;
|
|
--p;
|
|
while ((p > result) && (*p == '0')) {
|
|
--p;
|
|
}
|
|
*rve = p+1;
|
|
}
|
|
|
|
/* set decimal point for NaNs and Infinities */
|
|
if (isnan(number) || isinf(number)) {
|
|
*decpt = 9999;
|
|
}
|
|
|
|
return result;
|
|
}
|