Improvements to %g pull request

This code %g is preliminary.

Fixed some code style issues to match the current code style.

Added regression tests and help file updates to printf and strprintf.

Fixed use of magic number -4: using -P instead.

Noted two problem areas with XXX comments in qio.c:

    1) need a qprintfg function
    2) re-write to not modify conf->outdigits
This commit is contained in:
Landon Curt Noll
2018-09-30 16:06:28 -07:00
parent fcfe237375
commit da6ccc146f
6 changed files with 82 additions and 39 deletions

View File

@@ -17,6 +17,9 @@ The following are the changes from calc version 2.12.6.9 to date:
Added regression tests 3729 thru 3732 to test E_TAN3, E_COT3, Added regression tests 3729 thru 3732 to test E_TAN3, E_COT3,
E_SEC3 and E_CSC3 respectively. E_SEC3 and E_CSC3 respectively.
Added experimential %g printf (and strprintf) format implementation
based on pull request from github user 10110111.
The following are the changes from calc version 2.12.6.6 to 2.12.6.8: The following are the changes from calc version 2.12.6.6 to 2.12.6.8:

View File

@@ -4106,38 +4106,46 @@ define test_strprintf()
'4821: strprintf("%b", 27/29) == "0b11011/0b11101"'); '4821: strprintf("%b", 27/29) == "0b11011/0b11101"');
vrfy(strprintf("%e", 12345) == "~1.23e4", vrfy(strprintf("%e", 12345) == "~1.23e4",
'4822: strprintf("%e", 12345) == "~1.23e4"'); '4822: strprintf("%e", 12345) == "~1.23e4"');
vrfy(strprintf("%g", .385) == "~.38",
'4823: strprintf("%g", .385) == "~.38"');
vrfy(strprintf("%g", 385) == "~3.8e2",
'4824: strprintf("%g", 385) == "~3.8e2"');
/* mode tests with tilde == 0 */ /* mode tests with tilde == 0 */
c = config("tilde", 0); c = config("tilde", 0);
print '4823: c = config("tilde", 0)'; print '4825: c = config("tilde", 0)';
vrfy(strprintf("%e", 12345) == "1.23e4", vrfy(strprintf("%e", 12345) == "1.23e4",
'4824: strprintf("%e", 12345) == "1.23e4"'); '4826: strprintf("%e", 12345) == "1.23e4"');
vrfy(strprintf("%.3e", 12345) == "1.234e4", vrfy(strprintf("%.3e", 12345) == "1.234e4",
'4825: strprintf("%.3e", 12345) == "1.234e4"'); '4827: strprintf("%.3e", 12345) == "1.234e4"');
vrfy(strprintf("%e", .00012345) == "1.23e-4", vrfy(strprintf("%e", .00012345) == "1.23e-4",
'4826: strprintf("%e", .00012345) == "1.23e-4"'); '4828: strprintf("%e", .00012345) == "1.23e-4"');
vrfy(strprintf("%d %d", 27) == "27 ", vrfy(strprintf("%d %d", 27) == "27 ",
'4827: strprintf("%d %d", 27) == "27 "'); '4829: strprintf("%d %d", 27) == "27 "');
vrfy(strprintf("%d", 27, 29) == "27", vrfy(strprintf("%d", 27, 29) == "27",
'4828: strprintf("%d", 27, 29) == "27"'); '4830: strprintf("%d", 27, 29) == "27"');
vrfy(strprintf("%r = %f", 27/29, 27/29) == "27/29 = .93", vrfy(strprintf("%r = %f", 27/29, 27/29) == "27/29 = .93",
'4829: strprintf("%r = %f", 27/29, 27/29) == "27/29 = .93"'); '4831: strprintf("%r = %f", 27/29, 27/29) == "27/29 = .93"');
vrfy(strprintf("%s", "abc") == "abc", vrfy(strprintf("%s", "abc") == "abc",
'4830: strprintf("%s", "abc") == "abc"'); '4832: strprintf("%s", "abc") == "abc"');
vrfy(strprintf("%f", "abc") == "abc", vrfy(strprintf("%f", "abc") == "abc",
'4831: strprintf("%f", "abc") == "abc"'); '4833: strprintf("%f", "abc") == "abc"');
vrfy(strprintf("%e", "abc") == "abc", vrfy(strprintf("%e", "abc") == "abc",
'4832: strprintf("%e", "abc") == "abc"'); '4834: strprintf("%e", "abc") == "abc"');
vrfy(strprintf("%5s", "abc") == " abc", vrfy(strprintf("%5s", "abc") == " abc",
'4833: strprintf("%5s", "abc") == " abc"'); '4835: strprintf("%5s", "abc") == " abc"');
vrfy(strprintf("%-5s", "abc") == "abc ", vrfy(strprintf("%-5s", "abc") == "abc ",
'4834: strprintf("%-5s", "abc") == "abc "'); '4836: strprintf("%-5s", "abc") == "abc "');
vrfy(strprintf("%g", .385) == ".38",
'4837: strprintf("%g", .385) == ".38"');
vrfy(strprintf("%g", 385) == "3.8e2",
'4838: strprintf("%g", 385) == "3.8e2"');
/* restore config */ /* restore config */
c = config("all", callcfg); c = config("all", callcfg);
print '4835: c = config("all", callcfg)'; print '4839: c = config("all", callcfg)';
print '4836: Ending test_strprintf'; print '4840: Ending test_strprintf';
} }
print '088: parsed test_fileop()'; print '088: parsed test_fileop()';

