Re: [patch] fixed bugs with inf and nan when using printf()

2016-08-28 Fir de Conversatie Bram Moolenaar

Dominique Pellé wrote:

> I found more unexpected results of printf() with
> float infinity and float nan (not a number) values
> using Vim-7.4.2275:
> 
> :echo printf('%+f', 1.0/0.0)
>   Expected: '+inf'
>   Actual:   'inf'
> 
> :echo printf('% f', 1.0/0.0)
>   Expected: ' inf'
>   Actual:   'inf'
> 
> :echo printf('%+06f', 1.0/0.0)
>   Expected: '  +inf'
>   Actual:   '000inf'
> 
> :echo printf('%G', 0.0/0.0)
>   Expected: 'NAN'
>   Actual:   '-NAN'
> 
> :echo printf('%6f', 0.0/0.0)
>Expected: '   nan'
>Actual:   '  nan'
> 
> :echo printf('%06f', 0.0/0.0)
>Expected: '   nan'
>Actual:   '00nan'
> 
> Code in Vim-7.4.2275 was also using isinf(f) == -1
> which I don't think was portable as man isinf states:
> 
> === BEGIN QUOTE  man isinf ===
> For isinf(), the standards merely say that the return value
> is nonzero if and only if the argument has an infinite value.
> === END QUOTE ===
> 
> Attached patch fixes all those problems, and adds the
> test cases to src/testdir/test_expr.vim.  I could only test
> it on Linux.
> 
> But there are remaining problems which I have not been
> able to fix yet (they exist prior to my  patch, so they are not
> introduced by my patch):
> 
> :echo printf('%06.2f', -1.0/3.0)
>Expected: '000.33'
>Actual:   '0-0.33'
> 
> :echo printf('%+06.2f', 1.0/3.0)
>Expected: '+00.33'
>Actual:   '000.33'
> 
> :echo printf('% 06.2f', 1.0/3.0)
>Expected: ' 00.33'
>Actual:   '000.33'
> 
> I added test cases for the remaining problems too, but they are
> commented out as they currently fail.

Thanks, I'll include it.
I hope you can fix the remaining problems too.

-- 
I AM THANKFUL...
...for the mess to clean after a party because it means I have
been surrounded by friends.

 /// Bram Moolenaar -- b...@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///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[patch] fixed bugs with inf and nan when using printf()

2016-08-27 Fir de Conversatie Dominique Pellé
Hi

I found more unexpected results of printf() with
float infinity and float nan (not a number) values
using Vim-7.4.2275:

:echo printf('%+f', 1.0/0.0)
  Expected: '+inf'
  Actual:   'inf'

:echo printf('% f', 1.0/0.0)
  Expected: ' inf'
  Actual:   'inf'

:echo printf('%+06f', 1.0/0.0)
  Expected: '  +inf'
  Actual:   '000inf'

:echo printf('%G', 0.0/0.0)
  Expected: 'NAN'
  Actual:   '-NAN'

:echo printf('%6f', 0.0/0.0)
   Expected: '   nan'
   Actual:   '  nan'

:echo printf('%06f', 0.0/0.0)
   Expected: '   nan'
   Actual:   '00nan'

Code in Vim-7.4.2275 was also using isinf(f) == -1
which I don't think was portable as man isinf states:

=== BEGIN QUOTE  man isinf ===
For isinf(), the standards merely say that the return value
is nonzero if and only if the argument has an infinite value.
=== END QUOTE ===

Attached patch fixes all those problems, and adds the
test cases to src/testdir/test_expr.vim.  I could only test
it on Linux.

But there are remaining problems which I have not been
able to fix yet (they exist prior to my  patch, so they are not
introduced by my patch):

:echo printf('%06.2f', -1.0/3.0)
   Expected: '000.33'
   Actual:   '0-0.33'

:echo printf('%+06.2f', 1.0/3.0)
   Expected: '+00.33'
   Actual:   '000.33'

:echo printf('% 06.2f', 1.0/3.0)
   Expected: ' 00.33'
   Actual:   '000.33'

