Branch: Tag:

2020-06-06

2020-06-06 10:03:53 by Marcus Comstedt <marcus@mc.pp.se>

Compiler: Only keep parsing digits in float literals while they matter

As soon as it is detected that adding more digits stops contributing
to the mantissa, skip the remaining digits and only count them towards
the exponent. This prevents some degradation of precision, although
the function is still less exact than libc strtod...

2618:       int got_dot; /* Found a decimal point. */    int got_digit; /* Seen any digits. */ +  int precision_loss;/* No more digits fit in mantissa */       /* The exponent of the number. */    long int exponent;
2642:    got_dot = 0;    got_digit = 0;    exponent = 0; +  precision_loss = 0;    for (;; INC_PCHARP(s,1))    {    if (WIDE_ISDIGIT (EXTRACT_PCHARP(s)))
2649:    got_digit = 1;       /* Make sure that multiplication by 10 will not overflow. */ -  if (num > DBL_MAX * 0.1) +  if (precision_loss || num > DBL_MAX * 0.1)    /* The value of the digit doesn't matter, since we have already    gotten as many digits as can be represented in a `double'.    This doesn't necessarily mean the result will overflow.
2658:    We just need to record that there was another    digit so that we can multiply by 10 later. */    ++exponent; -  else -  num = (num * 10.0) + (EXTRACT_PCHARP(s) - '0'); +  else { +  int v = EXTRACT_PCHARP(s) - '0'; +  num *= 10.0; +  if (v != 0) { +  double check = num; +  num += v; +  if (num == check) +  precision_loss = 1; +  } +  }       /* Keep track of the number of digits after the decimal point.    If we just divided by 10 here, we would lose precision. */
2775: Inside #if SIZEOF_FLOAT_TYPE > SIZEOF_DOUBLE
      int got_dot; /* Found a decimal point. */    int got_digit; /* Seen any digits. */ +  int precision_loss;/* No more digits fit in mantissa */       /* The exponent of the number. */    long int exponent;
2799: Inside #if SIZEOF_FLOAT_TYPE > SIZEOF_DOUBLE
   got_dot = 0;    got_digit = 0;    exponent = 0; +  precision_loss = 0;    for (;; INC_PCHARP(s,1))    {    if (WIDE_ISDIGIT (EXTRACT_PCHARP(s)))
2806: Inside #if SIZEOF_FLOAT_TYPE > SIZEOF_DOUBLE
   got_digit = 1;       /* Make sure that multiplication by 10 will not overflow. */ -  if (num > LDBL_MAX * 0.1) +  if (precision_loss || num > LDBL_MAX * 0.1)    /* The value of the digit doesn't matter, since we have already    gotten as many digits as can be represented in a `long double'.    This doesn't necessarily mean the result will overflow.
2815: Inside #if SIZEOF_FLOAT_TYPE > SIZEOF_DOUBLE
   We just need to record that there was another    digit so that we can multiply by 10 later. */    ++exponent; -  else -  num = (num * 10.0) + (EXTRACT_PCHARP(s) - '0'); +  else { +  int v = EXTRACT_PCHARP(s) - '0'; +  num *= 10.0; +  if (v != 0) { +  long double check = num; +  num += v; +  if (num == check) +  precision_loss = 1; +  } +  }       /* Keep track of the number of digits after the decimal point.    If we just divided by 10 here, we would lose precision. */