View File

@@ -28,7 +28,7 @@ DESCRIPTION
zero or more decimal digits zero or more decimal digits
an optional '. followed by zero or more decimal deigits an optional '. followed by zero or more decimal deigits
an optional 'l' an optional 'l'
one of the letters: d, s, c, f, e, r, o, x, b, one of the letters: d, s, c, f, e, g, r, o, x, b,
If any other character is read, the '%' and any characters If any other character is read, the '%' and any characters
between '%' and the character are ignored and no specifier is between '%' and the character are ignored and no specifier is
@@ -51,26 +51,27 @@ DESCRIPTION
d, s, c current config("mode") d, s, c current config("mode")
f real (decimal, floating point) f real (decimal, floating point)
e exponential e exponential
g real or exponential depending on config("display")
r fractional r fractional
o octal o octal
x hexadecimal x hexadecimal
b binary b binary
If the number of arguments after fmt is less than the If the number of arguments after fmt is less than the number
number of format specifiers in fmt, the "missing" arguments of format specifiers in fmt, the "missing" arguments may be
may be taken to be null values - these contribute nothing to the taken to be null values - these contribute nothing to the output;
output; if a positive width w has been specified, the effect is if a positive width w has been specified, the effect is to
to produce w spaces, e.g. printf("abc%6dxyz") prints "abc xyz". produce w spaces, e.g., printf("abc%6dxyz") prints "abc xyz".
If i <= the number of specifiers in fmt, the value of argument x_i If i <= the number of specifiers in fmt, the value of argument
is printed in the format specified by the i-th specifier. x_i is printed in the format specified by the i-th specifier.
If a positive width w has been specified and normal printing of x_i If a positive width w has been specified and normal printing
does not include a '\n' character, what is printed will if necessary of x_i does not include a '\n' character, what is printed will
be padded with spaces so that the length of the printed output if necessary be padded with spaces so that the length of the
is at least the w. Note that control printed output is at least the w. Note that control characters
characters like '\t', '\b' each count as one character. If like '\t', '\b' each count as one character. If the 'right-pad'
the 'right-pad' flag has been set, the padding is on the right; flag has been set, the padding is on the right; otherwise it
otherwise it is on the left. is on the left.
If i > the number of specifiers in fmt, the value of argument x_i If i > the number of specifiers in fmt, the value of argument x_i
does not contribute to the printing. However, as all arguments does not contribute to the printing. However, as all arguments
@@ -84,9 +85,9 @@ DESCRIPTION
mode. mode.
In the case of floating-point (f) format the precision determines In the case of floating-point (f) format the precision determines
the maximum number of decimal places to be the maximum number of decimal places to be displayed. Other
displayed. Other aspects of this printing may be affected by the aspects of this printing may be affected by the configuration
configuration parameters "outround", "tilde", "fullzero", "leadzero". parameters "outround", "tilde", "fullzero", "leadzero".
EXAMPLE EXAMPLE
; c = config("epsilon", 1e-6); c = config("display", 6); ; c = config("epsilon", 1e-6); c = config("display", 6);
@@ -116,6 +117,11 @@ EXAMPLE
[2] = "undefined" [2] = "undefined"
[3] = NULL [3] = NULL
; c = config("display", 50);
; printf("%g %g\n%g %g\n", 1e5, 1e49, 1e50, 1e500);
100000 100000000000000000000000000000000000000000000000000
1e50 1e500
LIMITS LIMITS
The number of arguments of printf() is not to exceed 1024. The number of arguments of printf() is not to exceed 1024.
@@ -126,7 +132,7 @@ LINK LIBRARY
SEE ALSO SEE ALSO
fprintf, strprintf, print fprintf, strprintf, print
## Copyright (C) 1999-2006 Landon Curt Noll ## Copyright (C) 1999-2006,2018 Landon Curt Noll
## ##
## Calc is open software; you can redistribute it and/or modify it under ## Calc is open software; you can redistribute it and/or modify it under
## the terms of the version 2.1 of the GNU Lesser General Public License ## the terms of the version 2.1 of the GNU Lesser General Public License

