changeset 8832:1466c973f476

Add support for 'long double' number output.
author Bruno Haible <bruno@clisp.org>
date Fri, 18 May 2007 18:26:01 +0000
parents d3f907c33d15
children e0764d111cfe
files ChangeLog doc/functions/fprintf.texi doc/functions/printf.texi doc/functions/snprintf.texi doc/functions/sprintf.texi doc/functions/vfprintf.texi doc/functions/vprintf.texi doc/functions/vsnprintf.texi doc/functions/vsprintf.texi lib/vasnprintf.c m4/fprintf-posix.m4 m4/printf.m4 m4/snprintf-posix.m4 m4/sprintf-posix.m4 m4/vasnprintf-posix.m4 m4/vasnprintf.m4 m4/vasprintf-posix.m4 m4/vfprintf-posix.m4 m4/vsnprintf-posix.m4 m4/vsprintf-posix.m4 modules/fprintf-posix modules/snprintf-posix modules/sprintf-posix modules/vasnprintf modules/vasnprintf-posix modules/vasprintf-posix modules/vfprintf-posix modules/vsnprintf-posix modules/vsprintf-posix
diffstat 29 files changed, 1783 insertions(+), 158 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,47 @@
+2007-05-18  Bruno Haible  <bruno@clisp.org>
+
+	Add support for 'long double' number output.
+	* m4/printf.m4 (gl_PRINTF_LONG_DOUBLE): New macro.
+	* lib/vasnprintf.c: Include math.h and float+.h.
+	(mp_limb_t): New type.
+	(GMP_LIMB_BITS): New macro.
+	(mp_twolimb_t): New type.
+	(GMP_TWOLIMB_BITS): New macro.
+	(mpn_t): New type.
+	(multiply, divide, convert_to_decimal, decode_long_double,
+	scale10_round_long_double, scale10_round_decimal_long_double,
+	floorlog10l): New functions.
+	(VASNPRINTF) [NEED_PRINTF_LONG_DOUBLE]: Implement 'long double' support
+	for the %f, %F, %e, %E, %g, %G directives.
+	* m4/vasnprintf.m4 (gl_PREREQ_VASNPRINTF_LONG_DOUBLE): New macro.
+	* m4/fprintf-posix.m4 (gl_FUNC_FPRINTF_POSIX): Invoke
+	gl_PRINTF_LONG_DOUBLE and test its result. Invoke
+	gl_PREREQ_VASNPRINTF_LONG_DOUBLE.
+	* m4/snprintf-posix.m4 (gl_FUNC_SNPRINTF_POSIX): Likewise.
+	* m4/sprintf-posix.m4 (gl_FUNC_SPRINTF_POSIX): Likewise.
+	* m4/vasnprintf-posix.m4 (gl_FUNC_VASNPRINTF_POSIX): Likewise.
+	* m4/vasprintf-posix.m4 (gl_FUNC_VASPRINTF_POSIX): Likewise.
+	* m4/vfprintf-posix.m4 (gl_FUNC_VFPRINTF_POSIX): Likewise.
+	* m4/vsnprintf-posix.m4 (gl_FUNC_VSNPRINTF_POSIX): Likewise.
+	* m4/vsprintf-posix.m4 (gl_FUNC_VSPRINTF_POSIX): Likewise.
+	* modules/fprintf-posix (Depends-on): Add frexpl-nolibm.
+	* modules/snprintf-posix (Depends-on): Likewise.
+	* modules/sprintf-posix (Depends-on): Likewise.
+	* modules/vasnprintf-posix (Depends-on): Likewise.
+	* modules/vasprintf-posix (Depends-on): Likewise.
+	* modules/vfprintf-posix (Depends-on): Likewise.
+	* modules/vsnprintf-posix (Depends-on): Likewise.
+	* modules/vsprintf-posix (Depends-on): Likewise.
+	* modules/vasnprintf (Files): Add lib/float+.h.
+	* doc/functions/fprintf.texi: Update.
+	* doc/functions/printf.texi: Update.
+	* doc/functions/snprintf.texi: Update.
+	* doc/functions/sprintf.texi: Update.
+	* doc/functions/vfprintf.texi: Update.
+	* doc/functions/vprintf.texi: Update.
+	* doc/functions/vsnprintf.texi: Update.
+	* doc/functions/vsprintf.texi: Update.
+
 2007-05-18  Bruno Haible  <bruno@clisp.org>
 
 	* lib/vasnprintf.c (USE_SNPRINTF): Define to 0 on BeOS.
--- a/doc/functions/fprintf.texi
+++ b/doc/functions/fprintf.texi
@@ -13,6 +13,9 @@
 @code{j}, @code{t}, @code{z}) on some platforms:
 AIX 5.1, HP-UX 11.23, IRIX 6.5, OSF/1 5.1, Solaris 9, Cygwin 2006, mingw, BeOS.
 @item
+printf of @samp{long double} numbers is unsupported on some platforms:
+mingw, BeOS.
+@item
 This function does not support the @samp{a} and @samp{A} directives on some
 platforms:
 glibc-2.3.6, MacOS X 10.3, NetBSD 3.0, OpenBSD 4.0, AIX 5.2, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin, mingw, BeOS.
@@ -34,7 +37,4 @@
 
 Portability problems not fixed by Gnulib:
 @itemize
-@item
-printf of @samp{long double} numbers is unsupported on some platforms:
-mingw.
 @end itemize
--- a/doc/functions/printf.texi
+++ b/doc/functions/printf.texi
@@ -13,6 +13,9 @@
 @code{j}, @code{t}, @code{z}) on some platforms:
 AIX 5.1, HP-UX 11.23, IRIX 6.5, OSF/1 5.1, Solaris 9, Cygwin 2006, mingw, BeOS.
 @item
+printf of @samp{long double} numbers is unsupported on some platforms:
+mingw, BeOS.
+@item
 This function does not support the @samp{a} and @samp{A} directives on some
 platforms:
 glibc-2.3.6, MacOS X 10.3, NetBSD 3.0, OpenBSD 4.0, AIX 5.2, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin, mingw, BeOS.
@@ -34,7 +37,4 @@
 
 Portability problems not fixed by Gnulib:
 @itemize
-@item
-printf of @samp{long double} numbers is unsupported on some platforms:
-mingw.
 @end itemize
--- a/doc/functions/snprintf.texi
+++ b/doc/functions/snprintf.texi
@@ -20,6 +20,9 @@
 @code{j}, @code{t}, @code{z}) on some platforms:
 AIX 5.1, HP-UX 11.23, IRIX 6.5, OSF/1 5.1, Solaris 9, Cygwin 2006, mingw, BeOS.
 @item
+printf of @samp{long double} numbers is unsupported on some platforms:
+mingw, BeOS.
+@item
 This function does not support the @samp{a} and @samp{A} directives on some
 platforms:
 glibc-2.3.6, MacOS X 10.3, NetBSD 3.0, OpenBSD 4.0, AIX 5.2, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin, mingw, BeOS.
@@ -54,7 +57,4 @@
 
 Portability problems not fixed by Gnulib:
 @itemize
-@item
-printf of @samp{long double} numbers is unsupported on some platforms:
-mingw.
 @end itemize
--- a/doc/functions/sprintf.texi
+++ b/doc/functions/sprintf.texi
@@ -13,6 +13,9 @@
 @code{j}, @code{t}, @code{z}) on some platforms:
 AIX 5.1, HP-UX 11.23, IRIX 6.5, OSF/1 5.1, Solaris 9, Cygwin 2006, mingw, BeOS.
 @item
+printf of @samp{long double} numbers is unsupported on some platforms:
+mingw, BeOS.
+@item
 This function does not support the @samp{a} and @samp{A} directives on some
 platforms:
 glibc-2.3.6, MacOS X 10.3, NetBSD 3.0, OpenBSD 4.0, AIX 5.2, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin, mingw, BeOS.
@@ -34,7 +37,4 @@
 
 Portability problems not fixed by Gnulib:
 @itemize
-@item
-printf of @samp{long double} numbers is unsupported on some platforms:
-mingw.
 @end itemize
--- a/doc/functions/vfprintf.texi
+++ b/doc/functions/vfprintf.texi
@@ -13,6 +13,9 @@
 @code{j}, @code{t}, @code{z}) on some platforms:
 AIX 5.1, HP-UX 11.23, IRIX 6.5, OSF/1 5.1, Solaris 9, Cygwin 2006, mingw, BeOS.
 @item
+printf of @samp{long double} numbers is unsupported on some platforms:
+mingw, BeOS.
+@item
 This function does not support the @samp{a} and @samp{A} directives on some
 platforms:
 glibc-2.3.6, MacOS X 10.3, NetBSD 3.0, OpenBSD 4.0, AIX 5.2, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin, mingw, BeOS.
@@ -34,7 +37,4 @@
 
 Portability problems not fixed by Gnulib:
 @itemize
-@item
-printf of @samp{long double} numbers is unsupported on some platforms:
-mingw.
 @end itemize
--- a/doc/functions/vprintf.texi
+++ b/doc/functions/vprintf.texi
@@ -13,6 +13,9 @@
 @code{j}, @code{t}, @code{z}) on some platforms:
 AIX 5.1, HP-UX 11.23, IRIX 6.5, OSF/1 5.1, Solaris 9, Cygwin 2006, mingw, BeOS.
 @item
+printf of @samp{long double} numbers is unsupported on some platforms:
+mingw, BeOS.
+@item
 This function does not support the @samp{a} and @samp{A} directives on some
 platforms:
 glibc-2.3.6, MacOS X 10.3, NetBSD 3.0, OpenBSD 4.0, AIX 5.2, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin, mingw, BeOS.
@@ -34,7 +37,4 @@
 
 Portability problems not fixed by Gnulib:
 @itemize
-@item
-printf of @samp{long double} numbers is unsupported on some platforms:
-mingw.
 @end itemize
--- a/doc/functions/vsnprintf.texi
+++ b/doc/functions/vsnprintf.texi
@@ -20,6 +20,9 @@
 @code{j}, @code{t}, @code{z}) on some platforms:
 AIX 5.1, HP-UX 11.23, IRIX 6.5, OSF/1 5.1, Solaris 9, Cygwin 2006, mingw, BeOS.
 @item
+printf of @samp{long double} numbers is unsupported on some platforms:
+mingw, BeOS.
+@item
 This function does not support the @samp{a} and @samp{A} directives on some
 platforms:
 glibc-2.3.6, MacOS X 10.3, NetBSD 3.0, OpenBSD 4.0, AIX 5.2, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin, mingw, BeOS.
@@ -54,7 +57,4 @@
 
 Portability problems not fixed by Gnulib:
 @itemize
-@item
-printf of @samp{long double} numbers is unsupported on some platforms:
-mingw.
 @end itemize
--- a/doc/functions/vsprintf.texi
+++ b/doc/functions/vsprintf.texi
@@ -13,6 +13,9 @@
 @code{j}, @code{t}, @code{z}) on some platforms:
 AIX 5.1, HP-UX 11.23, IRIX 6.5, OSF/1 5.1, Solaris 9, Cygwin 2006, mingw, BeOS.
 @item
+printf of @samp{long double} numbers is unsupported on some platforms:
+mingw, BeOS.
+@item
 This function does not support the @samp{a} and @samp{A} directives on some
 platforms:
 glibc-2.3.6, MacOS X 10.3, NetBSD 3.0, OpenBSD 4.0, AIX 5.2, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin, mingw, BeOS.
@@ -34,7 +37,4 @@
 
 Portability problems not fixed by Gnulib:
 @itemize
-@item
-printf of @samp{long double} numbers is unsupported on some platforms:
-mingw.
 @end itemize
--- a/lib/vasnprintf.c
+++ b/lib/vasnprintf.c
@@ -62,6 +62,11 @@
 # include "fpucw.h"
 #endif
 
+#if NEED_PRINTF_LONG_DOUBLE && !defined IN_LIBINTL
+# include <math.h>
+# include "float+.h"
+#endif
+
 /* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW.  */
 #ifndef EOVERFLOW
 # define EOVERFLOW E2BIG
@@ -159,6 +164,950 @@
 # endif
 #endif
 
