1989-05-30 13:34:25 +00:00
|
|
|
/*
|
1991-06-10 17:07:18 +00:00
|
|
|
* fltpr.c - print floating point numbers
|
1989-05-30 13:34:25 +00:00
|
|
|
*/
|
1994-06-24 14:02:31 +00:00
|
|
|
/* $Id$ */
|
1989-05-30 13:34:25 +00:00
|
|
|
|
2018-06-21 20:33:47 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <stdarg.h>
|
2019-06-15 11:53:20 +00:00
|
|
|
#include "doprnt.h"
|
1989-05-30 13:34:25 +00:00
|
|
|
|
2018-06-23 16:54:40 +00:00
|
|
|
#if ACKCONF_WANT_STDIO && ACKCONF_WANT_STDIO_FLOAT
|
2007-04-27 22:41:39 +00:00
|
|
|
|
2018-06-21 20:33:47 +00:00
|
|
|
static char*
|
|
|
|
_pfloat(long double r, register char* s, int n, int flags)
|
1989-05-30 13:34:25 +00:00
|
|
|
{
|
2018-06-21 20:33:47 +00:00
|
|
|
register char* s1;
|
1989-05-30 13:34:25 +00:00
|
|
|
int sign, dp;
|
|
|
|
register int i;
|
|
|
|
|
1990-02-27 16:48:01 +00:00
|
|
|
s1 = _fcvt(r, n, &dp, &sign);
|
1989-05-30 13:34:25 +00:00
|
|
|
if (sign)
|
|
|
|
*s++ = '-';
|
|
|
|
else if (flags & FL_SIGN)
|
|
|
|
*s++ = '+';
|
|
|
|
else if (flags & FL_SPACE)
|
|
|
|
*s++ = ' ';
|
|
|
|
|
2018-06-21 20:33:47 +00:00
|
|
|
if (dp <= 0)
|
1989-05-30 13:34:25 +00:00
|
|
|
*s++ = '0';
|
2018-06-21 20:33:47 +00:00
|
|
|
for (i = dp; i > 0; i--)
|
|
|
|
if (*s1)
|
|
|
|
*s++ = *s1++;
|
|
|
|
else
|
|
|
|
*s++ = '0';
|
|
|
|
if (((i = n) > 0) || (flags & FL_ALT))
|
1989-05-30 13:34:25 +00:00
|
|
|
*s++ = '.';
|
2018-06-21 20:33:47 +00:00
|
|
|
while (++dp <= 0)
|
|
|
|
{
|
|
|
|
if (--i < 0)
|
1989-05-30 13:34:25 +00:00
|
|
|
break;
|
|
|
|
*s++ = '0';
|
|
|
|
}
|
|
|
|
while (--i >= 0)
|
2018-06-21 20:33:47 +00:00
|
|
|
if (*s1)
|
|
|
|
*s++ = *s1++;
|
|
|
|
else
|
|
|
|
*s++ = '0';
|
1989-06-26 10:37:05 +00:00
|
|
|
return s;
|
1989-05-30 13:34:25 +00:00
|
|
|
}
|
|
|
|
|
2018-06-21 20:33:47 +00:00
|
|
|
static char*
|
|
|
|
_pscien(long double r, register char* s, int n, int flags)
|
1989-05-30 13:34:25 +00:00
|
|
|
{
|
2018-06-21 20:33:47 +00:00
|
|
|
int sign, dp;
|
|
|
|
register char* s1;
|
1989-05-30 13:34:25 +00:00
|
|
|
|
1990-02-27 16:48:01 +00:00
|
|
|
s1 = _ecvt(r, n + 1, &dp, &sign);
|
1989-05-30 13:34:25 +00:00
|
|
|
if (sign)
|
|
|
|
*s++ = '-';
|
|
|
|
else if (flags & FL_SIGN)
|
|
|
|
*s++ = '+';
|
|
|
|
else if (flags & FL_SPACE)
|
|
|
|
*s++ = ' ';
|
|
|
|
|
|
|
|
*s++ = *s1++;
|
|
|
|
if ((n > 0) || (flags & FL_ALT))
|
|
|
|
*s++ = '.';
|
1989-12-18 15:04:14 +00:00
|
|
|
while (--n >= 0)
|
2018-06-21 20:33:47 +00:00
|
|
|
if (*s1)
|
|
|
|
*s++ = *s1++;
|
|
|
|
else
|
|
|
|
*s++ = '0';
|
1989-05-30 13:34:25 +00:00
|
|
|
*s++ = 'e';
|
2018-06-21 20:33:47 +00:00
|
|
|
if (r != 0)
|
|
|
|
--dp;
|
|
|
|
if (dp < 0)
|
|
|
|
{
|
|
|
|
*s++ = '-';
|
|
|
|
dp = -dp;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*s++ = '+';
|
1989-05-30 13:34:25 +00:00
|
|
|
}
|
2018-06-21 20:33:47 +00:00
|
|
|
if (dp >= 100)
|
|
|
|
{
|
1989-05-30 13:34:25 +00:00
|
|
|
*s++ = '0' + (dp / 100);
|
|
|
|
dp %= 100;
|
|
|
|
}
|
2018-06-21 20:33:47 +00:00
|
|
|
*s++ = '0' + (dp / 10);
|
|
|
|
*s++ = '0' + (dp % 10);
|
1989-06-26 10:37:05 +00:00
|
|
|
return s;
|
1989-05-30 13:34:25 +00:00
|
|
|
}
|
1991-06-10 17:07:18 +00:00
|
|
|
|
2018-06-21 20:33:47 +00:00
|
|
|
#define NDIGINEXP(exp) (((exp) >= 100 || (exp) <= -100) ? 3 : 2)
|
|
|
|
#define LOW_EXP -4
|
|
|
|
#define USE_EXP(exp, ndigits) (((exp) < LOW_EXP + 1) || (exp >= ndigits + 1))
|
1991-06-10 17:07:18 +00:00
|
|
|
|
2018-06-21 20:33:47 +00:00
|
|
|
static char*
|
|
|
|
_gcvt(long double value, int ndigit, char* s, int flags)
|
1991-06-10 17:07:18 +00:00
|
|
|
{
|
|
|
|
int sign, dp;
|
|
|
|
register char *s1, *s2;
|
|
|
|
register int i;
|
|
|
|
register int nndigit = ndigit;
|
|
|
|
|
|
|
|
s1 = _ecvt(value, ndigit, &dp, &sign);
|
|
|
|
s2 = s;
|
2018-06-21 20:33:47 +00:00
|
|
|
if (sign)
|
|
|
|
*s2++ = '-';
|
1991-06-10 17:07:18 +00:00
|
|
|
else if (flags & FL_SIGN)
|
|
|
|
*s2++ = '+';
|
|
|
|
else if (flags & FL_SPACE)
|
|
|
|
*s2++ = ' ';
|
|
|
|
|
|
|
|
if (!(flags & FL_ALT))
|
|
|
|
for (i = nndigit - 1; i > 0 && s1[i] == '0'; i--)
|
|
|
|
nndigit--;
|
|
|
|
|
2018-06-21 20:33:47 +00:00
|
|
|
if (USE_EXP(dp, ndigit))
|
|
|
|
{
|
1991-06-10 17:07:18 +00:00
|
|
|
/* Use E format */
|
|
|
|
dp--;
|
|
|
|
*s2++ = *s1++;
|
2018-06-21 20:33:47 +00:00
|
|
|
if ((nndigit > 1) || (flags & FL_ALT))
|
|
|
|
*s2++ = '.';
|
|
|
|
while (--nndigit > 0)
|
|
|
|
*s2++ = *s1++;
|
1991-06-10 17:07:18 +00:00
|
|
|
*s2++ = 'e';
|
2018-06-21 20:33:47 +00:00
|
|
|
if (dp < 0)
|
|
|
|
{
|
1991-06-10 17:07:18 +00:00
|
|
|
*s2++ = '-';
|
|
|
|
dp = -dp;
|
|
|
|
}
|
2018-06-21 20:33:47 +00:00
|
|
|
else
|
|
|
|
*s2++ = '+';
|
1991-06-10 17:07:18 +00:00
|
|
|
s2 += NDIGINEXP(dp);
|
|
|
|
*s2 = 0;
|
2018-06-21 20:33:47 +00:00
|
|
|
for (i = NDIGINEXP(dp); i > 0; i--)
|
|
|
|
{
|
1991-06-10 17:07:18 +00:00
|
|
|
*--s2 = dp % 10 + '0';
|
|
|
|
dp /= 10;
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
/* Use f format */
|
2018-06-21 20:33:47 +00:00
|
|
|
if (dp <= 0)
|
|
|
|
{
|
|
|
|
if (*s1 != '0')
|
|
|
|
{
|
1991-06-10 17:07:18 +00:00
|
|
|
/* otherwise the whole number is 0 */
|
|
|
|
*s2++ = '0';
|
|
|
|
*s2++ = '.';
|
|
|
|
}
|
2018-06-21 20:33:47 +00:00
|
|
|
while (dp < 0)
|
|
|
|
{
|
1991-06-10 17:07:18 +00:00
|
|
|
dp++;
|
|
|
|
*s2++ = '0';
|
|
|
|
}
|
|
|
|
}
|
2018-06-21 20:33:47 +00:00
|
|
|
for (i = 1; i <= nndigit; i++)
|
|
|
|
{
|
1991-06-10 17:07:18 +00:00
|
|
|
*s2++ = *s1++;
|
2018-06-21 20:33:47 +00:00
|
|
|
if (i == dp)
|
|
|
|
*s2++ = '.';
|
1991-06-10 17:07:18 +00:00
|
|
|
}
|
2018-06-21 20:33:47 +00:00
|
|
|
if (i <= dp)
|
|
|
|
{
|
|
|
|
while (i++ <= dp)
|
|
|
|
*s2++ = '0';
|
1991-06-10 17:07:18 +00:00
|
|
|
*s2++ = '.';
|
|
|
|
}
|
2018-06-21 20:33:47 +00:00
|
|
|
if ((s2[-1] == '.') && !(flags & FL_ALT))
|
|
|
|
s2--;
|
1991-06-10 17:07:18 +00:00
|
|
|
*s2 = '\0';
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2018-06-21 20:33:47 +00:00
|
|
|
char* _f_print(va_list* ap, int flags, char* s, char c, int precision)
|
1991-06-10 17:07:18 +00:00
|
|
|
{
|
2018-06-21 20:33:47 +00:00
|
|
|
register char* old_s = s;
|
1991-06-10 17:07:18 +00:00
|
|
|
long double ld_val;
|
|
|
|
|
2018-06-21 20:33:47 +00:00
|
|
|
if (flags & FL_LONGDOUBLE)
|
|
|
|
ld_val = va_arg(*ap, long double);
|
|
|
|
else
|
|
|
|
ld_val = (long double)va_arg(*ap, double);
|
|
|
|
|
|
|
|
switch (c)
|
|
|
|
{
|
|
|
|
case 'f':
|
|
|
|
s = _pfloat(ld_val, s, precision, flags);
|
|
|
|
break;
|
|
|
|
case 'e':
|
|
|
|
case 'E':
|
|
|
|
s = _pscien(ld_val, s, precision, flags);
|
|
|
|
break;
|
|
|
|
case 'g':
|
|
|
|
case 'G':
|
|
|
|
s = _gcvt(ld_val, precision, s, flags);
|
|
|
|
s += strlen(s);
|
|
|
|
break;
|
1991-06-10 17:07:18 +00:00
|
|
|
}
|
2018-06-21 20:33:47 +00:00
|
|
|
if (c == 'E' || c == 'G')
|
|
|
|
{
|
|
|
|
while (*old_s && *old_s != 'e')
|
|
|
|
old_s++;
|
|
|
|
if (*old_s == 'e')
|
|
|
|
*old_s = 'E';
|
1991-06-10 17:07:18 +00:00
|
|
|
}
|
|
|
|
return s;
|
|
|
|
}
|
2018-06-22 22:04:14 +00:00
|
|
|
#endif
|