diff --git a/CHANGES b/CHANGES index ca7a040..7888bbf 100644 --- a/CHANGES +++ b/CHANGES @@ -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, 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: diff --git a/cal/regress.cal b/cal/regress.cal index f67eeda..8d4e6ed 100644 --- a/cal/regress.cal +++ b/cal/regress.cal @@ -4106,38 +4106,46 @@ define test_strprintf() '4821: strprintf("%b", 27/29) == "0b11011/0b11101"'); vrfy(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 */ c = config("tilde", 0); - print '4823: c = config("tilde", 0)'; + print '4825: c = config("tilde", 0)'; vrfy(strprintf("%e", 12345) == "1.23e4", - '4824: strprintf("%e", 12345) == "1.23e4"'); + '4826: strprintf("%e", 12345) == "1.23e4"'); 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", - '4826: strprintf("%e", .00012345) == "1.23e-4"'); + '4828: strprintf("%e", .00012345) == "1.23e-4"'); vrfy(strprintf("%d %d", 27) == "27 ", - '4827: strprintf("%d %d", 27) == "27 "'); + '4829: strprintf("%d %d", 27) == "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", - '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", - '4830: strprintf("%s", "abc") == "abc"'); + '4832: strprintf("%s", "abc") == "abc"'); vrfy(strprintf("%f", "abc") == "abc", - '4831: strprintf("%f", "abc") == "abc"'); + '4833: strprintf("%f", "abc") == "abc"'); vrfy(strprintf("%e", "abc") == "abc", - '4832: strprintf("%e", "abc") == "abc"'); + '4834: strprintf("%e", "abc") == "abc"'); vrfy(strprintf("%5s", "abc") == " abc", - '4833: strprintf("%5s", "abc") == " abc"'); + '4835: 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 */ 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()'; diff --git a/help/printf b/help/printf index fa53958..b8b2115 100644 --- a/help/printf +++ b/help/printf @@ -28,7 +28,7 @@ DESCRIPTION zero or more decimal digits an optional '. followed by zero or more decimal deigits 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 between '%' and the character are ignored and no specifier is @@ -51,26 +51,27 @@ DESCRIPTION d, s, c current config("mode") f real (decimal, floating point) e exponential + g real or exponential depending on config("display") r fractional o octal x hexadecimal b binary - If the number of arguments after fmt is less than the - number of format specifiers in fmt, the "missing" arguments - may be taken to be null values - these contribute nothing to the - output; if a positive width w has been specified, the effect is - to produce w spaces, e.g. printf("abc%6dxyz") prints "abc xyz". + If the number of arguments after fmt is less than the number + of format specifiers in fmt, the "missing" arguments may be + taken to be null values - these contribute nothing to the output; + if a positive width w has been specified, the effect is to + 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 - 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 - does not include a '\n' character, what is printed will if necessary - be padded with spaces so that the length of the printed output - is at least the w. Note that control - characters like '\t', '\b' each count as one character. If - the 'right-pad' flag has been set, the padding is on the right; - otherwise it is on the left. + If i <= the number of specifiers in fmt, the value of argument + 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 does not include a '\n' character, what is printed will + if necessary be padded with spaces so that the length of the + printed output is at least the w. Note that control characters + like '\t', '\b' each count as one character. If the 'right-pad' + flag has been set, the padding is on the right; otherwise it + is on the left. If i > the number of specifiers in fmt, the value of argument x_i does not contribute to the printing. However, as all arguments @@ -84,9 +85,9 @@ DESCRIPTION mode. In the case of floating-point (f) format the precision determines - the maximum number of decimal places to be - displayed. Other aspects of this printing may be affected by the - configuration parameters "outround", "tilde", "fullzero", "leadzero". + the maximum number of decimal places to be displayed. Other + aspects of this printing may be affected by the configuration + parameters "outround", "tilde", "fullzero", "leadzero". EXAMPLE ; c = config("epsilon", 1e-6); c = config("display", 6); @@ -116,6 +117,11 @@ EXAMPLE [2] = "undefined" [3] = NULL + ; c = config("display", 50); + ; printf("%g %g\n%g %g\n", 1e5, 1e49, 1e50, 1e500); + 100000 100000000000000000000000000000000000000000000000000 + 1e50 1e500 + LIMITS The number of arguments of printf() is not to exceed 1024. @@ -126,7 +132,7 @@ LINK LIBRARY SEE ALSO 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 ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/help/strprintf b/help/strprintf index c4c0868..802a762 100644 --- a/help/strprintf +++ b/help/strprintf @@ -27,6 +27,13 @@ EXAMPLE "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 The number of arguments of strprintf() is not to exceed 1024. @@ -39,7 +46,7 @@ SEE ALSO 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 ## the terms of the version 2.1 of the GNU Lesser General Public License diff --git a/qio.c b/qio.c index 5884f0f..478eb47 100644 --- a/qio.c +++ b/qio.c @@ -97,6 +97,15 @@ qprintf(char *fmt, ...) q = va_arg(ap, NUMBER *); qprintfe(q, width, precision); 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': q = va_arg(ap, NUMBER *); @@ -235,18 +244,23 @@ qprintnum(NUMBER *q, int outmode) 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; tmpval = *q; tmpval.num.sign = 0; exp = qilog10(&tmpval); const long olddigits = conf->outdigits; - if(P > exp && exp >= -4) - { + if (P > exp && exp >= -P) { conf->outdigits = P - 1 - exp; qprintnum(q, MODE_REAL); - } - else - { + } else { conf->outdigits = P - 1; qprintnum(q, MODE_EXP); } diff --git a/zmath.h b/zmath.h index 881abe7..475c956 100644 --- a/zmath.h +++ b/zmath.h @@ -583,7 +583,12 @@ E_FUNC void zredcpower(REDC *rp, ZVALUE z1, ZVALUE z2, ZVALUE *res); #define MODE_MAX 8 #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 +#else +#define MODE_INITIAL MODE_REAL +#endif #define MODE2_INITIAL MODE2_OFF