+#if NEED_PRINTF_LONG_DOUBLE && !defined IN_LIBINTL
+
+/* Converting 'long double' to decimal without rare rounding bugs requires
+   real bignums.  We use the naming conventions of GNU gmp, but vastly simpler
+   (and slower) algorithms.  */
+
+typedef unsigned int mp_limb_t;
+# define GMP_LIMB_BITS 32
+typedef int mp_limb_verify[2 * (sizeof (mp_limb_t) * CHAR_BIT == GMP_LIMB_BITS) - 1];
+
+typedef unsigned long long mp_twolimb_t;
+# define GMP_TWOLIMB_BITS 64
+typedef int mp_twolimb_verify[2 * (sizeof (mp_twolimb_t) * CHAR_BIT == GMP_TWOLIMB_BITS) - 1];
+
+/* Representation of a bignum >= 0.  */
+typedef struct
+{
+  size_t nlimbs;
+  mp_limb_t *limbs; /* Bits in little-endian order, allocated with malloc().  */
+} mpn_t;
+
+/* Compute the product of two bignums >= 0.
+   Return the allocated memory in case of success, NULL in case of memory
+   allocation failure.  */
+static void *
+multiply (mpn_t src1, mpn_t src2, mpn_t *dest)
+{
+  const mp_limb_t *p1;
+  const mp_limb_t *p2;
+  size_t len1;
+  size_t len2;
+
+  if (src1.nlimbs <= src2.nlimbs)
+    {
+      len1 = src1.nlimbs;
+      p1 = src1.limbs;
+      len2 = src2.nlimbs;
+      p2 = src2.limbs;
+    }
+  else
+    {
+      len1 = src2.nlimbs;
+      p1 = src2.limbs;
+      len2 = src1.nlimbs;
+      p2 = src1.limbs;
+    }
+  /* Now 0 <= len1 <= len2.  */
+  if (len1 == 0)
+    {
+      /* src1 or src2 is zero.  */
+      dest->nlimbs = 0;
+      dest->limbs = (mp_limb_t *) malloc (1);
+    }
+  else
+    {
+      /* Here 1 <= len1 <= len2.  */
+      size_t dlen;
+      mp_limb_t *dp;
+      size_t k, i, j;
+
+      dlen = len1 + len2;
+      dp = (mp_limb_t *) malloc (dlen * sizeof (mp_limb_t));
+      if (dp == NULL)
+	return NULL;
+      for (k = len2; k > 0; )
+	dp[--k] = 0;
+      for (i = 0; i < len1; i++)
+	{
+	  mp_limb_t digit1 = p1[i];
+	  mp_twolimb_t carry = 0;
+	  for (j = 0; j < len2; j++)
+	    {
+	      mp_limb_t digit2 = p2[j];
+	      carry += (mp_twolimb_t) digit1 * (mp_twolimb_t) digit2;
+	      carry += dp[i + j];
+	      dp[i + j] = (mp_limb_t) carry;
+	      carry = carry >> GMP_LIMB_BITS;
+	    }
+	  dp[i + len2] = (mp_limb_t) carry;
+	}
+      /* Normalise.  */
+      while (dlen > 0 && dp[dlen - 1] == 0)
+	dlen--;
+      dest->nlimbs = dlen;
+      dest->limbs = dp;
+    }
+  return dest->limbs;
+}
+
+/* Compute the quotient of a bignum a >= 0 and a bignum b > 0.
+   a is written as  a = q * b + r  with 0 <= r < b.  q is the quotient, r
+   the remainder.
+   Finally, round-to-even is performed: If r > b/2 or if r = b/2 and q is odd,
+   q is incremented.
+   Return the allocated memory in case of success, NULL in case of memory
+   allocation failure.  */
+static void *
+divide (mpn_t a, mpn_t b, mpn_t *q)
+{
+  /* Algorithm:
+     First normalise a and b: a=[a[m-1],...,a[0]], b=[b[n-1],...,b[0]]
+     with m>=0 and n>0 (in base beta = 2^GMP_LIMB_BITS).
+     If m<n, then q:=0 and r:=a.
+     If m>=n=1, perform a single-precision division:
+       r:=0, j:=m,
+       while j>0 do
+         {Here (q[m-1]*beta^(m-1)+...+q[j]*beta^j) * b[0] + r*beta^j =
+               = a[m-1]*beta^(m-1)+...+a[j]*beta^j und 0<=r<b[0]<beta}
+         j:=j-1, r:=r*beta+a[j], q[j]:=floor(r/b[0]), r:=r-b[0]*q[j].
+       Normalise [q[m-1],...,q[0]], yields q.
+     If m>=n>1, perform a multiple-precision division:
+       We have a/b < beta^(m-n+1).
+       s:=intDsize-1-(hightest bit in b[n-1]), 0<=s<intDsize.
+       Shift a and b left by s bits, copying them. r:=a.
+       r=[r[m],...,r[0]], b=[b[n-1],...,b[0]] with b[n-1]>=beta/2.
+       For j=m-n,...,0: {Here 0 <= r < b*beta^(j+1).}
+         Compute q* :
+           q* := floor((r[j+n]*beta+r[j+n-1])/b[n-1]).
+           In case of overflow (q* >= beta) set q* := beta-1.
+           Compute c2 := ((r[j+n]*beta+r[j+n-1]) - q* * b[n-1])*beta + r[j+n-2]
+           and c3 := b[n-2] * q*.
+           {We have 0 <= c2 < 2*beta^2, even 0 <= c2 < beta^2 if no overflow
+            occurred.  Furthermore 0 <= c3 < beta^2.
+            If there was overflow and
+            r[j+n]*beta+r[j+n-1] - q* * b[n-1] >= beta, i.e. c2 >= beta^2,
+            the next test can be skipped.}
+           While c3 > c2, {Here 0 <= c2 < c3 < beta^2}
+             Put q* := q* - 1, c2 := c2 + b[n-1]*beta, c3 := c3 - b[n-2].
+           If q* > 0:
+             Put r := r - b * q* * beta^j. In detail:
+               [r[n+j],...,r[j]] := [r[n+j],...,r[j]] - q* * [b[n-1],...,b[0]].
+               hence: u:=0, for i:=0 to n-1 do
+                              u := u + q* * b[i],
+                              r[j+i]:=r[j+i]-(u mod beta) (+ beta, if carry),
+                              u:=u div beta (+ 1, if carry in subtraction)
+                      r[n+j]:=r[n+j]-u.
+               {Since always u = (q* * [b[i-1],...,b[0]] div beta^i) + 1
+                               < q* + 1 <= beta,
+                the carry u does not overflow.}
+             If a negative carry occurs, put q* := q* - 1
+               and [r[n+j],...,r[j]] := [r[n+j],...,r[j]] + [0,b[n-1],...,b[0]].
+         Set q[j] := q*.
+       Normalise [q[m-n],..,q[0]]; this yields the quotient q.
+       Shift [r[n-1],...,r[0]] right by s bits and normalise; this yields the
+       rest r.
+       The room for q[j] can be allocated at the memory location of r[n+j].
+     Finally, round-to-even:
+       Shift r left by 1 bit.
+       If r > b or if r = b and q[0] is odd, q := q+1.
+   */
+  const mp_limb_t *a_ptr = a.limbs;
+  size_t a_len = a.nlimbs;
+  const mp_limb_t *b_ptr = b.limbs;
+  size_t b_len = b.nlimbs;
+  mp_limb_t *roomptr;
+  mp_limb_t *tmp_roomptr = NULL;
+  mp_limb_t *q_ptr;
+  size_t q_len;
+  mp_limb_t *r_ptr;
+  size_t r_len;
+
+  /* Allocate room for a_len+2 digits.
+     (Need a_len+1 digits for the real division and 1 more digit for the
+     final rounding of q.)  */
+  roomptr = (mp_limb_t *) malloc ((a_len + 2) * sizeof (mp_limb_t));
+  if (roomptr == NULL)
+    return NULL;
+
+  /* Normalise a.  */
+  while (a_len > 0 && a_ptr[a_len - 1] == 0)
+    a_len--;
+
+  /* Normalise b.  */
+  for (;;)
+    {
+      if (b_len == 0)
+	/* Division by zero.  */
+	abort ();
+      if (b_ptr[b_len - 1] == 0)
+	b_len--;
+      else
+	break;
+    }
+
+  /* Here m = a_len >= 0 and n = b_len > 0.  */
+
+  if (a_len < b_len)
+    {
+      /* m<n: trivial case.  q=0, r := copy of a.  */
+      r_ptr = roomptr;
+      r_len = a_len;
+      memcpy (r_ptr, a_ptr, a_len * sizeof (mp_limb_t));
+      q_ptr = roomptr + a_len;
+      q_len = 0;
+    }
+  else if (b_len == 1)
+    {
+      /* n=1: single precision division.
+	 beta^(m-1) <= a < beta^m  ==>  beta^(m-2) <= a/b < beta^m  */
+      r_ptr = roomptr;
+      q_ptr = roomptr + 1;
+      {
+	mp_limb_t den = b_ptr[0];
+	mp_limb_t remainder = 0;
+	const mp_limb_t *sourceptr = a_ptr + a_len;
+	mp_limb_t *destptr = q_ptr + a_len;
+	size_t count;
+	for (count = a_len; count > 0; count--)
+	  {
+	    mp_twolimb_t num =
+	      ((mp_twolimb_t) remainder << GMP_LIMB_BITS) | *--sourceptr;
+	    *--destptr = num / den;
+	    remainder = num % den;
+	  }
+	/* Normalise and store r.  */
+	if (remainder > 0)
+	  {
+	    r_ptr[0] = remainder;
+	    r_len = 1;
+	  }
+	else
+	  r_len = 0;
+	/* Normalise q.  */
+	q_len = a_len;
+	if (q_ptr[q_len - 1] == 0)
+	  q_len--;
+      }
+    }
+  else
+    {
+      /* n>1: multiple precision division.
+	 beta^(m-1) <= a < beta^m, beta^(n-1) <= b < beta^n  ==>
+	 beta^(m-n-1) <= a/b < beta^(m-n+1).  */
+      /* Determine s.  */
+      size_t s;
+      {
+	mp_limb_t msd = b_ptr[b_len - 1]; /* = b[n-1], > 0 */
+	s = 31;
+	if (msd >= 0x10000)
+	  {
+	    msd = msd >> 16;
+	    s -= 16;
+	  }
+	if (msd >= 0x100)
+	  {
+	    msd = msd >> 8;
+	    s -= 8;
+	  }
+	if (msd >= 0x10)
+	  {
+	    msd = msd >> 4;
+	    s -= 4;
+	  }
+	if (msd >= 0x4)
+	  {
+	    msd = msd >> 2;
+	    s -= 2;
+	  }
+	if (msd >= 0x2)
+	  {
+	    msd = msd >> 1;
+	    s -= 1;
+	  }
+      }
+      /* 0 <= s < GMP_LIMB_BITS.
+	 Copy b, shifting it left by s bits.  */
+      if (s > 0)
+	{
+	  tmp_roomptr = (mp_limb_t *) malloc (b_len * sizeof (mp_limb_t));
+	  if (tmp_roomptr == NULL)
+	    {
+	      free (roomptr);
+	      return NULL;
+	    }
+	  {
+	    const mp_limb_t *sourceptr = b_ptr;
+	    mp_limb_t *destptr = tmp_roomptr;
+	    mp_twolimb_t accu = 0;
+	    size_t count;
+	    for (count = b_len; count > 0; count--)
+	      {
+		accu += (mp_twolimb_t) *sourceptr++ << s;
+		*destptr++ = (mp_limb_t) accu;
+		accu = accu >> GMP_LIMB_BITS;
+	      }
+	    /* accu must be zero, since that was how s was determined.  */
+	    if (accu != 0)
+	      abort ();
+	  }
+	  b_ptr = tmp_roomptr;
+	}
+      /* Copy a, shifting it left by s bits, yields r.
+	 Memory layout:
+	 At the beginning: r = roomptr[0..a_len],
+	 at the end: r = roomptr[0..b_len-1], q = roomptr[b_len..a_len]  */
+      r_ptr = roomptr;
+      if (s == 0)
+	{
+	  memcpy (r_ptr, a_ptr, a_len * sizeof (mp_limb_t));
+	  r_ptr[a_len] = 0;
+	}
+      else
+	{
+	  const mp_limb_t *sourceptr = a_ptr;
+	  mp_limb_t *destptr = r_ptr;
+	  mp_twolimb_t accu = 0;
+	  size_t count;
+	  for (count = a_len; count > 0; count--)
+	    {
+	      accu += (mp_twolimb_t) *sourceptr++ << s;
+	      *destptr++ = (mp_limb_t) accu;
+	      accu = accu >> GMP_LIMB_BITS;
+	    }
+	  *destptr++ = (mp_limb_t) accu;
+	}
+      q_ptr = roomptr + b_len;
+      q_len = a_len - b_len + 1; /* q will have m-n+1 limbs */
+      {
+	size_t j = a_len - b_len; /* m-n */
+	mp_limb_t b_msd = b_ptr[b_len - 1]; /* b[n-1] */
+	mp_limb_t b_2msd = b_ptr[b_len - 2]; /* b[n-2] */
+	mp_twolimb_t b_msdd = /* b[n-1]*beta+b[n-2] */
+	  ((mp_twolimb_t) b_msd << GMP_LIMB_BITS) | b_2msd;
+	/* Division loop, traversed m-n+1 times.
+	   j counts down, b is unchanged, beta/2 <= b[n-1] < beta.  */
+	for (;;)
+	  {
+	    mp_limb_t q_star;
+	    mp_limb_t c1;
+	    if (r_ptr[j + b_len] < b_msd) /* r[j+n] < b[n-1] ? */
+	      {
+		/* Divide r[j+n]*beta+r[j+n-1] by b[n-1], no overflow.  */
+		mp_twolimb_t num =
+		  ((mp_twolimb_t) r_ptr[j + b_len] << GMP_LIMB_BITS)
+		  | r_ptr[j + b_len - 1];
+		q_star = num / b_msd;
+		c1 = num % b_msd;
+	      }
+	    else
+	      {
+		/* Overflow, hence r[j+n]*beta+r[j+n-1] >= beta*b[n-1].  */
+		q_star = (mp_limb_t)~(mp_limb_t)0; /* q* = beta-1 */
+		/* Test whether r[j+n]*beta+r[j+n-1] - (beta-1)*b[n-1] >= beta
+		   <==> r[j+n]*beta+r[j+n-1] + b[n-1] >= beta*b[n-1]+beta
+		   <==> b[n-1] < floor((r[j+n]*beta+r[j+n-1]+b[n-1])/beta)
+		        {<= beta !}.
+		   If yes, jump directly to the subtraction loop.
+		   (Otherwise, r[j+n]*beta+r[j+n-1] - (beta-1)*b[n-1] < beta
+		    <==> floor((r[j+n]*beta+r[j+n-1]+b[n-1])/beta) = b[n-1] ) */
+		if (r_ptr[j + b_len] > b_msd
+		    || (c1 = r_ptr[j + b_len - 1] + b_msd) < b_msd)
+		  /* r[j+n] >= b[n-1]+1 or
+		     r[j+n] = b[n-1] and the addition r[j+n-1]+b[n-1] gives a
+		     carry.  */
+		  goto subtract;
+	      }
+	    /* q_star = q*,
+	       c1 = (r[j+n]*beta+r[j+n-1]) - q* * b[n-1] (>=0, <beta).  */
+	    {
+	      mp_twolimb_t c2 = /* c1*beta+r[j+n-2] */
+		((mp_twolimb_t) c1 << GMP_LIMB_BITS) | r_ptr[j + b_len - 2];
+	      mp_twolimb_t c3 = /* b[n-2] * q* */
+		(mp_twolimb_t) b_2msd * (mp_twolimb_t) q_star;
+	      /* While c2 < c3, increase c2 and decrease c3.
+		 Consider c3-c2.  While it is > 0, decrease it by
+		 b[n-1]*beta+b[n-2].  Because of b[n-1]*beta+b[n-2] >= beta^2/2
+		 this can happen only twice.  */
+	      if (c3 > c2)
+		{
+		  q_star = q_star - 1; /* q* := q* - 1 */
+		  if (c3 - c2 > b_msdd)
+		    q_star = q_star - 1; /* q* := q* - 1 */
+		}
+	    }
+	    if (q_star > 0)
+	      subtract:
+	      {
+		/* Subtract r := r - b * q* * beta^j.  */
+		mp_limb_t cr;
+		{
+		  const mp_limb_t *sourceptr = b_ptr;
+		  mp_limb_t *destptr = r_ptr + j;
+		  mp_twolimb_t carry = 0;
+		  size_t count;
+		  for (count = b_len; count > 0; count--)
+		    {
+		      /* Here 0 <= carry <= q*.  */
+		      carry =
+			carry
+			+ (mp_twolimb_t) q_star * (mp_twolimb_t) *sourceptr++
+			+ (mp_limb_t) ~(*destptr);
+		      /* Here 0 <= carry <= beta*q* + beta-1.  */
+		      *destptr++ = ~(mp_limb_t) carry;
+		      carry = carry >> GMP_LIMB_BITS; /* <= q* */
+		    }
+		  cr = (mp_limb_t) carry;
+		}
+		/* Subtract cr from r_ptr[j + b_len], then forget about
+		   r_ptr[j + b_len].  */
+		if (cr > r_ptr[j + b_len])
+		  {
+		    /* Subtraction gave a carry.  */
+		    q_star = q_star - 1; /* q* := q* - 1 */
+		    /* Add b back.  */
+		    {
+		      const mp_limb_t *sourceptr = b_ptr;
+		      mp_limb_t *destptr = r_ptr + j;
+		      mp_limb_t carry = 0;
+		      size_t count;
+		      for (count = b_len; count > 0; count--)
+			{
+			  mp_limb_t source1 = *sourceptr++;
+			  mp_limb_t source2 = *destptr;
+			  *destptr++ = source1 + source2 + carry;
+			  carry =
+			    (carry
+			     ? source1 >= (mp_limb_t) ~source2
+			     : source1 > (mp_limb_t) ~source2);
+			}
+		    }
+		    /* Forget about the carry and about r[j+n].  */
+		  }
+	      }
+	    /* q* is determined.  Store it as q[j].  */
+	    q_ptr[j] = q_star;
+	    if (j == 0)
+	      break;
+	    j--;
+	  }
+      }
+      r_len = b_len;
+      /* Normalise q.  */
+      if (q_ptr[q_len - 1] == 0)
+	q_len--;
+# if 0 /* Not needed here, since we need r only to compare it with b/2, and
+	  b is shifted left by s bits.  */
+      /* Shift r right by s bits.  */
+      if (s > 0)
+	{
+	  mp_limb_t ptr = r_ptr + r_len;
+	  mp_twolimb_t accu = 0;
+	  size_t count;
+	  for (count = r_len; count > 0; count--)
+	    {
+	      accu = (mp_twolimb_t) (mp_limb_t) accu << GMP_LIMB_BITS;
+	      accu += (mp_twolimb_t) *--ptr << (GMP_LIMB_BITS - s);
+	      *ptr = (mp_limb_t) (accu >> GMP_LIMB_BITS);
+	    }
+	}
+# endif
+      /* Normalise r.  */
+      while (r_len > 0 && r_ptr[r_len - 1] == 0)
+	r_len--;
+    }
+  /* Compare r << 1 with b.  */
+  if (r_len > b_len)
+    goto increment_q;
+  {
+    size_t i;
+    for (i = b_len; i > 0; )
+      {
+	i--;
+	{
+	  mp_limb_t r_i =
+	    (i + 1 < r_len ? r_ptr[i + 1] >> (GMP_LIMB_BITS - 1) : 0)
+	    | (i < r_len ? r_ptr[i] << 1 : 0);
+	  mp_limb_t b_i = b_ptr[i];
+	  if (r_i > b_i)
+	    goto increment_q;
+	  if (r_i < b_i)
+	    goto keep_q;
+	}
+      }
+  }
+  if (q_len > 0 && ((q_ptr[0] & 1) != 0))
+    /* q is odd.  */
+    increment_q:
+    {
+      size_t i;
+      for (i = 0; i < q_len; i++)
+	if (++(q_ptr[i]) != 0)
+	  goto keep_q;
+      q_ptr[q_len++] = 1;
+    }
+  keep_q:
+  if (tmp_roomptr != NULL)
+    free (tmp_roomptr);
+  q->limbs = q_ptr;
+  q->nlimbs = q_len;
+  return roomptr;
+}
+
+/* Convert a bignum a >= 0 to decimal representation.
+   Destroys the contents of a.
+   Return the allocated memory - containing the decimal digits in low-to-high
+   order, terminated with a NUL character - in case of success, NULL in case
+   of memory allocation failure.  */
+static char *
+convert_to_decimal (mpn_t a)
+{
+  mp_limb_t *a_ptr = a.limbs;
+  size_t a_len = a.nlimbs;
+  /* 0.03345 is slightly larger than log(2)/(9*log(10)).  */
+  size_t c_len = 9 * ((size_t)(a_len * (GMP_LIMB_BITS * 0.03345f)) + 1);
+  char *c_ptr = (char *) malloc (c_len);
+  if (c_ptr != NULL)
+    {
+      char *d_ptr = c_ptr;
+      while (a_len > 0)
+	{
+	  /* Divide a by 10^9, in-place.  */
+	  mp_limb_t remainder = 0;
+	  mp_limb_t *ptr = a_ptr + a_len;
+	  size_t count;
+	  for (count = a_len; count > 0; count--)
+	    {
+	      mp_twolimb_t num =
+		((mp_twolimb_t) remainder << GMP_LIMB_BITS) | *--ptr;
+	      *ptr = num / 1000000000;
+	      remainder = num % 1000000000;
+	    }
+	  /* Store the remainder as 9 decimal digits.  */
+	  for (count = 9; count > 0; count--)
+	    {
+	      *d_ptr++ = '0' + (remainder % 10);
+	      remainder = remainder / 10;
+	    }
+	  /* Normalize a.  */
+	  if (a_ptr[a_len - 1] == 0)
+	    a_len--;
+	}
+      /* Remove leading zeroes.  */
+      while (d_ptr > c_ptr && d_ptr[-1] == '0')
+	d_ptr--;
+      /* But keep at least one zero.  */
+      if (d_ptr == c_ptr)
+	*d_ptr++ = '0';
+      /* Terminate the string.  */
+      *d_ptr = '\0';
+    }
+  return c_ptr;
+}
+
+/* Assuming x is finite and >= 0:
+   write x as x = 2^e * m, where m is a bignum.
+   Return the allocated memory in case of success, NULL in case of memory
+   allocation failure.  */
+static void *
+decode_long_double (long double x, int *ep, mpn_t *mp)
+{
+  mpn_t m;
+  int exp;
+  long double y;
+  size_t i;
+
+  /* Allocate memory for result.  */
+  m.nlimbs = (LDBL_MANT_BIT + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS;
+  m.limbs = (mp_limb_t *) malloc (m.nlimbs * sizeof (mp_limb_t));
+  if (m.limbs == NULL)
+    return NULL;
+  /* Split into exponential part and mantissa.  */
+  y = frexpl (x, &exp);
+  if (!(y >= 0.0L && y < 1.0L))
+    abort ();
+  /* x = 2^exp * y = 2^(exp - LDBL_MANT_BIT) * (y * LDBL_MANT_BIT), and the
+     latter is an integer.  */
+  /* Convert the mantissa (y * LDBL_MANT_BIT) to a sequence of limbs.
+     I'm not sure whether it's safe to cast a 'long double' value between
+     2^31 and 2^32 to 'unsigned int', therefore play safe and cast only
+     'long double' values between 0 and 2^16 (to 'unsigned int' or 'int',
+     doesn't matter).  */
+# if (LDBL_MANT_BIT % GMP_LIMB_BITS) != 0
+#  if (LDBL_MANT_BIT % GMP_LIMB_BITS) > GMP_LIMB_BITS / 2
+    {
+      mp_limb_t hi, lo;
+      y *= (mp_limb_t) 1 << (LDBL_MANT_BIT % (GMP_LIMB_BITS / 2));
+      hi = (int) y;
+      y -= hi;
+      if (!(y >= 0.0L && y < 1.0L))
+	abort ();
+      y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2);
+      lo = (int) y;
+      y -= lo;
+      if (!(y >= 0.0L && y < 1.0L))
+	abort ();
+      m.limbs[LDBL_MANT_BIT / GMP_LIMB_BITS] = (hi << (GMP_LIMB_BITS / 2)) | lo;
+    }
+#  else
+    {
+      mp_limb_t d;
+      y *= (mp_limb_t) 1 << (LDBL_MANT_BIT % GMP_LIMB_BITS);
+      d = (int) y;
+      y -= d;
+      if (!(y >= 0.0L && y < 1.0L))
+	abort ();
+      m.limbs[LDBL_MANT_BIT / GMP_LIMB_BITS] = d;
+    }
+#  endif
+# endif
+  for (i = LDBL_MANT_BIT / GMP_LIMB_BITS; i > 0; )
+    {
+      mp_limb_t hi, lo;
+      y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2);
+      hi = (int) y;
+      y -= hi;
+      if (!(y >= 0.0L && y < 1.0L))
+	abort ();
+      y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2);
+      lo = (int) y;
+      y -= lo;
+      if (!(y >= 0.0L && y < 1.0L))
+	abort ();
+      m.limbs[--i] = (hi << (GMP_LIMB_BITS / 2)) | lo;
+    }
+  if (!(y == 0.0L))
+    abort ();
+  /* Normalise.  */
+  while (m.nlimbs > 0 && m.limbs[m.nlimbs - 1] == 0)
+    m.nlimbs--;
+  *mp = m;
+  *ep = exp - LDBL_MANT_BIT;
+  return m.limbs;
+}
+
+/* Assuming x is finite and >= 0, and n is an integer:
+   Compute y = round (x * 10^n) as a bignum >= 0.
+   Return the allocated memory in case of success, NULL in case of memory
+   allocation failure.  */
+static void *
+scale10_round_long_double (long double x, int n, mpn_t *yp)
+{
+  int e;
+  mpn_t m;
+  void *memory = decode_long_double (x, &e, &m);
+  int s;
+  unsigned int abs_n;
+  unsigned int abs_s;
+  mp_limb_t *pow5_ptr;
+  size_t pow5_len;
+  unsigned int s_limbs;
+  unsigned int s_bits;
+  mpn_t pow5;
+
+  if (memory == NULL)
+    return NULL;
+  /* x = 2^e * m, hence
+     y = round (2^e * 10^n * m) = round (2^(e+n) * 5^n * m)
+       = round (2^s * 5^n * m).  */
+  s = e + n;
+  /* Compute 5^|n|, possibly shifted by |s| bits if n and s have the same
+     sign.  2.322 is slightly larger than log(5)/log(2).  */
+  abs_n = (n >= 0 ? n : -n);
+  abs_s = (s >= 0 ? s : -s);
+  pow5_ptr = (mp_limb_t *) malloc (((int)(abs_n * (2.322f / GMP_LIMB_BITS)) + 1
+				    + abs_s / GMP_LIMB_BITS + 1)
+				   * sizeof (mp_limb_t));
+  if (pow5_ptr == NULL)
+    {
+      free (memory);
+      return NULL;
+    }
+  /* Initialize with 1.  */
+  pow5_ptr[0] = 1;
+  pow5_len = 1;
+  /* Multiply with 5^|n|.  */
+  if (abs_n > 0)
+    {
+      static mp_limb_t const small_pow5[13 + 1] =
+	{
+	  1, 5, 25, 125, 625, 3125, 15625, 78125, 390625, 1953125, 9765625,
+	  48828125, 244140625, 1220703125
+	};
+      unsigned int n13;
+      for (n13 = 0; n13 <= abs_n; n13 += 13)
+	{
+	  mp_limb_t digit1 = small_pow5[n13 + 13 <= abs_n ? 13 : abs_n - n13];
+	  size_t j;
+	  mp_twolimb_t carry = 0;
+	  for (j = 0; j < pow5_len; j++)
+	    {
+	      mp_limb_t digit2 = pow5_ptr[j];
+	      carry += (mp_twolimb_t) digit1 * (mp_twolimb_t) digit2;
+	      pow5_ptr[j] = (mp_limb_t) carry;
+	      carry = carry >> GMP_LIMB_BITS;
+	    }
+	  if (carry > 0)
+	    pow5_ptr[pow5_len++] = (mp_limb_t) carry;
+	}
+    }
+  s_limbs = abs_s / GMP_LIMB_BITS;
+  s_bits = abs_s % GMP_LIMB_BITS;
+  if (n >= 0 ? s >= 0 : s <= 0)
+    {
+      /* Multiply with 2^|s|.  */
+      if (s_bits > 0)
+	{
+	  mp_limb_t *ptr = pow5_ptr;
+	  mp_twolimb_t accu = 0;
+	  size_t count;
+	  for (count = pow5_len; count > 0; count--)
+	    {
+	      accu += (mp_twolimb_t) *ptr << s_bits;
+	      *ptr++ = (mp_limb_t) accu;
+	      accu = accu >> GMP_LIMB_BITS;
+	    }
+	  if (accu > 0)
+	    {
+	      *ptr = (mp_limb_t) accu;
+	      pow5_len++;
+	    }
+	}
+      if (s_limbs > 0)
+	{
+	  size_t count;
+	  for (count = pow5_len; count > 0;)
+	    {
+	      count--;
+	      pow5_ptr[s_limbs + count] = pow5_ptr[count];
+	    }
+	  for (count = s_limbs; count > 0;)
+	    {
+	      count--;
+	      pow5_ptr[count] = 0;
+	    }
+	  pow5_len += s_limbs;
+	}
+      pow5.limbs = pow5_ptr;
+      pow5.nlimbs = pow5_len;
+      if (n >= 0)
+	{
+	  /* Multiply m with pow5.  No division needed.  */
+	  void *result_memory = multiply (m, pow5, yp);
+	  free (pow5_ptr);
+	  free (memory);
+	  return result_memory;
+	}
+      else
+	{
+	  /* Divide m by pow5 and round.  */
+	  void *result_memory = divide (m, pow5, yp);
+	  free (pow5_ptr);
+	  free (memory);
+	  return result_memory;
+	}
+    }
+  else
+    {
+      pow5.limbs = pow5_ptr;
+      pow5.nlimbs = pow5_len;
+      if (n >= 0)
+	{
+	  /* n >= 0, s < 0.
+	     Multiply m with pow5, then divide by 2^|s|.  */
+	  mpn_t numerator;
+	  mpn_t denominator;
+	  void *tmp_memory;
+	  void *result_memory;
+	  tmp_memory = multiply (m, pow5, &numerator);
+	  if (tmp_memory == NULL)
+	    {
+	      free (pow5_ptr);
+	      free (memory);
+	      return NULL;
+	    }
+	  /* Construct 2^|s|.  */
+	  {
+	    mp_limb_t *ptr = pow5_ptr + pow5_len;
+	    size_t i;
+	    for (i = 0; i < s_limbs; i++)
+	      ptr[i] = 0;
+	    ptr[s_limbs] = (mp_limb_t) 1 << s_bits;
+	    denominator.limbs = ptr;
+	    denominator.nlimbs = s_limbs + 1;
+	  }
+	  result_memory = divide (numerator, denominator, yp);
+	  free (tmp_memory);
+	  free (pow5_ptr);
+	  free (memory);
+	  return result_memory;
+	}
+      else
+	{
+	  /* n < 0, s > 0.
+	     Multiply m with 2^s, then divide by pow5.  */
+	  mpn_t numerator;
+	  mp_limb_t *num_ptr;
+	  void *result_memory;
+	  num_ptr = (mp_limb_t *) malloc ((m.nlimbs + s_limbs + 1)
+					  * sizeof (mp_limb_t));
+	  if (num_ptr == NULL)
+	    {
+	      free (pow5_ptr);
+	      free (memory);
+	      return NULL;
+	    }
+	  {
+	    mp_limb_t *destptr = num_ptr;
+	    {
+	      size_t i;
+	      for (i = 0; i < s_limbs; i++)
+		*destptr++ = 0;
+	    }
+	    if (s_bits > 0)
+	      {
+		const mp_limb_t *sourceptr = m.limbs;
+		mp_twolimb_t accu = 0;
+		size_t count;
+		for (count = m.nlimbs; count > 0; count--)
+		  {
+		    accu += (mp_twolimb_t) *sourceptr++ << s;
+		    *destptr++ = (mp_limb_t) accu;
+		    accu = accu >> GMP_LIMB_BITS;
+		  }
+		if (accu > 0)
+		  *destptr++ = (mp_limb_t) accu;
+	      }
+	    else
+	      {
+		const mp_limb_t *sourceptr = m.limbs;
+		size_t count;
+		for (count = m.nlimbs; count > 0; count--)
+		  *destptr++ = *sourceptr++;
+	      }
+	    numerator.limbs = num_ptr;
+	    numerator.nlimbs = destptr - num_ptr;
+	  }
+	  result_memory = divide (numerator, pow5, yp);
+	  free (num_ptr);
+	  free (pow5_ptr);
+	  free (memory);
+	  return result_memory;
+	}
+    }
+}
+
+/* Assuming x is finite and >= 0, and n is an integer:
+   Returns the decimal representation of round (x * 10^n).
+   Return the allocated memory - containing the decimal digits in low-to-high
+   order, terminated with a NUL character - in case of success, NULL in case
+   of memory allocation failure.  */
+static char *
+scale10_round_decimal_long_double (long double x, int n)
+{
+  mpn_t y;
+  void *memory;
+  char *digits;
+
+  memory = scale10_round_long_double (x, n, &y);
+  if (memory == NULL)
+    return NULL;
+  digits = convert_to_decimal (y);
+  free (memory);
+  return digits;
+}
+
+/* Assuming x is finite and > 0:
+   Return an approximation for n with 10^n <= x < 10^(n+1).
+   The approximation is usually the right n, but may be off by 1 sometimes.  */
+static int
+floorlog10l (long double x)
+{
+  int exp;
+  long double y;
+  double z;
+  double l;
+
+  /* Split into exponential part and mantissa.  */
+  y = frexpl (x, &exp);
+  if (!(y >= 0.0L && y < 1.0L))
+    abort ();
+  if (y == 0.0L)
+    return INT_MIN;
+  if (y < 0.5L)
+    {
+      while (y < (1.0L / (1 << (GMP_LIMB_BITS / 2)) / (1 << (GMP_LIMB_BITS / 2))))
+	{
+	  y *= 1.0L * (1 << (GMP_LIMB_BITS / 2)) * (1 << (GMP_LIMB_BITS / 2));
+	  exp -= GMP_LIMB_BITS;
+	}
+      if (y < (1.0L / (1 << 16)))
+	{
+	  y *= 1.0L * (1 << 16);
+	  exp -= 16;
+	}
+      if (y < (1.0L / (1 << 8)))
+	{
+	  y *= 1.0L * (1 << 8);
+	  exp -= 8;
+	}
+      if (y < (1.0L / (1 << 4)))
+	{
+	  y *= 1.0L * (1 << 4);
+	  exp -= 4;
+	}
+      if (y < (1.0L / (1 << 2)))
+	{
+	  y *= 1.0L * (1 << 2);
+	  exp -= 2;
+	}
+      if (y < (1.0L / (1 << 1)))
+	{
+	  y *= 1.0L * (1 << 1);
+	  exp -= 1;
+	}
+    }
+  if (!(y >= 0.5L && y < 1.0L))
+    abort ();
+  /* Compute an approximation for l = log2(x) = exp + log2(y).  */
+  l = exp;
+  z = y;
+  if (z < 0.70710678118654752444)
+    {
+      z *= 1.4142135623730950488;
+      l -= 0.5;
+    }
+  if (z < 0.8408964152537145431)
+    {
+      z *= 1.1892071150027210667;
+      l -= 0.25;
+    }
+  if (z < 0.91700404320467123175)
+    {
+      z *= 1.0905077326652576592;
+      l -= 0.125;
+    }
+  if (z < 0.9576032806985736469)
+    {
+      z *= 1.0442737824274138403;
+      l -= 0.0625;
+    }
+  /* Now 0.95 <= z <= 1.01.  */
+  z = 1 - z;
+  /* log(1-z) = - z - z^2/2 - z^3/3 - z^4/4 - ...
+     Four terms are enough to get an approximation with error < 10^-7.  */
+  l -= z * (1.0 + z * (0.5 + z * ((1.0 / 3) + z * 0.25)));
+  /* Finally multiply with log(2)/log(10), yields an approximation for
+     log10(x).  */
+  l *= 0.30102999566398119523;
+  /* Round down to the next integer.  */
+  return (int) l + (l < 0 ? -1 : 0);
+}
+
+#endif
+
 CHAR_T *
 VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list args)
 {
@@ -313,6 +1262,516 @@
 		    abort ();
 		  }
 	      }
