To: vim_dev@googlegroups.com Subject: Patch 7.4.2291 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 7.4.2291 Problem: printf() handles floats wrong when there is a sign. Solution: Fix placing the sign. Add tests. (Dominique Pelle) Files: src/testdir/test_expr.vim, runtime/doc/eval.txt, src/message.c *** ../vim-7.4.2290/src/testdir/test_expr.vim 2016-08-28 16:03:34.824991857 +0200 --- src/testdir/test_expr.vim 2016-08-29 21:45:35.009473848 +0200 *************** *** 162,182 **** 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('%.*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)) 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('abc', printf('%#s', 'abc')) call assert_equal('abc', printf('%#S', 'abc')) call assert_equal(' 00123', printf('%6.5d', 123)) call assert_equal(' 0007b', printf('%6.5x', 123)) --- 162,205 ---- 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(' 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(' 123', printf('% *d', 5, 123)) call assert_equal(' +123', printf('%+ *d', 5, 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('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(' 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(' 0007b', printf('%6.5x', 123)) *************** *** 201,206 **** --- 224,230 ---- function Test_printf_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('9999999.9', printf('%g', 9999999.9)) *************** *** 215,224 **** 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)) ! " FIXME: 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)) ! " FIXME: 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)) " Float infinity can be signed. call assert_equal('inf', printf('%f', 1.0/0.0)) --- 239,269 ---- 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('-00.33', printf('%06.2f', -1.0/3.0)) ! 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(' 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. call assert_equal('inf', printf('%f', 1.0/0.0)) *************** *** 227,232 **** --- 272,279 ---- 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('%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)) *************** *** 245,250 **** --- 292,300 ---- 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('%-6E', 1.0/0.0)) *************** *** 252,273 **** 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. 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('%g', 0.0/0.0)) call assert_equal('nan', printf('%e', 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('%G', -0.0/0.0)) call assert_equal('NAN', printf('%E', -0.0/0.0)) call assert_equal(' nan', printf('%6f', 0.0/0.0)) --- 302,317 ---- call assert_equal('inf', printf('%s', 1.0/0.0)) call assert_equal('-inf', printf('%s', -1.0/0.0)) " Float nan (not a number) has no sign. 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('%g', 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('%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('%E', -0.0/0.0)) call assert_equal(' nan', printf('%6f', 0.0/0.0)) *** ../vim-7.4.2290/runtime/doc/eval.txt 2016-08-27 21:25:22.698047706 +0200 --- runtime/doc/eval.txt 2016-08-29 21:46:41.816905449 +0200 *************** *** 5873,5881 **** %X hex number using upper case letters %o octal number %08b binary number padded with zeros to at least 8 chars ! %f floating point number in the form 123.456 ! %e floating point number in the form 1.234e3 ! %E floating point number in the form 1.234E3 %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 --- 5907,5916 ---- %X hex number using upper case letters %o octal number %08b binary number padded with zeros to at least 8 chars ! %f floating point number as 12.23, inf, -inf or nan ! %F floating point number as 12.23, INF, -INF or NAN ! %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 %% the % character itself *************** *** 5973,5978 **** --- 6008,6023 ---- cause truncation of a numeric field; if the result of a conversion is wider than the field width, the field is expanded to contain the conversion result. + The 'h' modifier indicates the argument is 16 bits. + The 'l' modifier indicates the argument is 32 bits. + The 'L' modifier indicates the argument is 64 bits. + Generally, these modifiers are not useful. They are + ignored when type is known from the argument. + + i alias for d + D alias for ld + U alias for lu + O alias for lo *printf-c* c The Number argument is converted to a byte, and the *************** *** 5992,6004 **** feature works just like 's'. *printf-f* *E807* ! f The Float argument is converted into a string of the form 123.456. The precision specifies the number of digits after the decimal point. When the precision is zero the decimal point is omitted. When the precision is not specified 6 is used. A really big number ! (out of range or dividing by zero) results in "inf". ! "0.0 / 0.0" results in "nan". Example: > echo printf("%.2f", 12.115) < 12.12 --- 6037,6050 ---- feature works just like 's'. *printf-f* *E807* ! f F The Float argument is converted into a string of the form 123.456. The precision specifies the number of digits after the decimal point. When the precision is zero the decimal point is omitted. When the precision is not specified 6 is used. A really big number ! (out of range or dividing by zero) results in "inf" ! or "-inf" with %f (INF or -INF with %F). ! "0.0 / 0.0" results in "nan" with %f (NAN with %F). Example: > echo printf("%.2f", 12.115) < 12.12 *** ../vim-7.4.2290/src/message.c 2016-08-28 21:21:19.836617773 +0200 --- src/message.c 2016-08-29 21:49:04.527691343 +0200 *************** *** 4030,4036 **** * with flags: '-', '+', ' ', '0' and '#'. * An asterisk is supported for field width as well as precision. * ! * Limited support for floating point was added: 'f', 'e', 'E', 'g', 'G'. * * Length modifiers 'h' (short int) and 'l' (long int) and 'll' (long long int) * are supported. --- 4030,4036 ---- * with flags: '-', '+', ' ', '0' and '#'. * An asterisk is supported for field width as well as precision. * ! * 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) * are supported. *************** *** 4286,4292 **** case 'D': fmt_spec = 'd'; length_modifier = 'l'; break; case 'U': fmt_spec = 'u'; length_modifier = 'l'; break; case 'O': fmt_spec = 'o'; length_modifier = 'l'; break; - case 'F': fmt_spec = 'f'; break; default: break; } --- 4286,4291 ---- *************** *** 4715,4720 **** --- 4714,4720 ---- # ifdef FEAT_FLOAT case 'f': + case 'F': case 'e': case 'E': case 'g': *************** *** 4740,4752 **** * "1.0" as "1", we don't want that. */ if ((abs_f >= 0.001 && abs_f < 10000000.0) || abs_f == 0.0) ! fmt_spec = 'f'; else fmt_spec = fmt_spec == 'g' ? 'e' : 'E'; remove_trailing_zeroes = TRUE; } ! if (fmt_spec == 'f' && # ifdef VAX abs_f > 1.0e38 # else --- 4740,4752 ---- * "1.0" as "1", we don't want that. */ if ((abs_f >= 0.001 && abs_f < 10000000.0) || abs_f == 0.0) ! fmt_spec = ASCII_ISUPPER(fmt_spec) ? 'F' : 'f'; else fmt_spec = fmt_spec == 'g' ? 'e' : 'E'; remove_trailing_zeroes = TRUE; } ! if ((fmt_spec == 'f' || fmt_spec == 'F') && # ifdef VAX abs_f > 1.0e38 # else *************** *** 4762,4784 **** } 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)) { /* Not a number: nan or NAN */ --- 4762,4767 ---- *************** *** 4795,4802 **** --- 4778,4807 ---- zero_padding = 0; } else + { /* 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); + } if (remove_trailing_zeroes) { *************** *** 4804,4810 **** char *tp; /* Using %g or %G: remove superfluous zeroes. */ ! if (fmt_spec == 'f') tp = tmp + str_arg_l - 1; else { --- 4809,4815 ---- char *tp; /* Using %g or %G: remove superfluous zeroes. */ ! if (fmt_spec == 'f' || fmt_spec == 'F') tp = tmp + str_arg_l - 1; else { *************** *** 4861,4866 **** --- 4866,4878 ---- } } } + 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; break; } *** ../vim-7.4.2290/src/version.c 2016-08-28 21:21:19.836617773 +0200 --- src/version.c 2016-08-29 21:47:16.772608054 +0200 *************** *** 765,766 **** --- 765,768 ---- { /* Add new patch number below this line */ + /**/ + 2291, /**/ -- hundred-and-one symptoms of being an internet addict: 105. When someone asks you for your address, you tell them your URL. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///