Skip to content

Commit 0418609

Browse files
committed
patch 7.4.2291
Problem: printf() handles floats wrong when there is a sign. Solution: Fix placing the sign. Add tests. (Dominique Pelle)
1 parent 7f7bd29 commit 0418609

4 files changed

Lines changed: 107 additions & 45 deletions

File tree

runtime/doc/eval.txt

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*eval.txt* For Vim version 7.4. Last change: 2016 Aug 28
1+
*eval.txt* For Vim version 7.4. Last change: 2016 Aug 29
22

33

44
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -643,7 +643,7 @@ It's possible to form a variable name with curly braces, see
643643

644644
Expression syntax summary, from least to most significant:
645645

646-
|expr1| expr2 ? expr1 : expr1 if-then-else
646+
|expr1| expr2 ? expr1 : expr1 if-then-else
647647

648648
|expr2| expr3 || expr3 .. logical OR
649649

@@ -736,7 +736,9 @@ use in a variable such as "a:1".
736736
expr2 and expr3 *expr2* *expr3*
737737
---------------
738738

739-
*expr-barbar* *expr-&&*
739+
expr3 || expr3 .. logical OR *expr-barbar*
740+
expr4 && expr4 .. logical AND *expr-&&*
741+
740742
The "||" and "&&" operators take one argument on each side. The arguments
741743
are (converted to) Numbers. The result is:
742744

@@ -1981,7 +1983,7 @@ assert_notmatch({pat}, {text} [, {msg}]) none assert {pat} not matches {text}
19811983
assert_true({actual} [, {msg}]) none assert {actual} is true
19821984
asin({expr}) Float arc sine of {expr}
19831985
atan({expr}) Float arc tangent of {expr}
1984-
atan2({expr}, {expr}) Float arc tangent of {expr1} / {expr2}
1986+
atan2({expr1}, {expr2}) Float arc tangent of {expr1} / {expr2}
19851987
browse({save}, {title}, {initdir}, {default})
19861988
String put up a file requester
19871989
browsedir({title}, {initdir}) String put up a directory requester
@@ -5905,9 +5907,10 @@ printf({fmt}, {expr1} ...) *printf()*
59055907
%X hex number using upper case letters
59065908
%o octal number
59075909
%08b binary number padded with zeros to at least 8 chars
5908-
%f floating point number in the form 123.456
5909-
%e floating point number in the form 1.234e3
5910-
%E floating point number in the form 1.234E3
5910+
%f floating point number as 12.23, inf, -inf or nan
5911+
%F floating point number as 12.23, INF, -INF or NAN
5912+
%e floating point number as 1.23e3, inf, -inf or nan
5913+
%E floating point number as 1.23E3, INF, -INF or NAN
59115914
%g floating point number, as %f or %e depending on value
59125915
%G floating point number, as %f or %E depending on value
59135916
%% the % character itself
@@ -6039,8 +6042,9 @@ printf({fmt}, {expr1} ...) *printf()*
60396042
digits after the decimal point. When the precision is
60406043
zero the decimal point is omitted. When the precision
60416044
is not specified 6 is used. A really big number
6042-
(out of range or dividing by zero) results in "inf".
6043-
"0.0 / 0.0" results in "nan".
6045+
(out of range or dividing by zero) results in "inf"
6046+
or "-inf" with %f (INF or -INF with %F).
6047+
"0.0 / 0.0" results in "nan" with %f (NAN with %F).
60446048
Example: >
60456049
echo printf("%.2f", 12.115)
60466050
< 12.12
@@ -7507,7 +7511,7 @@ system({expr} [, {input}]) *system()* *E677*
75077511

75087512
Pipes are not used, the 'shelltemp' option is not used.
75097513

7510-
When prepended by |:silent| the shell will not be set to
7514+
When prepended by |:silent| the terminal will not be set to
75117515
cooked mode. This is meant to be used for commands that do
75127516
not need the user to type. It avoids stray characters showing
75137517
up on the screen which require |CTRL-L| to remove. >