+#if NEED_PRINTF_LONG_DOUBLE && !defined IN_LIBINTL
+	    else if ((dp->conversion == 'f' || dp->conversion == 'F'
+		      || dp->conversion == 'e' || dp->conversion == 'E'
+		      || dp->conversion == 'g' || dp->conversion == 'G')
+		     && a.arg[dp->arg_index].type == TYPE_LONGDOUBLE)
+	      {
+		int flags = dp->flags;
+		int has_width;
+		size_t width;
+		int has_precision;
+		size_t precision;
+		long double arg;
+		size_t tmp_length;
+		CHAR_T tmpbuf[700];
+		CHAR_T *tmp;
+		CHAR_T *pad_ptr;
+		CHAR_T *p;
+
+		has_width = 0;
+		width = 0;
+		if (dp->width_start != dp->width_end)
+		  {
+		    if (dp->width_arg_index != ARG_NONE)
+		      {
+			int arg;
+
+			if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
+			  abort ();
+			arg = a.arg[dp->width_arg_index].a.a_int;
+			if (arg < 0)
+			  {
+			    /* "A negative field width is taken as a '-' flag
+			        followed by a positive field width."  */
+			    flags |= FLAG_LEFT;
+			    width = (unsigned int) (-arg);
+			  }
+			else
+			  width = arg;
+		      }
+		    else
+		      {
+			const CHAR_T *digitp = dp->width_start;
+
+			do
+			  width = xsum (xtimes (width, 10), *digitp++ - '0');
+			while (digitp != dp->width_end);
+		      }
+		    has_width = 1;
+		  }
+
+		has_precision = 0;
+		precision = 0;
+		if (dp->precision_start != dp->precision_end)
+		  {
+		    if (dp->precision_arg_index != ARG_NONE)
+		      {
+			int arg;
+
+			if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
+			  abort ();
+			arg = a.arg[dp->precision_arg_index].a.a_int;
+			/* "A negative precision is taken as if the precision
+			    were omitted."  */
+			if (arg >= 0)
+			  {
+			    precision = arg;
+			    has_precision = 1;
+			  }
+		      }
+		    else
+		      {
+			const CHAR_T *digitp = dp->precision_start + 1;
+
+			precision = 0;
+			while (digitp != dp->precision_end)
+			  precision = xsum (xtimes (precision, 10), *digitp++ - '0');
+			has_precision = 1;
+		      }
+		  }
+
+		arg = a.arg[dp->arg_index].a.a_longdouble;
+
+		/* Allocate a temporary buffer of sufficient size.  */
+		tmp_length = LDBL_DIG + 1;
+		if (tmp_length < precision)
+		  tmp_length = precision;
+		if (dp->conversion == 'f' || dp->conversion == 'F')
+		  if (!(isnanl (arg) || arg + arg == arg))
+		    {
+		      int exponent = floorlog10l (arg < 0 ? -arg : arg);
+		      if (exponent >= 0 && tmp_length < exponent + precision)
+			tmp_length = exponent + precision;
+		    }
+		/* Account for sign, decimal point etc. */
+		tmp_length = xsum (tmp_length, 12);
+
+		if (tmp_length < width)
+		  tmp_length = width;
+
+		tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */
+
+		if (tmp_length <= sizeof (tmpbuf) / sizeof (CHAR_T))
+		  tmp = tmpbuf;
+		else
+		  {
+		    size_t tmp_memsize = xtimes (tmp_length, sizeof (CHAR_T));
+
+		    if (size_overflow_p (tmp_memsize))
+		      /* Overflow, would lead to out of memory.  */
+		      goto out_of_memory;
+		    tmp = (CHAR_T *) malloc (tmp_memsize);
+		    if (tmp == NULL)
+		      /* Out of memory.  */
+		      goto out_of_memory;
+		  }
+
+		pad_ptr = NULL;
+		p = tmp;
+
+		if (isnanl (arg))
+		  {
+		    if (dp->conversion >= 'A' && dp->conversion <= 'Z')
+		      {
+			*p++ = 'N'; *p++ = 'A'; *p++ = 'N';
+		      }
+		    else
+		      {
+			*p++ = 'n'; *p++ = 'a'; *p++ = 'n';
+		      }
+		  }
+		else
+		  {
+		    int sign = 0;
+		    DECL_LONG_DOUBLE_ROUNDING
+
+		    BEGIN_LONG_DOUBLE_ROUNDING ();
+
+		    if (signbit (arg)) /* arg < 0.0L or negative zero */
+		      {
+			sign = -1;
+			arg = -arg;
+		      }
+
+		    if (sign < 0)
+		      *p++ = '-';
+		    else if (flags & FLAG_SHOWSIGN)
+		      *p++ = '+';
+		    else if (flags & FLAG_SPACE)
+		      *p++ = ' ';
+
+		    if (arg > 0.0L && arg + arg == arg)
+		      {
+			if (dp->conversion >= 'A' && dp->conversion <= 'Z')
+			  {
+			    *p++ = 'I'; *p++ = 'N'; *p++ = 'F';
+			  }
+			else
+			  {
+			    *p++ = 'i'; *p++ = 'n'; *p++ = 'f';
+			  }
+		      }
+		    else
+		      {
+			pad_ptr = p;
+
+			if (dp->conversion == 'f' || dp->conversion == 'F')
+			  {
+			    char *digits;
+			    size_t ndigits;
+
+			    if (!has_precision)
+			      precision = 6;
+
+			    digits =
+			      scale10_round_decimal_long_double (arg, precision);
+			    if (digits == NULL)
+			      {
+				END_LONG_DOUBLE_ROUNDING ();
+				goto out_of_memory;
+			      }
+			    ndigits = strlen (digits);
+
+			    if (ndigits > precision)
+			      do
+				{
+				  --ndigits;
+				  *p++ = digits[ndigits];
+				}
+			      while (ndigits > precision);
+			    else
+			      *p++ = '0';
+			    /* Here ndigits <= precision.  */
+			    if ((flags & FLAG_ALT) || precision > 0)
+			      {
+				*p++ = decimal_point_char ();
+				for (; precision > ndigits; precision--)
+				  *p++ = '0';
+				while (ndigits > 0)
+				  {
+				    --ndigits;
+				    *p++ = digits[ndigits];
+				  }
+			      }
+
+			    free (digits);
+			  }
+			else if (dp->conversion == 'e' || dp->conversion == 'E')
+			  {
+			    int exponent;
+
+			    if (!has_precision)
+			      precision = 6;
+
+			    if (arg == 0.0L)
+			      {
+				exponent = 0;
+				*p++ = '0';
+				if ((flags & FLAG_ALT) || precision > 0)
+				  {
+				    *p++ = decimal_point_char ();
+				    for (; precision > 0; precision--)
+				      *p++ = '0';
+				  }
+			      }
+			    else
+			      {
+				/* arg > 0.0L.  */
+				int adjusted;
+				char *digits;
+				size_t ndigits;
+
+				exponent = floorlog10l (arg);
+				adjusted = 0;
+				for (;;)
+				  {
+				    digits =
+				      scale10_round_decimal_long_double (arg,
+									 (int)precision - exponent);
+				    if (digits == NULL)
+				      {
+					END_LONG_DOUBLE_ROUNDING ();
+					goto out_of_memory;
+				      }
+				    ndigits = strlen (digits);
+
+				    if (ndigits == precision + 1)
+				      break;
+				    if (ndigits < precision
+					|| ndigits > precision + 2)
+				      /* The exponent was not guessed precisely
+					 enough.  */
+				      abort ();
+				    if (adjusted)
+				      /* None of two values of exponent is the
+					 right one.  Prevent an endless loop.  */
+				      abort ();
+				    free (digits);
+				    if (ndigits == precision)
+				      exponent -= 1;
+				    else
+				      exponent += 1;
+				    adjusted = 1;
+				  }
+
+				/* Here ndigits = precision+1.  */
+				*p++ = digits[--ndigits];
+				if ((flags & FLAG_ALT) || precision > 0)
+				  {
+				    *p++ = decimal_point_char ();
+				    while (ndigits > 0)
+				      {
+					--ndigits;
+					*p++ = digits[ndigits];
+				      }
+				  }
+
+				free (digits);
+			      }
+
+			    *p++ = dp->conversion; /* 'e' or 'E' */
+# if WIDE_CHAR_VERSION
+			    {
+			      static const wchar_t decimal_format[] =
+				{ '%', '+', '.', '2', 'd', '\0' };
+			      SNPRINTF (p, 6 + 1, decimal_format, exponent);
+			    }
+# else
+			    sprintf (p, "%+.2d", exponent);
+# endif
+			    while (*p != '\0')
+			      p++;
+			  }
+			else if (dp->conversion == 'g' || dp->conversion == 'G')
+			  {
+			    /* This is not specified by POSIX, but
+			       implementations appear to do this.  */
+			    if (!has_precision)
+			      precision = 6;
+
+			    if (precision == 0)
+			      precision = 1;
+			    /* precision >= 1.  */
+
+			    if (arg == 0.0L)
+			      /* The exponent is 0, >= -4, < precision.
+				 Use fixed-point notation.  */
+			      {
+				size_t ndigits = precision;
+				/* Number of trailing zeroes that have to be
+				   dropped.  */
+				size_t nzeroes =
+				  (flags & FLAG_ALT ? 0 : precision - 1);
+
+				--ndigits;
+				*p++ = '0';
+				if ((flags & FLAG_ALT) || ndigits > nzeroes)
+				  {
+				    *p++ = decimal_point_char ();
+				    while (ndigits > nzeroes)
+				      {
+					--ndigits;
+					*p++ = '0';
+				      }
+				  }
+			      }
+			    else
+			      {
+				/* arg > 0.0L.  */
+				int exponent;
+				int adjusted;
+				char *digits;
+				size_t ndigits;
+				size_t nzeroes;
+
+				exponent = floorlog10l (arg);
+				adjusted = 0;
+				for (;;)
+				  {
+				    digits =
+				      scale10_round_decimal_long_double (arg,
+									 (int)(precision - 1) - exponent);
+				    if (digits == NULL)
+				      {
+					END_LONG_DOUBLE_ROUNDING ();
+					goto out_of_memory;
+				      }
+				    ndigits = strlen (digits);
+
+				    if (ndigits == precision)
+				      break;
+				    if (ndigits < precision - 1
+					|| ndigits > precision + 1)
+				      /* The exponent was not guessed precisely
+					 enough.  */
+				      abort ();
+				    if (adjusted)
+				      /* None of two values of exponent is the
+					 right one.  Prevent an endless loop.  */
+				      abort ();
+				    free (digits);
+				    if (ndigits < precision)
+				      exponent -= 1;
+				    else
+				      exponent += 1;
+				    adjusted = 1;
+				  }
+				/* Here ndigits = precision.  */
+
+				/* Determine the number of trailing zeroes that
+				   have to be dropped.  */
+				nzeroes = 0;
+				if ((flags & FLAG_ALT) == 0)
+				  while (nzeroes < ndigits
+					 && digits[nzeroes] == '0')
+				    nzeroes++;
+
+				/* The exponent is now determined.  */
+				if (exponent >= -4 && exponent < (long)precision)
+				  {
+				    /* Fixed-point notation: max(exponent,0)+1
+				       digits, then the decimal point, then the
+				       remaining digits without trailing zeroes.  */
+				    if (exponent >= 0)
+				      {
+					size_t count = exponent + 1;
+					/* Note: count <= precision = ndigits.  */
+					for (; count > 0; count--)
+					  *p++ = digits[--ndigits];
+					if ((flags & FLAG_ALT) || ndigits > nzeroes)
+					  {
+					    *p++ = decimal_point_char ();
+					    while (ndigits > nzeroes)
+					      {
+						--ndigits;
+						*p++ = digits[ndigits];
+					      }
+					  }
+				      }
+				    else
+				      {
+					size_t count = -exponent - 1;
+					*p++ = '0';
+					*p++ = decimal_point_char ();
+					for (; count > 0; count--)
+					  *p++ = '0';
+					while (ndigits > nzeroes)
+					  {
+					    --ndigits;
+					    *p++ = digits[ndigits];
+					  }
+				      }
+				  }
+				else
+				  {
+				    /* Exponential notation.  */
+				    *p++ = digits[--ndigits];
+				    if ((flags & FLAG_ALT) || ndigits > nzeroes)
+				      {
+					*p++ = decimal_point_char ();
+					while (ndigits > nzeroes)
+					  {
+					    --ndigits;
+					    *p++ = digits[ndigits];
+					  }
+				      }
+				    *p++ = dp->conversion - 'G' + 'E'; /* 'e' or 'E' */
+# if WIDE_CHAR_VERSION
+				    {
+				      static const wchar_t decimal_format[] =
+					{ '%', '+', '.', '2', 'd', '\0' };
+				      SNPRINTF (p, 6 + 1, decimal_format, exponent);
+				    }
+# else
+				    sprintf (p, "%+.2d", exponent);
+# endif
+				    while (*p != '\0')
+				      p++;
+				  }
+
+				free (digits);
+			      }
+			  }
+			else
+			  abort ();
+		      }
+
+		    END_LONG_DOUBLE_ROUNDING ();
+		  }
+
+		/* The generated string now extends from tmp to p, with the
+		   zero padding insertion point being at pad_ptr.  */
+		if (has_width && p - tmp < width)
+		  {
+		    size_t pad = width - (p - tmp);
+		    CHAR_T *end = p + pad;
+
+		    if (flags & FLAG_LEFT)
+		      {
+			/* Pad with spaces on the right.  */
+			for (; pad > 0; pad--)
+			  *p++ = ' ';
+		      }
+		    else if ((flags & FLAG_ZERO) && pad_ptr != NULL)
+		      {
+			/* Pad with zeroes.  */
+			CHAR_T *q = end;
+
+			while (p > pad_ptr)
+			  *--q = *--p;
+			for (; pad > 0; pad--)
+			  *p++ = '0';
+		      }
+		    else
+		      {
+			/* Pad with spaces on the left.  */
+			CHAR_T *q = end;
+
+			while (p > tmp)
+			  *--q = *--p;
+			for (; pad > 0; pad--)
+			  *p++ = ' ';
+		      }
+
+		    p = end;
+		  }
+
+		{
+		  size_t count = p - tmp;
+
+		  if (count >= tmp_length)
+		    /* tmp_length was incorrectly calculated - fix the
+		       code above!  */
+		    abort ();
+
+		  /* Make room for the result.  */
+		  if (count >= allocated - length)
+		    {
+		      size_t n = xsum (length, count);
+
+		      ENSURE_ALLOCATION (n);
+		    }
+
+		  /* Append the result.  */
+		  memcpy (result + length, tmp, count * sizeof (CHAR_T));
+		  if (tmp != tmpbuf)
+		    free (tmp);
+		  length += count;
+		}
+	      }
+#endif
 #if NEED_PRINTF_DIRECTIVE_A && !defined IN_LIBINTL
 	    else if (dp->conversion == 'a' || dp->conversion == 'A')
 	      {
--- a/m4/fprintf-posix.m4
+++ b/m4/fprintf-posix.m4
@@ -1,4 +1,4 @@
-# fprintf-posix.m4 serial 5
+# fprintf-posix.m4 serial 6
 dnl Copyright (C) 2007 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -8,6 +8,7 @@
 [
   AC_REQUIRE([gl_EOVERFLOW])
   AC_REQUIRE([gl_PRINTF_SIZES_C99])
+  AC_REQUIRE([gl_PRINTF_LONG_DOUBLE])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_A])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_F])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_N])
@@ -17,20 +18,25 @@
   gl_cv_func_fprintf_posix=no
   case "$gl_cv_func_printf_sizes_c99" in
     *yes)
