0
0
mirror of https://github.com/vim/vim.git synced 2025-09-27 04:14:06 -04:00

patch 7.4.2291

Problem:    printf() handles floats wrong when there is a sign.
Solution:   Fix placing the sign.  Add tests. (Dominique Pelle)
This commit is contained in:
Bram Moolenaar
2016-08-29 21:55:35 +02:00
parent 7f7bd297d6
commit 0418609534
4 changed files with 107 additions and 45 deletions

View File

@@ -1,4 +1,4 @@
*eval.txt* For Vim version 7.4. Last change: 2016 Aug 28 *eval.txt* For Vim version 7.4. Last change: 2016 Aug 29
VIM REFERENCE MANUAL by Bram Moolenaar VIM REFERENCE MANUAL by Bram Moolenaar
@@ -643,7 +643,7 @@ It's possible to form a variable name with curly braces, see
Expression syntax summary, from least to most significant: Expression syntax summary, from least to most significant:
|expr1| expr2 ? expr1 : expr1 if-then-else |expr1| expr2 ? expr1 : expr1 if-then-else
|expr2| expr3 || expr3 .. logical OR |expr2| expr3 || expr3 .. logical OR
@@ -736,7 +736,9 @@ use in a variable such as "a:1".
expr2 and expr3 *expr2* *expr3* expr2 and expr3 *expr2* *expr3*
--------------- ---------------
*expr-barbar* *expr-&&* expr3 || expr3 .. logical OR *expr-barbar*
expr4 && expr4 .. logical AND *expr-&&*
The "||" and "&&" operators take one argument on each side. The arguments The "||" and "&&" operators take one argument on each side. The arguments
are (converted to) Numbers. The result is: are (converted to) Numbers. The result is:
@@ -1981,7 +1983,7 @@ assert_notmatch({pat}, {text} [, {msg}]) none assert {pat} not matches {text}
assert_true({actual} [, {msg}]) none assert {actual} is true assert_true({actual} [, {msg}]) none assert {actual} is true
asin({expr}) Float arc sine of {expr} asin({expr}) Float arc sine of {expr}
atan({expr}) Float arc tangent of {expr} atan({expr}) Float arc tangent of {expr}
atan2({expr}, {expr}) Float arc tangent of {expr1} / {expr2} atan2({expr1}, {expr2}) Float arc tangent of {expr1} / {expr2}
browse({save}, {title}, {initdir}, {default}) browse({save}, {title}, {initdir}, {default})
String put up a file requester String put up a file requester
browsedir({title}, {initdir}) String put up a directory requester browsedir({title}, {initdir}) String put up a directory requester
@@ -5905,9 +5907,10 @@ printf({fmt}, {expr1} ...) *printf()*
%X hex number using upper case letters %X hex number using upper case letters
%o octal number %o octal number
%08b binary number padded with zeros to at least 8 chars %08b binary number padded with zeros to at least 8 chars
%f floating point number in the form 123.456 %f floating point number as 12.23, inf, -inf or nan
%e floating point number in the form 1.234e3 %F floating point number as 12.23, INF, -INF or NAN
%E floating point number in the form 1.234E3 %e floating point number as 1.23e3, inf, -inf or nan
%E floating point number as 1.23E3, INF, -INF or NAN
%g floating point number, as %f or %e depending on value %g floating point number, as %f or %e depending on value
%G floating point number, as %f or %E depending on value %G floating point number, as %f or %E depending on value
%% the % character itself %% the % character itself
@@ -6039,8 +6042,9 @@ printf({fmt}, {expr1} ...) *printf()*
digits after the decimal point. When the precision is digits after the decimal point. When the precision is
zero the decimal point is omitted. When the precision zero the decimal point is omitted. When the precision
is not specified 6 is used. A really big number is not specified 6 is used. A really big number
(out of range or dividing by zero) results in "inf". (out of range or dividing by zero) results in "inf"
"0.0 / 0.0" results in "nan". or "-inf" with %f (INF or -INF with %F).
"0.0 / 0.0" results in "nan" with %f (NAN with %F).
Example: > Example: >
echo printf("%.2f", 12.115) echo printf("%.2f", 12.115)
< 12.12 < 12.12
@@ -7507,7 +7511,7 @@ system({expr} [, {input}]) *system()* *E677*
Pipes are not used, the 'shelltemp' option is not used. Pipes are not used, the 'shelltemp' option is not used.
When prepended by |:silent| the shell will not be set to When prepended by |:silent| the terminal will not be set to
cooked mode. This is meant to be used for commands that do cooked mode. This is meant to be used for commands that do
not need the user to type. It avoids stray characters showing not need the user to type. It avoids stray characters showing
up on the screen which require |CTRL-L| to remove. > up on the screen which require |CTRL-L| to remove. >