src/message.c

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4030,7 +4030,7 @@ infinity_str(int positive,
40304030
* with flags: '-', '+', ' ', '0' and '#'.
40314031
* An asterisk is supported for field width as well as precision.
40324032
*
4033-
* Limited support for floating point was added: 'f', 'e', 'E', 'g', 'G'.
4033+
* Limited support for floating point was added: 'f', 'F', 'e', 'E', 'g', 'G'.
40344034
*
40354035
* Length modifiers 'h' (short int) and 'l' (long int) and 'll' (long long int)
40364036
* are supported.
@@ -4286,7 +4286,6 @@ vim_vsnprintf(
42864286
case 'D': fmt_spec = 'd'; length_modifier = 'l'; break;
42874287
case 'U': fmt_spec = 'u'; length_modifier = 'l'; break;
42884288
case 'O': fmt_spec = 'o'; length_modifier = 'l'; break;
4289-
case 'F': fmt_spec = 'f'; break;
42904289
default: break;
42914290
}
42924291

@@ -4715,6 +4714,7 @@ vim_vsnprintf(
47154714

47164715
# ifdef FEAT_FLOAT
47174716
case 'f':
4717+
case 'F':
47184718
case 'e':
47194719
case 'E':
47204720
case 'g':
@@ -4740,13 +4740,13 @@ vim_vsnprintf(
47404740
* "1.0" as "1", we don't want that. */
47414741
if ((abs_f >= 0.001 && abs_f < 10000000.0)
47424742
|| abs_f == 0.0)
4743-
fmt_spec = 'f';
4743+
fmt_spec = ASCII_ISUPPER(fmt_spec) ? 'F' : 'f';
47444744
else
47454745
fmt_spec = fmt_spec == 'g' ? 'e' : 'E';
47464746
remove_trailing_zeroes = TRUE;
47474747
}
47484748

4749-
if (fmt_spec == 'f' &&
4749+
if ((fmt_spec == 'f' || fmt_spec == 'F') &&
47504750
# ifdef VAX
47514751
abs_f > 1.0e38
47524752
# else
@@ -4762,23 +4762,6 @@ vim_vsnprintf(
47624762
}
47634763
else
47644764
{
4765-
format[0] = '%';
4766-
l = 1;
4767-
if (precision_specified)
4768-
{
4769-
size_t max_prec = TMP_LEN - 10;
4770-
4771-
/* Make sure we don't get more digits than we
4772-
* have room for. */
4773-
if (fmt_spec == 'f' && abs_f > 1.0)
4774-
max_prec -= (size_t)log10(abs_f);
4775-
if (precision > max_prec)
4776-
precision = max_prec;
4777-
l += sprintf(format + 1, ".%d", (int)precision);
4778-
}
4779-
format[l] = fmt_spec;
4780-
format[l + 1] = NUL;
4781-
47824765
if (isnan(f))
47834766
{
47844767
/* Not a number: nan or NAN */
@@ -4795,16 +4778,38 @@ vim_vsnprintf(
47954778
zero_padding = 0;
47964779
}
47974780
else
4781+
{
47984782
/* Regular float number */
4783+
format[0] = '%';
4784+
l = 1;
4785+
if (force_sign)
4786+
format[l++] = space_for_positive ? ' ' : '+';
4787+
if (precision_specified)
4788+
{
4789+
size_t max_prec = TMP_LEN - 10;
4790+
4791+
/* Make sure we don't get more digits than we
4792+
* have room for. */
4793+
if ((fmt_spec == 'f' || fmt_spec == 'F')
4794+
&& abs_f > 1.0)
4795+
max_prec -= (size_t)log10(abs_f);
4796+
if (precision > max_prec)
4797+
precision = max_prec;
4798+
l += sprintf(format + l, ".%d", (int)precision);
4799+
}
4800+
format[l] = fmt_spec;
4801+
format[l + 1] = NUL;
4802+
47994803
str_arg_l = sprintf(tmp, format, f);
4804+
}
48004805

48014806
if (remove_trailing_zeroes)
48024807
{
48034808
int i;
48044809
char *tp;
48054810

48064811
/* Using %g or %G: remove superfluous zeroes. */
4807-
if (fmt_spec == 'f')
4812+
if (fmt_spec == 'f' || fmt_spec == 'F')
48084813
tp = tmp + str_arg_l - 1;
48094814
else
48104815
{
@@ -4861,6 +4866,13 @@ vim_vsnprintf(
48614866
}
48624867
}
48634868
}
4869+
if (zero_padding && min_field_width > str_arg_l
4870+
&& (tmp[0] == '-' || force_sign))
4871+
{
4872+
/* padding 0's should be inserted after the sign */
4873+
number_of_zeros_to_pad = min_field_width - str_arg_l;
4874+
zero_padding_insertion_ind = 1;
4875+
}
48644876
str_arg = tmp;
48654877
break;
48664878
}

src/testdir/test_expr.vim

Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -162,21 +162,44 @@ function Test_printf_misc()
162162
call assert_equal(' +123', printf('%+6d', 123))
163163
call assert_equal(' 123', printf('% 6d', 123))
164164
call assert_equal(' -123', printf('% 6d', -123))
165+
166+
" Test left adjusted.
167+
call assert_equal('123 ', printf('%-6d', 123))
165168
call assert_equal('+123 ', printf('%-+6d', 123))
166169
call assert_equal(' 123 ', printf('%- 6d', 123))
167170
call assert_equal('-123 ', printf('%- 6d', -123))
168171

172+
call assert_equal(' 00123', printf('%7.5d', 123))
173+
call assert_equal(' -00123', printf('%7.5d', -123))
174+
call assert_equal(' +00123', printf('%+7.5d', 123))
175+
" Precision field should not be used when combined with %0
176+
call assert_equal(' 00123', printf('%07.5d', 123))
177+
call assert_equal(' -00123', printf('%07.5d', -123))
178+
179+
call assert_equal(' 123', printf('%*d', 5, 123))
180+
call assert_equal('123 ', printf('%*d', -5, 123))
169181
call assert_equal('00123', printf('%.*d', 5, 123))
170182
call assert_equal(' 123', printf('% *d', 5, 123))
171183
call assert_equal(' +123', printf('%+ *d', 5, 123))
172184

173-
call assert_equal('123 ', printf('%-5d', 123))
185+
" Simple quote (thousand grouping char) is ignored.
186+
call assert_equal('+00123456', printf("%+'09d", 123456))
187+
188+
" Unrecognized format specifier kept as-is.
189+
call assert_equal('_123', printf("%_%d", 123))
190+
191+
" Test alternate forms.
174192
call assert_equal('0x7b', printf('%#x', 123))
175193
call assert_equal('0X7B', printf('%#X', 123))
176194
call assert_equal('0173', printf('%#o', 123))
177195
call assert_equal('0173', printf('%#O', 123))
178196
call assert_equal('abc', printf('%#s', 'abc'))
179197
call assert_equal('abc', printf('%#S', 'abc'))
198+
call assert_equal(' 0173', printf('%#6o', 123))
199+
call assert_equal(' 00173', printf('%#6.5o', 123))
200+
call assert_equal(' 0173', printf('%#6.2o', 123))
201+
call assert_equal(' 0173', printf('%#6.2o', 123))
202+
call assert_equal('0173', printf('%#2.2o', 123))
180203

181204
call assert_equal(' 00123', printf('%6.5d', 123))
182205
call assert_equal(' 0007b', printf('%6.5x', 123))
@@ -201,6 +224,7 @@ endfunc
201224

202225
function Test_printf_float()
203226
if has('float')
227+
call assert_equal('1.000000', printf('%f', 1))
204228
call assert_equal('1.230000', printf('%f', 1.23))
205229
call assert_equal('1.230000', printf('%F', 1.23))
206230
call assert_equal('9999999.9', printf('%g', 9999999.9))
@@ -215,10 +239,31 @@ function Test_printf_float()
215239
call assert_equal(' 0.33', printf('%6.2f', 1.0/3.0))
216240
call assert_equal(' -0.33', printf('%6.2f', -1.0/3.0))
217241
call assert_equal('000.33', printf('%06.2f', 1.0/3.0))
218-
" FIXME: call assert_equal('-00.33', printf('%06.2f', -1.0/3.0))
219-
" FIXME: call assert_equal('-00.33', printf('%+06.2f', -1.0/3.0))
220-
" FIXME: call assert_equal('+00.33', printf('%+06.2f', 1.0/3.0))
221-
" FIXME: call assert_equal(' 00.33', printf('% 06.2f', 1.0/3.0))
242+
call assert_equal('-00.33', printf('%06.2f', -1.0/3.0))
243+
call assert_equal('-00.33', printf('%+06.2f', -1.0/3.0))
244+
call assert_equal('+00.33', printf('%+06.2f', 1.0/3.0))
245+
call assert_equal(' 00.33', printf('% 06.2f', 1.0/3.0))
246+
call assert_equal('000.33', printf('%06.2g', 1.0/3.0))
247+
call assert_equal('-00.33', printf('%06.2g', -1.0/3.0))
248+
call assert_equal('0.33', printf('%3.2f', 1.0/3.0))
249+
call assert_equal('003.33e-01', printf('%010.2e', 1.0/3.0))
250+
call assert_equal(' 03.33e-01', printf('% 010.2e', 1.0/3.0))
251+
call assert_equal('+03.33e-01', printf('%+010.2e', 1.0/3.0))
252+
call assert_equal('-03.33e-01', printf('%010.2e', -1.0/3.0))
253+
254+
" When precision is 0, the dot should be omitted.
255+
call assert_equal(' 2', printf('%3.f', 7.0/3.0))
256+
call assert_equal(' 2', printf('%3.g', 7.0/3.0))
257+
call assert_equal(' 2e+00', printf('%7.e', 7.0/3.0))
258+
259+
" Float zero can be signed.
260+
call assert_equal('+0.000000', printf('%+f', 0.0))
261+
call assert_equal('0.000000', printf('%f', 1.0/(1.0/0.0)))
262+
call assert_equal('-0.000000', printf('%f', 1.0/(-1.0/0.0)))
263+
call assert_equal('0.0', printf('%s', 1.0/(1.0/0.0)))
264+
call assert_equal('-0.0', printf('%s', 1.0/(-1.0/0.0)))
265+
call assert_equal('0.0', printf('%S', 1.0/(1.0/0.0)))
266+
call assert_equal('-0.0', printf('%S', 1.0/(-1.0/0.0)))
222267

223268
" Float infinity can be signed.
224269
call assert_equal('inf', printf('%f', 1.0/0.0))
@@ -227,6 +272,8 @@ function Test_printf_float()
227272
call assert_equal('-inf', printf('%g', -1.0/0.0))
228273
call assert_equal('inf', printf('%e', 1.0/0.0))
229274
call assert_equal('-inf', printf('%e', -1.0/0.0))
275+
call assert_equal('INF', printf('%F', 1.0/0.0))
276+
call assert_equal('-INF', printf('%F', -1.0/0.0))
230277
call assert_equal('INF', printf('%E', 1.0/0.0))
231278
call assert_equal('-INF', printf('%E', -1.0/0.0))
232279
call assert_equal('INF', printf('%E', 1.0/0.0))
@@ -245,29 +292,26 @@ function Test_printf_float()
245292
call assert_equal('-inf ', printf('%-6f', -1.0/0.0))
246293
call assert_equal('+inf ', printf('%-+6f', 1.0/0.0))
247294
call assert_equal(' inf ', printf('%- 6f', 1.0/0.0))
295+
call assert_equal('-INF ', printf('%-6F', -1.0/0.0))
296+
call assert_equal('+INF ', printf('%-+6F', 1.0/0.0))
297+
call assert_equal(' INF ', printf('%- 6F', 1.0/0.0))
248298
call assert_equal('INF ', printf('%-6G', 1.0/0.0))
249299
call assert_equal('-INF ', printf('%-6G', -1.0/0.0))
250300
call assert_equal('INF ', printf('%-6E', 1.0/0.0))
251301
call assert_equal('-INF ', printf('%-6E', -1.0/0.0))
252302
call assert_equal('inf', printf('%s', 1.0/0.0))
253303
call assert_equal('-inf', printf('%s', -1.0/0.0))
254304

255-
" Float zero can be signed.
256-
call assert_equal('0.000000', printf('%f', 1.0/(1.0/0.0)))
257-
call assert_equal('-0.000000', printf('%f', 1.0/(-1.0/0.0)))
258-
call assert_equal('0.0', printf('%s', 1.0/(1.0/0.0)))
259-
call assert_equal('-0.0', printf('%s', 1.0/(-1.0/0.0)))
260-
call assert_equal('0.0', printf('%S', 1.0/(1.0/0.0)))
261-
call assert_equal('-0.0', printf('%S', 1.0/(-1.0/0.0)))
262-
263305
" Float nan (not a number) has no sign.
264306
call assert_equal('nan', printf('%f', sqrt(-1.0)))
265307
call assert_equal('nan', printf('%f', 0.0/0.0))
266308
call assert_equal('nan', printf('%f', -0.0/0.0))
267309
call assert_equal('nan', printf('%g', 0.0/0.0))
268310
call assert_equal('nan', printf('%e', 0.0/0.0))
311+
call assert_equal('NAN', printf('%F', 0.0/0.0))
269312
call assert_equal('NAN', printf('%G', 0.0/0.0))
270313
call assert_equal('NAN', printf('%E', 0.0/0.0))
314+
call assert_equal('NAN', printf('%F', -0.0/0.0))
271315
call assert_equal('NAN', printf('%G', -0.0/0.0))
272316
call assert_equal('NAN', printf('%E', -0.0/0.0))
273317
call assert_equal(' nan', printf('%6f', 0.0/0.0))

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,8 @@ static char *(features[]) =
763763

764764
static int included_patches[] =
765765
{ /* Add new patch number below this line */
766+
/**/
767+
2291,
766768
/**/
767769
2290,
768770
/**/

0 commit comments

Comments
 (0)