-      case "$gl_cv_func_printf_directive_a" in
+      case "$gl_cv_func_printf_long_double" in
         *yes)
-          case "$gl_cv_func_printf_directive_f" in
+          case "$gl_cv_func_printf_directive_a" in
             *yes)
-              case "$gl_cv_func_printf_directive_n" in
+              case "$gl_cv_func_printf_directive_f" in
                 *yes)
-                  case "$gl_cv_func_printf_positions" in
+                  case "$gl_cv_func_printf_directive_n" in
                     *yes)
-                      case "$gl_cv_func_printf_flag_grouping" in
+                      case "$gl_cv_func_printf_positions" in
                         *yes)
-                          case "$gl_cv_func_printf_flag_zero" in
+                          case "$gl_cv_func_printf_flag_grouping" in
                             *yes)
-                              # fprintf exists and is already POSIX compliant.
-                              gl_cv_func_fprintf_posix=yes
+                              case "$gl_cv_func_printf_flag_zero" in
+                                *yes)
+                                  # fprintf exists and is already POSIX
+                                  # compliant.
+                                  gl_cv_func_fprintf_posix=yes
+                                  ;;
+                              esac
                               ;;
                           esac
                           ;;
@@ -46,6 +52,7 @@
       ;;
   esac
   if test $gl_cv_func_fprintf_posix = no; then
