Branch: Tag:

2020-05-31

2020-05-31 17:51:45 by Marcus Comstedt <marcus@mc.pp.se>

Compiler: Fix floating point literals with long-double-precision

2760:    return 0.0;   }    + #if SIZEOF_FLOAT_TYPE > SIZEOF_DOUBLE + /* Convert PCHARP to a long double. If ENDPTR is not NULL, a pointer to the +  character after the last one used in the number is put in *ENDPTR. */ + PMOD_EXPORT long double STRTOLD_PCHARP(const PCHARP nptr, PCHARP *endptr) + { +  /* Note: Code duplication in strtod. */    -  +  PCHARP s; +  short int sign; +  +  /* The number so far. */ +  long double num; +  +  int got_dot; /* Found a decimal point. */ +  int got_digit; /* Seen any digits. */ +  +  /* The exponent of the number. */ +  long int exponent; +  +  if (nptr.ptr == NULL) +  { +  errno = EINVAL; +  goto noconv; +  } +  +  s = nptr; +  +  /* Eat whitespace. */ +  while (wide_isspace(EXTRACT_PCHARP(s))) INC_PCHARP(s,1); +  +  /* Get the sign. */ +  sign = EXTRACT_PCHARP(s) == '-' ? -1 : 1; +  if (EXTRACT_PCHARP(s) == '-' || EXTRACT_PCHARP(s) == '+') +  INC_PCHARP(s,1); +  +  num = 0.0; +  got_dot = 0; +  got_digit = 0; +  exponent = 0; +  for (;; INC_PCHARP(s,1)) +  { +  if (WIDE_ISDIGIT (EXTRACT_PCHARP(s))) +  { +  got_digit = 1; +  +  /* Make sure that multiplication by 10 will not overflow. */ +  if (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. +  The exponent may reduce it to within range. +  +  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'); +  +  /* Keep track of the number of digits after the decimal point. +  If we just divided by 10 here, we would lose precision. */ +  if (got_dot) +  --exponent; +  } +  else if (!got_dot && (char) EXTRACT_PCHARP(s) == '.') +  /* Record that we have found the decimal point. */ +  got_dot = 1; +  else +  /* Any other character terminates the number. */ +  break; +  } +  +  if (!got_digit) +  goto noconv; +  +  if (EXTRACT_PCHARP(s) == 'E' || EXTRACT_PCHARP(s) == 'e') +  { +  /* Get the exponent specified after the `e' or `E'. */ +  int save = errno; +  PCHARP end; +  long int exp; +  +  errno = 0; +  INC_PCHARP(s,1); +  exp = STRTOL_PCHARP(s, &end, 10); +  if (errno == ERANGE) +  { +  /* The exponent overflowed a `long int'. It is probably a safe +  assumption that an exponent that cannot be represented by +  a `long int' exceeds the limits of a `long double'. */ +  /* NOTE: Don't trust the value returned from strtol. +  * We need to find the sign of the exponent by hand. +  */ +  p_wchar2 c; +  while(wide_isspace(c = EXTRACT_PCHARP(s))) { +  INC_PCHARP(s, 1); +  } +  if (endptr != NULL) +  *endptr = end; +  if (c == '-') +  goto underflow; +  else +  goto overflow; +  } +  else if (COMPARE_PCHARP(end,==,s)) +  /* There was no exponent. Reset END to point to +  the 'e' or 'E', so *ENDPTR will be set there. */ +  end = ADD_PCHARP(s,-1); +  errno = save; +  s = end; +  exponent += exp; +  } +  +  if(got_dot && INDEX_PCHARP(s,-1)=='.') INC_PCHARP(s,-1); +  if (endptr != NULL) +  *endptr = s; +  +  if (num == 0.0) +  return 0.0; +  +  /* Multiply NUM by 10 to the EXPONENT power, +  checking for overflow and underflow. */ +  +  if (exponent < 0) +  { +  if (num < LDBL_MIN * pow(10.0, (double) -exponent)) +  goto underflow; +  } +  else if (exponent > 0) +  { +  if (num > LDBL_MAX * pow(10.0, (double) -exponent)) +  goto overflow; +  } +  +  if(exponent < 0 && exponent >-100) /* make sure we don't underflow */ +  num /= powl(10.0, (long double) -exponent); +  else +  num *= powl(10.0, (long double) exponent); +  +  return num * sign; +  +  overflow: +  /* Return an overflow error. */ +  errno = ERANGE; +  return HUGE_VALL * sign; +  +  underflow: +  /* Return an underflow error. */ +  errno = ERANGE; +  return 0.0; +  +  noconv: +  /* There was no number. */ +  if (endptr != NULL) +  *endptr = nptr; +  return 0.0; + } + #endif +  +    PMOD_EXPORT p_wchar0 *require_wstring0(const struct pike_string *s,    char **to_free)   {