*** bram/eval.c	2008-04-13
--- eval.c	2008-04-16
***************
*** 4768,4773 ****
--- 4768,4776 ----
      char_u	*start_leader, *end_leader;
      int		ret = OK;
      char_u	*alias;
+ #ifdef FEAT_FLOAT
+     char_u	next;
+ #endif
  
      /*
       * Initialise variable so that clear_tv() can't mistake this for a
***************
*** 4836,4842 ****
       */
      case '&':
  #ifdef FEAT_FLOAT
! 		if (vim_isdigit(*(*arg + 1)))
  		    get_float_tv(arg, rettv, evaluate);
  		else
  #endif
--- 4839,4846 ----
       */
      case '&':
  #ifdef FEAT_FLOAT
! 		next = *(*arg + 1);
! 		if (vim_isdigit(next) || (next == '-' || next == '+'))
  		    get_float_tv(arg, rettv, evaluate);
  		else
  #endif
***************
*** 7263,7270 ****
  }
  
  /*
!  * Convert the sting "text" to a floating point number.
   * Returns the length of the text that was consumed.
   */
      static int
  string2float(text, value, comma)
--- 7267,7278 ----
  }
  
  /*
!  * Convert the string "text" to a floating point number.
   * Returns the length of the text that was consumed.
+  * Handles "12", "1.2", "1.2e3", "1.2e+3", "1.2e-3" and leading '+' or '-'.
+  * This should work up to the machine's limit, then silently(?) overflow.
+  * As an optimisation, integer arithmetic is used for each group
+  * of up to 8 digits.
   */
      static int
  string2float(text, value, comma)
***************
*** 7272,7305 ****
      float_T	*value;	    /* result stored here */
      int		comma;	    /* accept a comma as decimal separator */
  {
!     char_u	*s = text;
!     int		len;
!     long	n;
!     float_T	f;
! 
!     vim_str2nr(s, NULL, &len, FALSE, FALSE, &n, NULL);
!     s += len;
!     f = n;
  
!     if ((*s == '.' || (comma && *s == ',')) && s[1] != '-')
      {
  	++s;
- 	vim_str2nr(s, NULL, &len, FALSE, FALSE, &n, NULL);
- 	s += len;
- 	f += (float_T)n / pow(10.0, (double)len);
      }
! 
!     /* 1.234e-20 */
      if (*s == 'e' || *s == 'E')
      {
  	++s;
! 	if (*s == '+')	    /* accept 1.234e+3 */
  	    ++s;
! 	vim_str2nr(s, NULL, &len, FALSE, FALSE, &n, NULL);
! 	s += len;
! 	f *= pow(10.0, (double)n);
      }
- 
      *value = f;
      return (int)(s - text);
  }
--- 7280,7355 ----
      float_T	*value;	    /* result stored here */
      int		comma;	    /* accept a comma as decimal separator */
  {
!     char_u	    *s = text;
!     float_T	    f = 0;
!     float_T	    factor = 1;
!     unsigned long   un = 0;
!     int		    dot = 0;
!     int		    group = 0;
!     int		    negative = 0;
  
!     if (*s == '+')
! 	++s;
!     else if (*s == '-')
      {
+ 	negative = 1;
  	++s;
      }
!     for (;;)
!     {
! 	if (!VIM_ISDIGIT(*s))
! 	{
! 	    if ((*s == '.' || (comma && *s == ',')) && dot == 0)
! 	    {
! 		dot = 1;
! 		++s;
! 		continue;
! 	    }
! 	    break;
! 	}
! 	if (dot > 0)
! 	    factor *= 10;
! 	if (group >= 8)
! 	{
! 	    f = f * 1e8 + un;
! 	    un = 0;
! 	    group = 0;
! 	}
! 	un = un * 10 + (unsigned long)(*s - '0');
! 	++group;
! 	++s;
!     }
!     if (group > 0)
! 	f = f * pow(10.0, (double)group) + un;
!     f /= factor;
!     if (negative)
! 	f = -f;
!     /* 1.234e3 or 1.234e-20 or 1.234e+3 */
      if (*s == 'e' || *s == 'E')
      {
+ 	long exp = 0;
+ 	negative = 0;
  	++s;
! 	if (*s == '+')
! 	    ++s;
! 	else if (*s == '-')
! 	{
! 	    negative = 1;
  	    ++s;
! 	}
! 	group = 0;
! 	while (VIM_ISDIGIT(*s))
! 	{
! 	    if (group > 4)	/* 1.2e4932 is max 128-bit float */
! 		break;
! 	    exp = exp * 10 + (*s - '0');
! 	    ++group;
! 	    ++s;
! 	}
! 	if (negative)
! 	    exp = -exp;
! 	f *= pow(10.0, (double)exp);
      }
      *value = f;
      return (int)(s - text);
  }