+    gl_PREREQ_VASNPRINTF_LONG_DOUBLE
     gl_PREREQ_VASNPRINTF_DIRECTIVE_A
     gl_PREREQ_VASNPRINTF_DIRECTIVE_F
     gl_PREREQ_VASNPRINTF_FLAG_GROUPING
--- a/m4/printf.m4
+++ b/m4/printf.m4
@@ -1,4 +1,4 @@
-# printf.m4 serial 9
+# printf.m4 serial 10
 dnl Copyright (C) 2003, 2007 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -81,6 +81,49 @@
     ])
 ])
 
+dnl Test whether the *printf family of functions supports 'long double'
+dnl arguments together with the 'L' size specifier. (ISO C99, POSIX:2001)
+dnl Result is gl_cv_func_printf_long_double.
+
+AC_DEFUN([gl_PRINTF_LONG_DOUBLE],
+[
+  AC_REQUIRE([AC_PROG_CC])
+  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+  AC_CACHE_CHECK([whether printf supports 'long double' arguments],
+    [gl_cv_func_printf_long_double], 
+    [
+      AC_TRY_RUN([
+#include <stdio.h>
+#include <string.h>
+static char buf[100];
+int main ()
+{
+  buf[0] = '\0';
+  if (sprintf (buf, "%Lf %d", 1.75L, 33, 44, 55) < 0
+      || strcmp (buf, "1.750000 33") != 0)
+    return 1;
+  buf[0] = '\0';
+  if (sprintf (buf, "%Le %d", 1.75L, 33, 44, 55) < 0
+      || strcmp (buf, "1.750000e+00 33") != 0)
+    return 1;
+  buf[0] = '\0';
+  if (sprintf (buf, "%Lg %d", 1.75L, 33, 44, 55) < 0
+      || strcmp (buf, "1.75 33") != 0)
+    return 1;
+  return 0;
+}], [gl_cv_func_printf_long_double=yes], [gl_cv_func_printf_long_double=no],
+      [
+changequote(,)dnl
+       case "$host_os" in
+         beos*)        gl_cv_func_printf_long_double="guessing no";;
+         mingw* | pw*) gl_cv_func_printf_long_double="guessing no";;
+         *)            gl_cv_func_printf_long_double="guessing yes";;
+       esac
+changequote([,])dnl
+      ])
+    ])
+])
+
 dnl Test whether the *printf family of functions supports the 'a' and 'A'
 dnl conversion specifier for hexadecimal output of floating-point numbers.
 dnl (ISO C99, POSIX:2001)
