diff --git a/src/lex.c b/src/lex.c
index 9e5dbca755bfaff8455da6567b8d772c3f39f0e9..67e2f04b3c403526bdd69ed6fe9af729070aaa80 100644
--- a/src/lex.c
+++ b/src/lex.c
@@ -13,6 +13,21 @@
 
 #include <ctype.h>
 
+static FLOAT_TYPE mymy_strtod(const char *nptr, char **endptr)
+{
+#if SIZEOF_FLOAT_TYPE > SIZEOF_DOUBLE
+  FLOAT_TYPE tmp=strtold(nptr,endptr);
+#else
+  double tmp=strtod(nptr,endptr);
+#endif
+  if(*endptr>nptr)
+  {
+    if(endptr[0][-1]=='.')
+      endptr[0]--;
+  }
+  return tmp;
+}
+
 #define LEXDEBUG 0
 
 /* Make lexers for shifts 0, 1 and 2. */
diff --git a/src/lexer.h b/src/lexer.h
index 7bb5f8bb0f3e6fcf4742147aaa0d7ef34ad4262b..9d819e34330bbfe34ec7bbafcc36b930343b120c 100644
--- a/src/lexer.h
+++ b/src/lexer.h
@@ -54,7 +54,7 @@
 #define low_yylex low_yylex0
 #define lex_atoi atoi
 #define lex_strtol strtol
-#define lex_strtod my_strtod
+#define lex_strtod mymy_strtod
 #define lex_isidchar isidchar
 
 #else /* SHIFT != 0 */
@@ -144,11 +144,16 @@ static long lex_strtol(char *buf, char **end, int base)
   return ret;
 }
 
-static double lex_strtod(char *buf, char **end)
+static FLOAT_TYPE lex_strtod(char *buf, char **end)
 {
   PCHARP foo;
+#if SIZEOF_FLOAT_TYPE > SIZEOF_DOUBLE
+  FLOAT_TYPE ret;
+  ret=STRTOLD_PCHARP(MKPCHARP(buf,SHIFT),&foo);
+#else
   double ret;
   ret=STRTOD_PCHARP(MKPCHARP(buf,SHIFT),&foo);
+#endif
   if(end) end[0]=(char *)foo.ptr;
   return ret;
 }
@@ -972,7 +977,7 @@ unknown_directive:
     case '5': case '6': case '7': case '8': case '9':
     {
       char *p1, *p2;
-      double f;
+      FLOAT_TYPE f;
       long l;
       struct svalue sval;
 
@@ -1026,10 +1031,10 @@ unknown_directive:
 	  }
 	}
 	free_svalue(&sval);
-	yylval->fnum=(FLOAT_TYPE)f;
+	yylval->fnum=f;
 #if 0
-	fprintf(stderr, "LEX: \"%.8s\" => %f, %f\n",
-		(char *)lex->pos, f, yylval->fnum);
+	fprintf(stderr, "LEX: \"%.8s\" => %"PRINTPIKEFLOAT"f\n",
+		(char *)lex->pos, f);
 #endif /* 0 */
 	lex->pos=p1;
 	if (lex_isidchar (LOOK())) {
diff --git a/src/stralloc.c b/src/stralloc.c
index 98331edf85941a00fa91da70e1e9739b23dbafba..2229bd74fbd617c2107cfbdab08835a3c018b9cf 100644
--- a/src/stralloc.c
+++ b/src/stralloc.c
@@ -3673,6 +3673,164 @@ PMOD_EXPORT double STRTOD_PCHARP(PCHARP nptr, PCHARP *endptr)
   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(PCHARP nptr, PCHARP *endptr)
+{
+  /* Note: Code duplication in strtod. */
+
+  register 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 (EXTRACT_PCHARP(s) <256 && 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 (EXTRACT_PCHARP(s)<256 && 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) <256 && tolower(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(struct pike_string *s,
 			   char **to_free)
diff --git a/src/stralloc.h b/src/stralloc.h
index 34cddba72b4152215cd861bf2c9e3d0554dc88e5..9e654f46b934779d3778a929569f20df40d3d7b2 100644
--- a/src/stralloc.h
+++ b/src/stralloc.h
@@ -459,6 +459,9 @@ PMOD_EXPORT int pcharp_to_svalue_inumber(struct svalue *r,
 					 ptrdiff_t maxlength);
 PMOD_EXPORT int convert_stack_top_string_to_inumber(int base);
 PMOD_EXPORT double STRTOD_PCHARP(PCHARP nptr, PCHARP *endptr);
+#if SIZEOF_FLOAT_TYPE > SIZEOF_DOUBLE
+PMOD_EXPORT long double STRTOLD_PCHARP(PCHARP nptr, PCHARP *endptr);
+#endif
 PMOD_EXPORT p_wchar0 *require_wstring0(struct pike_string *s,
                char **to_free);
 PMOD_EXPORT p_wchar1 *require_wstring1(struct pike_string *s,