I added test cases for the remaining problems too, but they are
commented out as they currently fail.

Regards
Dominique

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
diff --git a/src/message.c b/src/message.c
index 037d456..1db1cb3 100644
--- a/src/message.c
+++ b/src/message.c
@@ -3991,6 +3991,24 @@ tv_float(typval_T *tvs, int *idxp)
 #endif
 
 /*
+ * Return the representation of infinity for printf() function:
+ * "-inf", "inf", "+inf", " inf", "-INF", "INF", "+INF" or " INF".
+ */
+static const char *infinity_str(int positive, char fmt_spec, int force_sign, int space_for_positive)
+{
+static const char *table[] =
+{
+	"-inf", "inf", "+inf", " inf",
+	"-INF", "INF", "+INF", " INF"
+};
+int idx = positive*(1 + force_sign + force_sign*space_for_positive);
+
+if (ASCII_ISUPPER(fmt_spec))
+	idx += 4;
+return table[idx];
+}
+
+/*
  * This code was included to provide a portable vsnprintf() and snprintf().
  * Some systems may provide their own, but we always use this one for
  * consistency.
@@ -4008,8 +4026,8 @@ tv_float(typval_T *tvs, int *idxp)
  *
  * Limited support for floating point was added: 'f', 'e', 'E', 'g', 'G'.
  *
- * Length modifiers 'h' (short int) and 'l' (long int) are supported.
- * 'll' (long long int) is not supported.
+ * Length modifiers 'h' (short int) and 'l' (long int) and 'll' (long long int)
+ * are supported.
  *
  * The locale is not used, the string is used as a byte string.  This is only
  * relevant for double-byte encodings where the second byte may be '%'.
@@ -4397,7 +4415,7 @@ vim_vsnprintf(
 		uvarnumber_T ullong_arg = 0;
 # endif
 
-		/* only defined for b convertion */
+		/* only defined for b conversion */
 		uvarnumber_T bin_arg = 0;
 
 		/* pointer argument value -only defined for p
@@ -4732,16 +4750,9 @@ vim_vsnprintf(
 			)
 		{
 			/* Avoid a buffer overflow */
-			if (f < 0)
-			{
-			strcpy(tmp, "-inf");
-			str_arg_l = 4;
-			}
-			else
-			{
-			strcpy(tmp, "inf");
-			str_arg_l = 3;
-			}
+			STRCPY(tmp, infinity_str(f > 0.0, fmt_spec, force_sign, space_for_positive));
+			str_arg_l = STRLEN(tmp);
+			zero_padding = 0;
 		}
 		else
 		{
@@ -4761,23 +4772,23 @@ vim_vsnprintf(
 			}
 			format[l] = fmt_spec;
 			format[l + 1] = NUL;
-			str_arg_l = sprintf(tmp, format, f);
-
-			/* Be consistent: Change "1.#IND" to "nan" and
-			 * "1.#INF" to "inf". */
-			s = *tmp == '-' ? tmp + 1 : tmp;
-			if (STRNCMP(s, "1.#INF", 6) == 0)
-			STRCPY(s, "inf");
-			else if (STRNCMP(s, "1.#IND", 6) == 0)
-			STRCPY(s, "nan");
-
-			/* Remove sign before "nan". */
-			if (STRNCMP(tmp, "-nan", 4) == 0)
-			STRCPY(tmp, "nan");
-
-			/* Add sign before "inf" if needed. */
-			if (isinf(f) == -1 && STRNCMP(tmp, "inf", 3) == 0)
-			STRCPY(tmp, "-inf");
+
+			if (isnan(f))
+			{
+			/* Not a number: nan or NAN */
+			STRCPY(tmp, ASCII_ISUPPER(fmt_spec) ? "NAN" : "nan");
+			str_arg_l = 3;
+			zero_padding = 0;
+			}
+			else if (isinf(f))
+			{
+			STRCPY(tmp, infinity_str(f > 0.0, fmt_spec, force_sign, space_for_positive));
+			str_arg_l = STRLEN(tmp);
+			zero_padding = 0;
+			}
+			else
+			/* Regular float number */
+			str