@@ -662,52 +705,54 @@
 dnl The results of these tests on various platforms are:
 dnl
 dnl 1 = gl_PRINTF_SIZES_C99
-dnl 2 = gl_PRINTF_DIRECTIVE_A
-dnl 3 = gl_PRINTF_DIRECTIVE_F
-dnl 4 = gl_PRINTF_DIRECTIVE_N
-dnl 5 = gl_PRINTF_POSITIONS
-dnl 6 = gl_PRINTF_FLAG_GROUPING
-dnl 7 = gl_PRINTF_FLAG_ZERO
-dnl 8 = gl_SNPRINTF_PRESENCE
-dnl 9 = gl_SNPRINTF_TRUNCATION_C99
-dnl 10 = gl_SNPRINTF_RETVAL_C99
-dnl 11 = gl_SNPRINTF_DIRECTIVE_N
-dnl 12 = gl_VSNPRINTF_ZEROSIZE_C99
+dnl 2 = gl_PRINTF_LONG_DOUBLE
+dnl 3 = gl_PRINTF_DIRECTIVE_A
+dnl 4 = gl_PRINTF_DIRECTIVE_F
+dnl 5 = gl_PRINTF_DIRECTIVE_N
+dnl 6 = gl_PRINTF_POSITIONS
+dnl 7 = gl_PRINTF_FLAG_GROUPING
+dnl 8 = gl_PRINTF_FLAG_ZERO
+dnl 9 = gl_SNPRINTF_PRESENCE
+dnl 10 = gl_SNPRINTF_TRUNCATION_C99
+dnl 11 = gl_SNPRINTF_RETVAL_C99
+dnl 12 = gl_SNPRINTF_DIRECTIVE_N
+dnl 13 = gl_VSNPRINTF_ZEROSIZE_C99
 dnl
 dnl 1 = checking whether printf supports size specifiers as in C99...
-dnl 2 = checking whether printf supports the 'a' and 'A' directives...
-dnl 3 = checking whether printf supports the 'F' directive...
-dnl 4 = checking whether printf supports the 'n' directive...
-dnl 5 = checking whether printf supports POSIX/XSI format strings with positions...
-dnl 6 = checking whether printf supports the grouping flag...
-dnl 7 = checking whether printf supports the zero flag correctly...
-dnl 8 = checking for snprintf...
-dnl 9 = checking whether snprintf truncates the result as in C99...
-dnl 10 = checking whether snprintf returns a byte count as in C99...
-dnl 11 = checking whether snprintf fully supports the 'n' directive...
-dnl 12 = checking whether vsnprintf respects a zero size as in C99...
+dnl 2 = checking whether printf supports 'long double' arguments...
+dnl 3 = checking whether printf supports the 'a' and 'A' directives...
+dnl 4 = checking whether printf supports the 'F' directive...
+dnl 5 = checking whether printf supports the 'n' directive...
+dnl 6 = checking whether printf supports POSIX/XSI format strings with positions...
+dnl 7 = checking whether printf supports the grouping flag...
+dnl 8 = checking whether printf supports the zero flag correctly...
+dnl 9 = checking for snprintf...
+dnl 10 = checking whether snprintf truncates the result as in C99...
+dnl 11 = checking whether snprintf returns a byte count as in C99...
+dnl 12 = checking whether snprintf fully supports the 'n' directive...
+dnl 13 = checking whether vsnprintf respects a zero size as in C99...
 dnl
 dnl . = yes, # = no.
 dnl
