diff --git a/NEWS b/NEWS index 1d4e483d383f..c7fa1593f4a4 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,11 @@ For full details, see the git log at: https://github.com/ksh93/ksh Any uppercase BUG_* names are modernish shell bug IDs. +2020-09-14: + +- Corrected rounding of floating point values by ksh's printf %f formatting + operator. Fix contributed by @hyenias. + 2020-09-11: - The 'command' regular builtin utility (which runs a simple command, removing diff --git a/src/cmd/ksh93/include/version.h b/src/cmd/ksh93/include/version.h index 6e32d374dd55..c1fbc0bfca32 100644 --- a/src/cmd/ksh93/include/version.h +++ b/src/cmd/ksh93/include/version.h @@ -17,4 +17,4 @@ * David Korn * * * ***********************************************************************/ -#define SH_RELEASE "93u+m 2020-09-11" +#define SH_RELEASE "93u+m 2020-09-14" diff --git a/src/cmd/ksh93/tests/math.sh b/src/cmd/ksh93/tests/math.sh index d29d6d6a63a3..5901524039bf 100755 --- a/src/cmd/ksh93/tests/math.sh +++ b/src/cmd/ksh93/tests/math.sh @@ -193,4 +193,48 @@ function test_has_iszero test_arithmetric_expression_accesss_array_element_through_nameref test_has_iszero +# ====== +# Validate that typeset -E/F formatting matches that of their equivalent +# printf formatting options as well as checking for correct float scaling +# of the fractional parts. + +unset i tf pf; typeset -F 3 tf +for i in {'','-'}{0..1}.{0,9}{0,9}{0,1,9}{0,1,9} +do tf=$i + pf=${ printf '%.3f' tf ;} + if [[ $tf != "$pf" ]] + then err_exit "typeset -F formatted data does not match its printf. typeset -F 3: $tf != $pf" + break + fi +done +unset i tf pf; typeset -lF 3 tf +for i in {'','-'}{0..1}.{0,9}{0,9}{0,1,9}{0,1,9} +do tf=$i + pf=${ printf '%.3Lf' tf ;} + if [[ $tf != "$pf" ]] + then err_exit "typeset -lF formatted data does not match its printf. typeset -lF 3: $tf != $pf" + break + fi +done +unset i tf pf; typeset -E 3 tf +for i in {'','-'}{0..1}.{0,9}{0,9}{0,1,9}{0,1,9} +do tf=$i + pf=${ printf '%.3g' tf ;} + if [[ $tf != "$pf" ]] + then err_exit "typeset -E formatted data does not match its printf. typeset -E 3: $tf != $pf" + break + fi +done +unset i tf pf; typeset -lE 3 tf +for i in {'','-'}{0..1}.{0,9}{0,9}{0,1,9}{0,1,9} +do tf=$i + pf=${ printf '%.3Lg' tf ;} + if [[ $tf != "$pf" ]] + then err_exit "typeset -lE formatted data does not match its printf. typeset -lE 3: $tf != $pf" + break + fi +done +unset i tf pf + +# ====== exit $((Errors<125?Errors:125)) diff --git a/src/lib/libast/sfio/sfcvt.c b/src/lib/libast/sfio/sfcvt.c index 7da1dcffb3f3..a83b8ef89b6f 100644 --- a/src/lib/libast/sfio/sfcvt.c +++ b/src/lib/libast/sfio/sfcvt.c @@ -287,7 +287,7 @@ int format; /* conversion format */ while(sp < ep) { /* generate fractional digits */ - if(f <= 0.) + if(f <= 0. && *decpt >= 0) { /* fill with 0's */ do { *sp++ = '0'; } while(sp < ep); goto done; @@ -404,7 +404,7 @@ int format; /* conversion format */ } } while(f >= (double)CVT_DBL_MAXINT); } - else if(f > 0.0 && f < 1e-8) + else if(f > 0.0 && f < 0.1) { /* scale to avoid excessive multiply by 10 below */ v = SF_MAXEXP10-1; do @@ -459,7 +459,7 @@ int format; /* conversion format */ while(sp < ep) { /* generate fractional digits */ - if(f <= 0.) + if(f <= 0. && *decpt >= 0) { /* fill with 0's */ do { *sp++ = '0'; } while(sp < ep); goto done; @@ -480,20 +480,29 @@ int format; /* conversion format */ ep = b+1; else if(ep < endsp) { /* round the last digit */ - *--sp += 5; + if (!(format&SFFMT_EFORMAT) && *decpt < 0) + sp += *decpt-1; + else + --sp; + *sp += 5; while(*sp > '9') - { *sp = '0'; - if(sp > b) + { if(sp > b) + { *sp = '0'; *--sp += 1; + } else - { /* next power of 10 */ + { /* next power of 10 and at beginning */ *sp = '1'; *decpt += 1; if(!(format&SFFMT_EFORMAT)) { /* add one more 0 for %f precision */ - ep[-1] = '0'; + if (sp != &ep[-1]) + { /* prevents overwriting the previous 1 with 0 */ + ep[-1] = '0'; + } ep += 1; } + break; } } }