View File

@@ -27,6 +27,13 @@ EXAMPLE
"1.732051, 1.732051,1.732051 , ~1.7320,~1.7320,~1. "1.732051, 1.732051,1.732051 , ~1.7320,~1.7320,~1.
" "
; c = config("display", 50);
; fmt2 = "%g %g\n%g %g\n"
; strprintf(fmt2, 1e5, 1e49, 1e50, 1e500);
"100000 100000000000000000000000000000000000000000000000000
1e50 1e500
"
LIMITS LIMITS
The number of arguments of strprintf() is not to exceed 1024. The number of arguments of strprintf() is not to exceed 1024.
@@ -39,7 +46,7 @@ SEE ALSO
printf, fprintf, print printf, fprintf, print
## Copyright (C) 1999-2006 Landon Curt Noll ## Copyright (C) 1999-2006,2018 Landon Curt Noll
## ##
## Calc is open software; you can redistribute it and/or modify it under ## Calc is open software; you can redistribute it and/or modify it under
## the terms of the version 2.1 of the GNU Lesser General Public License ## the terms of the version 2.1 of the GNU Lesser General Public License

24
qio.c
View File

@@ -97,6 +97,15 @@ qprintf(char *fmt, ...)
q = va_arg(ap, NUMBER *); q = va_arg(ap, NUMBER *);
qprintfe(q, width, precision); qprintfe(q, width, precision);
break; break;
case 'g':
q = va_arg(ap, NUMBER *);
/* XXX - we need a qprintfg function */
#if 0 /* XXX - we need a qprintfg() function */
qprintfg(q, width, precision);
#else /* XXX - use qprintfe until we have a qprintfg() function */
qprintfe(q, width, precision);
#endif /* XXX - we need a qprintfg() function */
break;
case 'r': case 'r':
case 'R': case 'R':
q = va_arg(ap, NUMBER *); q = va_arg(ap, NUMBER *);
@@ -235,18 +244,23 @@ qprintnum(NUMBER *q, int outmode)
case MODE_REAL_AUTO: case MODE_REAL_AUTO:
{ {
/*
* XXX - re-write to not modify conf->outdigits
*
* Modifying the configuration value could be dangerious
* when a calculation is aborted within an opcode.
* Better to use qprintfg() use inline code that
* does not depend on changing conf->outdigits.
*/
const int P = conf->outdigits ? conf->outdigits : 1; const int P = conf->outdigits ? conf->outdigits : 1;
tmpval = *q; tmpval = *q;
tmpval.num.sign = 0; tmpval.num.sign = 0;
exp = qilog10(&tmpval); exp = qilog10(&tmpval);
const long olddigits = conf->outdigits; const long olddigits = conf->outdigits;
if(P > exp && exp >= -4) if (P > exp && exp >= -P) {
{
conf->outdigits = P - 1 - exp; conf->outdigits = P - 1 - exp;
qprintnum(q, MODE_REAL); qprintnum(q, MODE_REAL);
} } else {
else
{
conf->outdigits = P - 1; conf->outdigits = P - 1;
qprintnum(q, MODE_EXP); qprintnum(q, MODE_EXP);
} }

View File

@@ -583,7 +583,12 @@ E_FUNC void zredcpower(REDC *rp, ZVALUE z1, ZVALUE z2, ZVALUE *res);
#define MODE_MAX 8 #define MODE_MAX 8
#define MODE2_OFF (MODE_MAX+1) #define MODE2_OFF (MODE_MAX+1)
/* XXX - perhaps we need the MODE_REAL_AUTO vs MODE_REAL as a config mode? */
#if 0 /* XXX - can we safely set MODE_INITIAL to MODE_REAL_AUTO ?? */
#define MODE_INITIAL MODE_REAL_AUTO #define MODE_INITIAL MODE_REAL_AUTO
#else
#define MODE_INITIAL MODE_REAL
#endif
#define MODE2_INITIAL MODE2_OFF #define MODE2_INITIAL MODE2_OFF