-dnl                                        1  2  3  4  5  6  7  8  9 10 11 12
-dnl   glibc 2.5                            .  .  .  .  .  .  .  .  .  .  .  .
-dnl   glibc 2.3.6                          .  #  .  .  .  .  .  .  .  .  .  .
-dnl   FreeBSD 5.4, 6.1                     .  ?  .  .  .  .  #  .  .  .  .  .
-dnl   MacOS X 10.3.9                       .  #  .  .  .  .  #  .  .  .  .  .
-dnl   OpenBSD 3.9, 4.0                     .  #  ?  .  .  ?  ?  .  .  .  ?  ?
-dnl   Cygwin 2007 (= Cygwin 1.5.24)        .  #  #  .  .  .  #  .  .  .  .  .
-dnl   Cygwin 2006 (= Cygwin 1.5.19)        #  #  #  .  .  #  #  .  .  .  .  .
-dnl   Solaris 10                           .  #  .  .  .  .  #  .  .  .  .  .
-dnl   Solaris 2.6 ... 9                    #  #  #  .  .  .  #  .  .  .  .  .
-dnl   Solaris 2.5.1                        #  #  #  .  .  .  #  #  #  #  #  #
-dnl   AIX 5.2                              .  #  .  .  .  .  #  .  .  .  .  .
-dnl   AIX 4.3.2, 5.1                       #  #  #  .  .  .  #  .  .  .  .  .
-dnl   HP-UX 11.31                          .  #  .  .  .  .  #  .  .  #  #  .
-dnl   HP-UX 10.20, 11.00, 11.11, 11.23     #  #  #  .  .  .  #  .  .  #  #  #
-dnl   IRIX 6.5                             #  #  #  .  .  .  #  .  .  #  .  .
-dnl   OSF/1 5.1                            #  #  #  .  .  .  #  .  .  #  .  #
-dnl   OSF/1 4.0d                           #  #  #  .  .  .  #  #  #  #  #  #
-dnl   NetBSD 4.0                           .  ?  ?  .  .  ?  ?  .  .  .  ?  ?
-dnl   NetBSD 3.0                           .  #  #  .  #  #  #  .  .  .  .  .
-dnl   BeOS                                 #  #  #  .  #  .  .  .  .  .  .  .
-dnl   mingw                                #  #  #  .  #  #  #  .  #  #  #  .
+dnl                                        1  2  3  4  5  6  7  8  9 10 11 12 13
+dnl   glibc 2.5                            .  .  .  .  .  .  .  .  .  .  .  .  .
+dnl   glibc 2.3.6                          .  .  #  .  .  .  .  .  .  .  .  .  .
+dnl   FreeBSD 5.4, 6.1                     .  ?  ?  .  .  .  .  #  .  .  .  .  .
+dnl   MacOS X 10.3.9                       .  .  #  .  .  .  .  #  .  .  .  .  .
+dnl   OpenBSD 3.9, 4.0                     .  ?  #  ?  .  .  ?  ?  .  .  .  ?  ?
+dnl   Cygwin 2007 (= Cygwin 1.5.24)        .  ?  #  #  .  .  .  #  .  .  .  .  .
+dnl   Cygwin 2006 (= Cygwin 1.5.19)        #  ?  #  #  .  .  #  #  .  .  .  .  .
+dnl   Solaris 10                           .  .  #  .  .  .  .  #  .  .  .  .  .
+dnl   Solaris 2.6 ... 9                    #  .  #  #  .  .  .  #  .  .  .  .  .
+dnl   Solaris 2.5.1                        #  .  #  #  .  .  .  #  #  #  #  #  #
+dnl   AIX 5.2                              .  .  #  .  .  .  .  #  .  .  .  .  .
+dnl   AIX 4.3.2, 5.1                       #  .  #  #  .  .  .  #  .  .  .  .  .
+dnl   HP-UX 11.31                          .  .  #  .  .  .  .  #  .  .  #  #  .
+dnl   HP-UX 10.20, 11.00, 11.11, 11.23     #  .  #  #  .  .  .  #  .  .  #  #  #
+dnl   IRIX 6.5                             #  .  #  #  .  .  .  #  .  .  #  .  .
+dnl   OSF/1 5.1                            #  .  #  #  .  .  .  #  .  .  #  .  #
+dnl   OSF/1 4.0d                           #  .  #  #  .  .  .  #  #  #  #  #  #
+dnl   NetBSD 4.0                           .  ?  ?  ?  .  .  ?  ?  .  .  .  ?  ?
+dnl   NetBSD 3.0                           .  ?  #  #  .  #  #  #  .  .  .  .  .
+dnl   BeOS                                 #  #  #  #  .  #  .  .  .  .  .  .  .
+dnl   mingw                                #  #  #  #  .  #  #  #  .  #  #  #  .
--- a/m4/snprintf-posix.m4
+++ b/m4/snprintf-posix.m4
@@ -1,4 +1,4 @@
-# snprintf-posix.m4 serial 6
+# snprintf-posix.m4 serial 7
 dnl Copyright (C) 2007 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -8,6 +8,7 @@
 [
   AC_REQUIRE([gl_EOVERFLOW])
   AC_REQUIRE([gl_PRINTF_SIZES_C99])
+  AC_REQUIRE([gl_PRINTF_LONG_DOUBLE])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_A])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_F])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_N])
@@ -23,29 +24,33 @@
     gl_VSNPRINTF_ZEROSIZE_C99
     case "$gl_cv_func_printf_sizes_c99" in
       *yes)
-        case "$gl_cv_func_printf_directive_a" in
+        case "$gl_cv_func_printf_long_double" in
           *yes)
-            case "$gl_cv_func_printf_directive_f" in
+            case "$gl_cv_func_printf_directive_a" in
               *yes)
-                case "$gl_cv_func_printf_directive_n" in
+                case "$gl_cv_func_printf_directive_f" in
                   *yes)
-                    case "$gl_cv_func_printf_positions" in
+                    case "$gl_cv_func_printf_directive_n" in
                       *yes)
-                        case "$gl_cv_func_printf_flag_grouping" in
+                        case "$gl_cv_func_printf_positions" in
                           *yes)
-                            case "$gl_cv_func_printf_flag_zero" in
+                            case "$gl_cv_func_printf_flag_grouping" in
                               *yes)
-                                case "$gl_cv_func_snprintf_truncation_c99" in
+                                case "$gl_cv_func_printf_flag_zero" in
                                   *yes)
-                                    case "$gl_cv_func_snprintf_retval_c99" in
+                                    case "$gl_cv_func_snprintf_truncation_c99" in
                                       *yes)
-                                        case "$gl_cv_func_snprintf_directive_n" in
+                                        case "$gl_cv_func_snprintf_retval_c99" in
                                           *yes)
-                                            case "$gl_cv_func_vsnprintf_zerosize_c99" in
+                                            case "$gl_cv_func_snprintf_directive_n" in
                                               *yes)
-                                                # snprintf exists and is already
-                                                # POSIX compliant.
-                                                gl_cv_func_snprintf_posix=yes
+                                                case "$gl_cv_func_vsnprintf_zerosize_c99" in
+                                                  *yes)
+                                                    # snprintf exists and is
+                                                    # already POSIX compliant.
+                                                    gl_cv_func_snprintf_posix=yes
+                                                    ;;
+                                                esac
                                                 ;;
                                             esac
                                             ;;
@@ -70,6 +75,7 @@
     esac
   fi
   if test $gl_cv_func_snprintf_posix = no; then
+    gl_PREREQ_VASNPRINTF_LONG_DOUBLE
     gl_PREREQ_VASNPRINTF_DIRECTIVE_A
     gl_PREREQ_VASNPRINTF_DIRECTIVE_F
     gl_PREREQ_VASNPRINTF_FLAG_GROUPING
--- a/m4/sprintf-posix.m4
+++ b/m4/sprintf-posix.m4
@@ -1,4 +1,4 @@
-# sprintf-posix.m4 serial 5
+# sprintf-posix.m4 serial 6
 dnl Copyright (C) 2007 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -8,6 +8,7 @@
 [
   AC_REQUIRE([gl_EOVERFLOW])
   AC_REQUIRE([gl_PRINTF_SIZES_C99])
+  AC_REQUIRE([gl_PRINTF_LONG_DOUBLE])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_A])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_F])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_N])
@@ -17,20 +18,25 @@
   gl_cv_func_sprintf_posix=no
   case "$gl_cv_func_printf_sizes_c99" in
     *yes)
-      case "$gl_cv_func_printf_directive_a" in
+      case "$gl_cv_func_printf_long_double" in
         *yes)
-          case "$gl_cv_func_printf_directive_f" in
+          case "$gl_cv_func_printf_directive_a" in
             *yes)
-              case "$gl_cv_func_printf_directive_n" in
+              case "$gl_cv_func_printf_directive_f" in
                 *yes)
-                  case "$gl_cv_func_printf_positions" in
+                  case "$gl_cv_func_printf_directive_n" in
                     *yes)
-                      case "$gl_cv_func_printf_flag_grouping" in
+                      case "$gl_cv_func_printf_positions" in
                         *yes)
-                          case "$gl_cv_func_printf_flag_zero" in
+                          case "$gl_cv_func_printf_flag_grouping" in
                             *yes)
-                              # sprintf exists and is already POSIX compliant.
-                              gl_cv_func_sprintf_posix=yes
+                              case "$gl_cv_func_printf_flag_zero" in
+                                *yes)
+                                  # sprintf exists and is already POSIX
+                                  # compliant.
+                                  gl_cv_func_sprintf_posix=yes
+                                  ;;
+                              esac
                               ;;
                           esac
                           ;;
@@ -46,6 +52,7 @@
       ;;
   esac
   if test $gl_cv_func_sprintf_posix = no; then
+    gl_PREREQ_VASNPRINTF_LONG_DOUBLE
     gl_PREREQ_VASNPRINTF_DIRECTIVE_A
     gl_PREREQ_VASNPRINTF_DIRECTIVE_F
     gl_PREREQ_VASNPRINTF_FLAG_GROUPING
--- a/m4/vasnprintf-posix.m4
+++ b/m4/vasnprintf-posix.m4
@@ -1,4 +1,4 @@
-# vasnprintf-posix.m4 serial 6
+# vasnprintf-posix.m4 serial 7
 dnl Copyright (C) 2007 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -8,6 +8,7 @@
 [
   AC_REQUIRE([gl_EOVERFLOW])
   AC_REQUIRE([gl_PRINTF_SIZES_C99])
+  AC_REQUIRE([gl_PRINTF_LONG_DOUBLE])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_A])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_F])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_N])
@@ -18,23 +19,27 @@
   AC_CHECK_FUNCS_ONCE([vasnprintf])
   case "$gl_cv_func_printf_sizes_c99" in
     *yes)
-      case "$gl_cv_func_printf_directive_a" in
+      case "$gl_cv_func_printf_long_double" in
         *yes)
-          case "$gl_cv_func_printf_directive_f" in
+          case "$gl_cv_func_printf_directive_a" in
             *yes)
-              case "$gl_cv_func_printf_directive_n" in
+              case "$gl_cv_func_printf_directive_f" in
                 *yes)
-                  case "$gl_cv_func_printf_positions" in
+                  case "$gl_cv_func_printf_directive_n" in
                     *yes)
-                      case "$gl_cv_func_printf_flag_grouping" in
+                      case "$gl_cv_func_printf_positions" in
                         *yes)
-                          case "$gl_cv_func_printf_flag_zero" in
+                          case "$gl_cv_func_printf_flag_grouping" in
                             *yes)
-                              if test $ac_cv_func_vasnprintf = yes; then
-                                # vasnprintf exists and is already POSIX
-                                # compliant.
-                                gl_cv_func_vasnprintf_posix=yes
-                              fi
+                              case "$gl_cv_func_printf_flag_zero" in
+                                *yes)
+                                  if test $ac_cv_func_vasnprintf = yes; then
+                                    # vasnprintf exists and is already POSIX
+                                    # compliant.
+                                    gl_cv_func_vasnprintf_posix=yes
+                                  fi
+                                  ;;
+                              esac
                               ;;
                           esac
                           ;;
@@ -50,6 +55,7 @@
       ;;
   esac
   if test $gl_cv_func_vasnprintf_posix = no; then
+    gl_PREREQ_VASNPRINTF_LONG_DOUBLE
     gl_PREREQ_VASNPRINTF_DIRECTIVE_A
     gl_PREREQ_VASNPRINTF_DIRECTIVE_F
     gl_PREREQ_VASNPRINTF_FLAG_GROUPING
--- a/m4/vasnprintf.m4
+++ b/m4/vasnprintf.m4
@@ -1,4 +1,4 @@
-# vasnprintf.m4 serial 15
+# vasnprintf.m4 serial 16
 dnl Copyright (C) 2002-2004, 2006-2007 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -59,6 +59,22 @@
   AC_CHECK_FUNCS(snprintf wcslen)
 ])
 
+# Extra prerequisites of lib/vasnprintf.c for supporting 'long double'
+# arguments.
+AC_DEFUN([gl_PREREQ_VASNPRINTF_LONG_DOUBLE],
+[
+  AC_REQUIRE([gl_PRINTF_LONG_DOUBLE])
+  case "$gl_cv_func_printf_long_double" in
+    *yes)
+      ;;
+    *)
+      AC_DEFINE([NEED_PRINTF_LONG_DOUBLE], 1,
+        [Define if the vasnprintf implementation needs special code for
+         'long double' arguments.])
+      ;;
+  esac
+])
+
 # Extra prerequisites of lib/vasnprintf.c for supporting the 'a' directive.
 AC_DEFUN([gl_PREREQ_VASNPRINTF_DIRECTIVE_A],
 [
--- a/m4/vasprintf-posix.m4
+++ b/m4/vasprintf-posix.m4
@@ -1,4 +1,4 @@
-# vasprintf-posix.m4 serial 6
+# vasprintf-posix.m4 serial 7
 dnl Copyright (C) 2007 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -8,6 +8,7 @@
 [
   AC_REQUIRE([gl_EOVERFLOW])
   AC_REQUIRE([gl_PRINTF_SIZES_C99])
+  AC_REQUIRE([gl_PRINTF_LONG_DOUBLE])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_A])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_F])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_N])
@@ -18,23 +19,27 @@
   AC_CHECK_FUNCS([vasprintf])
   case "$gl_cv_func_printf_sizes_c99" in
     *yes)