View File

@@ -4030,7 +4030,7 @@ infinity_str(int positive,
* with flags: '-', '+', ' ', '0' and '#'. * with flags: '-', '+', ' ', '0' and '#'.
* An asterisk is supported for field width as well as precision. * An asterisk is supported for field width as well as precision.
* *
* Limited support for floating point was added: 'f', 'e', 'E', 'g', 'G'. * Limited support for floating point was added: 'f', 'F', 'e', 'E', 'g', 'G'.
* *
* Length modifiers 'h' (short int) and 'l' (long int) and 'll' (long long int) * Length modifiers 'h' (short int) and 'l' (long int) and 'll' (long long int)
* are supported. * are supported.
@@ -4286,7 +4286,6 @@ vim_vsnprintf(
case 'D': fmt_spec = 'd'; length_modifier = 'l'; break; case 'D': fmt_spec = 'd'; length_modifier = 'l'; break;
case 'U': fmt_spec = 'u'; length_modifier = 'l'; break; case 'U': fmt_spec = 'u'; length_modifier = 'l'; break;
case 'O': fmt_spec = 'o'; length_modifier = 'l'; break; case 'O': fmt_spec = 'o'; length_modifier = 'l'; break;
case 'F': fmt_spec = 'f'; break;
default: break; default: break;
} }
@@ -4715,6 +4714,7 @@ vim_vsnprintf(
# ifdef FEAT_FLOAT # ifdef FEAT_FLOAT
case 'f': case 'f':
case 'F':
case 'e': case 'e':
case 'E': case 'E':
case 'g': case 'g':
@@ -4740,13 +4740,13 @@ vim_vsnprintf(
* "1.0" as "1", we don't want that. */ * "1.0" as "1", we don't want that. */
if ((abs_f >= 0.001 && abs_f < 10000000.0) if ((abs_f >= 0.001 && abs_f < 10000000.0)
|| abs_f == 0.0) || abs_f == 0.0)
fmt_spec = 'f'; fmt_spec = ASCII_ISUPPER(fmt_spec) ? 'F' : 'f';
else else
fmt_spec = fmt_spec == 'g' ? 'e' : 'E'; fmt_spec = fmt_spec == 'g' ? 'e' : 'E';
remove_trailing_zeroes = TRUE; remove_trailing_zeroes = TRUE;
} }
if (fmt_spec == 'f' && if ((fmt_spec == 'f' || fmt_spec == 'F') &&
# ifdef VAX # ifdef VAX
abs_f > 1.0e38 abs_f > 1.0e38
# else # else
@@ -4762,23 +4762,6 @@ vim_vsnprintf(
} }
else else
{ {
format[0] = '%';
l = 1;
if (precision_specified)
{
size_t max_prec = TMP_LEN - 10;
/* Make sure we don't get more digits than we
* have room for. */
if (fmt_spec == 'f' && abs_f > 1.0)
max_prec -= (size_t)log10(abs_f);
if (precision > max_prec)
precision = max_prec;
l += sprintf(format + 1, ".%d", (int)precision);
}
format[l] = fmt_spec;
format[l + 1] = NUL;
if (isnan(f)) if (isnan(f))
{ {
/* Not a number: nan or NAN */ /* Not a number: nan or NAN */
@@ -4795,8 +4778,30 @@ vim_vsnprintf(
zero_padding = 0; zero_padding = 0;
} }
else else
{
/* Regular float number */ /* Regular float number */
format[0] = '%';
l = 1;
if (force_sign)
format[l++] = space_for_positive ? ' ' : '+';
if (precision_specified)
{
size_t max_prec = TMP_LEN - 10;
/* Make sure we don't get more digits than we
* have room for. */
if ((fmt_spec == 'f' || fmt_spec == 'F')
&& abs_f > 1.0)
max_prec -= (size_t)log10(abs_f);
if (precision > max_prec)
precision = max_prec;
l += sprintf(format + l, ".%d", (int)precision);
}
format[l] = fmt_spec;
format[l + 1] = NUL;
str_arg_l = sprintf(tmp, format, f); str_arg_l = sprintf(tmp, format, f);
}
if (remove_trailing_zeroes) if (remove_trailing_zeroes)
{ {
@@ -4804,7 +4809,7 @@ vim_vsnprintf(
char *tp; char *tp;
/* Using %g or %G: remove superfluous zeroes. */ /* Using %g or %G: remove superfluous zeroes. */
if (fmt_spec == 'f') if (fmt_spec == 'f' || fmt_spec == 'F')
tp = tmp + str_arg_l - 1; tp = tmp + str_arg_l - 1;
else else
{ {
@@ -4861,6 +4866,13 @@ vim_vsnprintf(
} }
} }
} }
if (zero_padding && min_field_width > str_arg_l
&& (tmp[0] == '-' || force_sign))
{
/* padding 0's should be inserted after the sign */
number_of_zeros_to_pad = min_field_width - str_arg_l;
zero_padding_insertion_ind = 1;
}
str_arg = tmp; str_arg = tmp;
break; break;
} }

View File

@@ -162,21 +162,44 @@ function Test_printf_misc()
call assert_equal(' +123', printf('%+6d', 123)) call assert_equal(' +123', printf('%+6d', 123))
call assert_equal(' 123', printf('% 6d', 123)) call assert_equal(' 123', printf('% 6d', 123))
call assert_equal(' -123', printf('% 6d', -123)) call assert_equal(' -123', printf('% 6d', -123))
" Test left adjusted.
call assert_equal('123 ', printf('%-6d', 123))
call assert_equal('+123 ', printf('%-+6d', 123)) call assert_equal('+123 ', printf('%-+6d', 123))
call assert_equal(' 123 ', printf('%- 6d', 123)) call assert_equal(' 123 ', printf('%- 6d', 123))
call assert_equal('-123 ', printf('%- 6d', -123)) call assert_equal('-123 ', printf('%- 6d', -123))
call assert_equal(' 00123', printf('%7.5d', 123))
call assert_equal(' -00123', printf('%7.5d', -123))
call assert_equal(' +00123', printf('%+7.5d', 123))
" Precision field should not be used when combined with %0
call assert_equal(' 00123', printf('%07.5d', 123))
call assert_equal(' -00123', printf('%07.5d', -123))
call assert_equal(' 123', printf('%*d', 5, 123))
call assert_equal('123 ', printf('%*d', -5, 123))
call assert_equal('00123', printf('%.*d', 5, 123)) call assert_equal('00123', printf('%.*d', 5, 123))
call assert_equal(' 123', printf('% *d', 5, 123)) call assert_equal(' 123', printf('% *d', 5, 123))
call assert_equal(' +123', printf('%+ *d', 5, 123)) call assert_equal(' +123', printf('%+ *d', 5, 123))
call assert_equal('123 ', printf('%-5d', 123)) " Simple quote (thousand grouping char) is ignored.
call assert_equal('+00123456', printf("%+'09d", 123456))
" Unrecognized format specifier kept as-is.
call assert_equal('_123', printf("%_%d", 123))
" Test alternate forms.
call assert_equal('0x7b', printf('%#x', 123)) call assert_equal('0x7b', printf('%#x', 123))
call assert_equal('0X7B', printf('%#X', 123)) call assert_equal('0X7B', printf('%#X', 123))
call assert_equal('0173', printf('%#o', 123)) call assert_equal('0173', printf('%#o', 123))
call assert_equal('0173', printf('%#O', 123)) call assert_equal('0173', printf('%#O', 123))
call assert_equal('abc', printf('%#s', 'abc')) call assert_equal('abc', printf('%#s', 'abc'))
call assert_equal('abc', printf('%#S', 'abc')) call assert_equal('abc', printf('%#S', 'abc'))
call assert_equal(' 0173', printf('%#6o', 123))
call assert_equal(' 00173', printf('%#6.5o', 123))
call assert_equal(' 0173', printf('%#6.2o', 123))
call assert_equal(' 0173', printf('%#6.2o', 123))
call assert_equal('0173', printf('%#2.2o', 123))
call assert_equal(' 00123', printf('%6.5d', 123)) call assert_equal(' 00123', printf('%6.5d', 123))
call assert_equal(' 0007b', printf('%6.5x', 123)) call assert_equal(' 0007b', printf('%6.5x', 123))
@@ -201,6 +224,7 @@ endfunc
function Test_printf_float() function Test_printf_float()
if has('float') if has('float')
call assert_equal('1.000000', printf('%f', 1))
call assert_equal('1.230000', printf('%f', 1.23)) call assert_equal('1.230000', printf('%f', 1.23))
call assert_equal('1.230000', printf('%F', 1.23)) call assert_equal('1.230000', printf('%F', 1.23))
call assert_equal('9999999.9', printf('%g', 9999999.9)) call assert_equal('9999999.9', printf('%g', 9999999.9))
@@ -215,10 +239,31 @@ function Test_printf_float()
call assert_equal(' 0.33', printf('%6.2f', 1.0/3.0)) call assert_equal(' 0.33', printf('%6.2f', 1.0/3.0))
call assert_equal(' -0.33', printf('%6.2f', -1.0/3.0)) call assert_equal(' -0.33', printf('%6.2f', -1.0/3.0))
call assert_equal('000.33', printf('%06.2f', 1.0/3.0)) call assert_equal('000.33', printf('%06.2f', 1.0/3.0))
" FIXME: call assert_equal('-00.33', printf('%06.2f', -1.0/3.0)) call assert_equal('-00.33', printf('%06.2f', -1.0/3.0))
" FIXME: call assert_equal('-00.33', printf('%+06.2f', -1.0/3.0)) call assert_equal('-00.33', printf('%+06.2f', -1.0/3.0))
" FIXME: call assert_equal('+00.33', printf('%+06.2f', 1.0/3.0)) call assert_equal('+00.33', printf('%+06.2f', 1.0/3.0))
" FIXME: call assert_equal(' 00.33', printf('% 06.2f', 1.0/3.0)) call assert_equal(' 00.33', printf('% 06.2f', 1.0/3.0))
call assert_equal('000.33', printf('%06.2g', 1.0/3.0))
call assert_equal('-00.33', printf('%06.2g', -1.0/3.0))
call assert_equal('0.33', printf('%3.2f', 1.0/3.0))
call assert_equal('003.33e-01', printf('%010.2e', 1.0/3.0))
call assert_equal(' 03.33e-01', printf('% 010.2e', 1.0/3.0))
call assert_equal('+03.33e-01', printf('%+010.2e', 1.0/3.0))
call assert_equal('-03.33e-01', printf('%010.2e', -1.0/3.0))
" When precision is 0, the dot should be omitted.
call assert_equal(' 2', printf('%3.f', 7.0/3.0))
call assert_equal(' 2', printf('%3.g', 7.0/3.0))
call assert_equal(' 2e+00', printf('%7.e', 7.0/3.0))
" Float zero can be signed.
call assert_equal('+0.000000', printf('%+f', 0.0))
call assert_equal('0.000000', printf('%f', 1.0/(1.0/0.0)))
call assert_equal('-0.000000', printf('%f', 1.0/(-1.0/0.0)))
call assert_equal('0.0', printf('%s', 1.0/(1.0/0.0)))
call assert_equal('-0.0', printf('%s', 1.0/(-1.0/0.0)))
call assert_equal('0.0', printf('%S', 1.0/(1.0/0.0)))
call assert_equal('-0.0', printf('%S', 1.0/(-1.0/0.0)))
" Float infinity can be signed. " Float infinity can be signed.
call assert_equal('inf', printf('%f', 1.0/0.0)) call assert_equal('inf', printf('%f', 1.0/0.0))
@@ -227,6 +272,8 @@ function Test_printf_float()
call assert_equal('-inf', printf('%g', -1.0/0.0)) call assert_equal('-inf', printf('%g', -1.0/0.0))
call assert_equal('inf', printf('%e', 1.0/0.0)) call assert_equal('inf', printf('%e', 1.0/0.0))
call assert_equal('-inf', printf('%e', -1.0/0.0)) call assert_equal('-inf', printf('%e', -1.0/0.0))
call assert_equal('INF', printf('%F', 1.0/0.0))
call assert_equal('-INF', printf('%F', -1.0/0.0))
call assert_equal('INF', printf('%E', 1.0/0.0)) call assert_equal('INF', printf('%E', 1.0/0.0))
call assert_equal('-INF', printf('%E', -1.0/0.0)) call assert_equal('-INF', printf('%E', -1.0/0.0))
call assert_equal('INF', printf('%E', 1.0/0.0)) call assert_equal('INF', printf('%E', 1.0/0.0))
@@ -245,6 +292,9 @@ function Test_printf_float()
call assert_equal('-inf ', printf('%-6f', -1.0/0.0)) call assert_equal('-inf ', printf('%-6f', -1.0/0.0))
call assert_equal('+inf ', printf('%-+6f', 1.0/0.0)) call assert_equal('+inf ', printf('%-+6f', 1.0/0.0))
call assert_equal(' inf ', printf('%- 6f', 1.0/0.0)) call assert_equal(' inf ', printf('%- 6f', 1.0/0.0))
call assert_equal('-INF ', printf('%-6F', -1.0/0.0))
call assert_equal('+INF ', printf('%-+6F', 1.0/0.0))
call assert_equal(' INF ', printf('%- 6F', 1.0/0.0))
call assert_equal('INF ', printf('%-6G', 1.0/0.0)) call assert_equal('INF ', printf('%-6G', 1.0/0.0))
call assert_equal('-INF ', printf('%-6G', -1.0/0.0)) call assert_equal('-INF ', printf('%-6G', -1.0/0.0))
call assert_equal('INF ', printf('%-6E', 1.0/0.0)) call assert_equal('INF ', printf('%-6E', 1.0/0.0))
@@ -252,22 +302,16 @@ function Test_printf_float()
call assert_equal('inf', printf('%s', 1.0/0.0)) call assert_equal('inf', printf('%s', 1.0/0.0))
call assert_equal('-inf', printf('%s', -1.0/0.0)) call assert_equal('-inf', printf('%s', -1.0/0.0))
" Float zero can be signed.
call assert_equal('0.000000', printf('%f', 1.0/(1.0/0.0)))
call assert_equal('-0.000000', printf('%f', 1.0/(-1.0/0.0)))
call assert_equal('0.0', printf('%s', 1.0/(1.0/0.0)))
call assert_equal('-0.0', printf('%s', 1.0/(-1.0/0.0)))
call assert_equal('0.0', printf('%S', 1.0/(1.0/0.0)))
call assert_equal('-0.0', printf('%S', 1.0/(-1.0/0.0)))
" Float nan (not a number) has no sign. " Float nan (not a number) has no sign.
call assert_equal('nan', printf('%f', sqrt(-1.0))) call assert_equal('nan', printf('%f', sqrt(-1.0)))
call assert_equal('nan', printf('%f', 0.0/0.0)) call assert_equal('nan', printf('%f', 0.0/0.0))
call assert_equal('nan', printf('%f', -0.0/0.0)) call assert_equal('nan', printf('%f', -0.0/0.0))
call assert_equal('nan', printf('%g', 0.0/0.0)) call assert_equal('nan', printf('%g', 0.0/0.0))
call assert_equal('nan', printf('%e', 0.0/0.0)) call assert_equal('nan', printf('%e', 0.0/0.0))
call assert_equal('NAN', printf('%F', 0.0/0.0))
call assert_equal('NAN', printf('%G', 0.0/0.0)) call assert_equal('NAN', printf('%G', 0.0/0.0))
call assert_equal('NAN', printf('%E', 0.0/0.0)) call assert_equal('NAN', printf('%E', 0.0/0.0))
call assert_equal('NAN', printf('%F', -0.0/0.0))
call assert_equal('NAN', printf('%G', -0.0/0.0)) call assert_equal('NAN', printf('%G', -0.0/0.0))
call assert_equal('NAN', printf('%E', -0.0/0.0)) call assert_equal('NAN', printf('%E', -0.0/0.0))
call assert_equal(' nan', printf('%6f', 0.0/0.0)) call assert_equal(' nan', printf('%6f', 0.0/0.0))

View File

@@ -763,6 +763,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
2291,
/**/ /**/
2290, 2290,
/**/ /**/