-      case "$gl_cv_func_printf_directive_a" in
+      case "$gl_cv_func_printf_long_double" in
         *yes)
-          case "$gl_cv_func_printf_directive_f" in
+          case "$gl_cv_func_printf_directive_a" in
             *yes)
-              case "$gl_cv_func_printf_directive_n" in
+              case "$gl_cv_func_printf_directive_f" in
                 *yes)
-                  case "$gl_cv_func_printf_positions" in
+                  case "$gl_cv_func_printf_directive_n" in
                     *yes)
-                      case "$gl_cv_func_printf_flag_grouping" in
+                      case "$gl_cv_func_printf_positions" in
                         *yes)
-                          case "$gl_cv_func_printf_flag_zero" in
+                          case "$gl_cv_func_printf_flag_grouping" in
                             *yes)
-                              if test $ac_cv_func_vasprintf = yes; then
-                                # vasprintf exists and is already POSIX
-                                # compliant.
-                                gl_cv_func_vasprintf_posix=yes
-                              fi
+                              case "$gl_cv_func_printf_flag_zero" in
+                                *yes)
+                                  if test $ac_cv_func_vasprintf = yes; then
+                                    # vasprintf exists and is already POSIX
+                                    # compliant.
+                                    gl_cv_func_vasprintf_posix=yes
+                                  fi
+                                  ;;
+                              esac
                               ;;
                           esac
                           ;;
@@ -50,6 +55,7 @@
       ;;
   esac
   if test $gl_cv_func_vasprintf_posix = no; then
+    gl_PREREQ_VASNPRINTF_LONG_DOUBLE
     gl_PREREQ_VASNPRINTF_DIRECTIVE_A
     gl_PREREQ_VASNPRINTF_DIRECTIVE_F
     gl_PREREQ_VASNPRINTF_FLAG_GROUPING
--- a/m4/vfprintf-posix.m4
+++ b/m4/vfprintf-posix.m4
@@ -1,4 +1,4 @@
-# vfprintf-posix.m4 serial 5
+# vfprintf-posix.m4 serial 6
 dnl Copyright (C) 2007 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -8,6 +8,7 @@
 [
   AC_REQUIRE([gl_EOVERFLOW])
   AC_REQUIRE([gl_PRINTF_SIZES_C99])
+  AC_REQUIRE([gl_PRINTF_LONG_DOUBLE])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_A])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_F])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_N])
@@ -17,20 +18,25 @@
   gl_cv_func_vfprintf_posix=no
   case "$gl_cv_func_printf_sizes_c99" in
     *yes)
-      case "$gl_cv_func_printf_directive_a" in
+      case "$gl_cv_func_printf_long_double" in
         *yes)
-          case "$gl_cv_func_printf_directive_f" in
+          case "$gl_cv_func_printf_directive_a" in
             *yes)
-              case "$gl_cv_func_printf_directive_n" in
+              case "$gl_cv_func_printf_directive_f" in
                 *yes)
-                  case "$gl_cv_func_printf_positions" in
+                  case "$gl_cv_func_printf_directive_n" in
                     *yes)
-                      case "$gl_cv_func_printf_flag_grouping" in
+                      case "$gl_cv_func_printf_positions" in
                         *yes)
-                          case "$gl_cv_func_printf_flag_zero" in
+                          case "$gl_cv_func_printf_flag_grouping" in
                             *yes)
-                              # vfprintf exists and is already POSIX compliant.
-                              gl_cv_func_vfprintf_posix=yes
+                              case "$gl_cv_func_printf_flag_zero" in
+                                *yes)
+                                  # vfprintf exists and is already POSIX
+                                  # compliant.
+                                  gl_cv_func_vfprintf_posix=yes
+                                  ;;
+                              esac
                               ;;
                           esac
                           ;;
@@ -46,6 +52,7 @@
       ;;
   esac
   if test $gl_cv_func_vfprintf_posix = no; then
+    gl_PREREQ_VASNPRINTF_LONG_DOUBLE
     gl_PREREQ_VASNPRINTF_DIRECTIVE_A
     gl_PREREQ_VASNPRINTF_DIRECTIVE_F
     gl_PREREQ_VASNPRINTF_FLAG_GROUPING
--- a/m4/vsnprintf-posix.m4
+++ b/m4/vsnprintf-posix.m4
@@ -1,4 +1,4 @@
-# vsnprintf-posix.m4 serial 6
+# vsnprintf-posix.m4 serial 7
 dnl Copyright (C) 2007 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -8,6 +8,7 @@
 [
   AC_REQUIRE([gl_EOVERFLOW])
   AC_REQUIRE([gl_PRINTF_SIZES_C99])
+  AC_REQUIRE([gl_PRINTF_LONG_DOUBLE])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_A])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_F])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_N])
@@ -24,29 +25,33 @@
     gl_VSNPRINTF_ZEROSIZE_C99
     case "$gl_cv_func_printf_sizes_c99" in
       *yes)
-        case "$gl_cv_func_printf_directive_a" in
+        case "$gl_cv_func_printf_long_double" in
           *yes)
-            case "$gl_cv_func_printf_directive_f" in
+            case "$gl_cv_func_printf_directive_a" in
               *yes)
-                case "$gl_cv_func_printf_directive_n" in
+                case "$gl_cv_func_printf_directive_f" in
                   *yes)
-                    case "$gl_cv_func_printf_positions" in
+                    case "$gl_cv_func_printf_directive_n" in
                       *yes)
-                        case "$gl_cv_func_printf_flag_grouping" in
+                        case "$gl_cv_func_printf_positions" in
                           *yes)
-                            case "$gl_cv_func_printf_flag_zero" in
+                            case "$gl_cv_func_printf_flag_grouping" in
                               *yes)
-                                case "$gl_cv_func_snprintf_truncation_c99" in
+                                case "$gl_cv_func_printf_flag_zero" in
                                   *yes)
-                                    case "$gl_cv_func_snprintf_retval_c99" in
+                                    case "$gl_cv_func_snprintf_truncation_c99" in
                                       *yes)
-                                        case "$gl_cv_func_snprintf_directive_n" in
+                                        case "$gl_cv_func_snprintf_retval_c99" in
                                           *yes)
-                                            case "$gl_cv_func_vsnprintf_zerosize_c99" in
+                                            case "$gl_cv_func_snprintf_directive_n" in
                                               *yes)
-                                                # vsnprintf exists and is
-                                                # already POSIX compliant.
-                                                gl_cv_func_vsnprintf_posix=yes
+                                                case "$gl_cv_func_vsnprintf_zerosize_c99" in
+                                                  *yes)
+                                                    # vsnprintf exists and is
+                                                    # already POSIX compliant.
+                                                    gl_cv_func_vsnprintf_posix=yes
+                                                    ;;
+                                                esac
                                                 ;;
                                             esac
                                             ;;
@@ -71,6 +76,7 @@
     esac
   fi
   if test $gl_cv_func_vsnprintf_posix = no; then
+    gl_PREREQ_VASNPRINTF_LONG_DOUBLE
     gl_PREREQ_VASNPRINTF_DIRECTIVE_A
     gl_PREREQ_VASNPRINTF_DIRECTIVE_F
     gl_PREREQ_VASNPRINTF_FLAG_GROUPING
--- a/m4/vsprintf-posix.m4
+++ b/m4/vsprintf-posix.m4
@@ -1,4 +1,4 @@
-# vsprintf-posix.m4 serial 5
+# vsprintf-posix.m4 serial 6
 dnl Copyright (C) 2007 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -8,6 +8,7 @@
 [
   AC_REQUIRE([gl_EOVERFLOW])
   AC_REQUIRE([gl_PRINTF_SIZES_C99])
+  AC_REQUIRE([gl_PRINTF_LONG_DOUBLE])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_A])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_F])
   AC_REQUIRE([gl_PRINTF_DIRECTIVE_N])
@@ -17,20 +18,25 @@
   gl_cv_func_vsprintf_posix=no
   case "$gl_cv_func_printf_sizes_c99" in
     *yes)
-      case "$gl_cv_func_printf_directive_a" in
+      case "$gl_cv_func_printf_long_double" in
         *yes)
-          case "$gl_cv_func_printf_directive_f" in
+          case "$gl_cv_func_printf_directive_a" in
             *yes)
-              case "$gl_cv_func_printf_directive_n" in
+              case "$gl_cv_func_printf_directive_f" in
                 *yes)
-                  case "$gl_cv_func_printf_positions" in
+                  case "$gl_cv_func_printf_directive_n" in
                     *yes)
-                      case "$gl_cv_func_printf_flag_grouping" in
+                      case "$gl_cv_func_printf_positions" in
                         *yes)
-                          case "$gl_cv_func_printf_flag_zero" in
+                          case "$gl_cv_func_printf_flag_grouping" in
                             *yes)
-                              # vsprintf exists and is already POSIX compliant.
-                              gl_cv_func_vsprintf_posix=yes
+                              case "$gl_cv_func_printf_flag_zero" in
+                                *yes)
+                                  # vsprintf exists and is already POSIX
+                                  # compliant.
+                                  gl_cv_func_vsprintf_posix=yes
+                                  ;;
+                              esac
                               ;;
                           esac
                           ;;
@@ -46,6 +52,7 @@
       ;;
   esac
   if test $gl_cv_func_vsprintf_posix = no; then
+    gl_PREREQ_VASNPRINTF_LONG_DOUBLE
     gl_PREREQ_VASNPRINTF_DIRECTIVE_A
     gl_PREREQ_VASNPRINTF_DIRECTIVE_F
     gl_PREREQ_VASNPRINTF_FLAG_GROUPING
--- a/modules/fprintf-posix
+++ b/modules/fprintf-posix
@@ -12,6 +12,7 @@
 vasnprintf
 isnan-nolibm
 isnanl-nolibm
+frexpl-nolibm
 printf-frexp
 printf-frexpl
 signbit
--- a/modules/snprintf-posix
+++ b/modules/snprintf-posix
@@ -11,6 +11,7 @@
 vasnprintf
 isnan-nolibm
 isnanl-nolibm
+frexpl-nolibm
 printf-frexp
 printf-frexpl
 signbit
--- a/modules/sprintf-posix
+++ b/modules/sprintf-posix
@@ -11,6 +11,7 @@
 vasnprintf
 isnan-nolibm
 isnanl-nolibm
+frexpl-nolibm
 printf-frexp
 printf-frexpl
 signbit
--- a/modules/vasnprintf
+++ b/modules/vasnprintf
@@ -2,6 +2,7 @@
 vsprintf with automatic memory allocation and bounded output size.
 
 Files:
+lib/float+.h
 lib/printf-args.h
 lib/printf-args.c
 lib/printf-parse.h
--- a/modules/vasnprintf-posix
+++ b/modules/vasnprintf-posix
@@ -10,6 +10,7 @@
 vasnprintf
 isnan-nolibm
 isnanl-nolibm
+frexpl-nolibm
 printf-frexp
 printf-frexpl
 signbit
--- a/modules/vasprintf-posix
+++ b/modules/vasprintf-posix
@@ -10,6 +10,7 @@
 vasnprintf
 isnan-nolibm
 isnanl-nolibm
+frexpl-nolibm
 printf-frexp
 printf-frexpl
 signbit
--- a/modules/vfprintf-posix
+++ b/modules/vfprintf-posix
@@ -12,6 +12,7 @@
 vasnprintf
 isnan-nolibm
 isnanl-nolibm
+frexpl-nolibm
 printf-frexp
 printf-frexpl
 signbit
--- a/modules/vsnprintf-posix
+++ b/modules/vsnprintf-posix
@@ -11,6 +11,7 @@
 vasnprintf
 isnan-nolibm
 isnanl-nolibm
+frexpl-nolibm
 printf-frexp
 printf-frexpl
 signbit
--- a/modules/vsprintf-posix
+++ b/modules/vsprintf-posix
@@ -11,6 +11,7 @@
 vasnprintf
 isnan-nolibm
 isnanl-nolibm
+frexpl-nolibm
 printf-frexp
 printf-frexpl
 signbit