public inbox for newlib@sourceware.org
 help / color / mirror / Atom feed
* Fwd: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed value is incorrectly rounded
       [not found] <CAL9Mx1uMOz2wfqbMpD_xfA=D9JkpFzVz6AR_DKHK34AvrGOP6w@mail.gmail.com>
@ 2021-11-03 21:26 ` Pavel M
  2021-11-04 12:24   ` Corinna Vinschen
  0 siblings, 1 reply; 25+ messages in thread
From: Pavel M @ 2021-11-03 21:26 UTC (permalink / raw)
  To: newlib

---------- Forwarded message ---------
From: Pavel M <pavel.morozkin@gmail.com>
Date: Sat, 12 Jun 2021 at 23:45
Subject: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed
value is incorrectly rounded
To: <cygwin@cygwin.com>


Sample code (t903.c):
#include <stdio.h>
int main(void)
{
    printf("%.43f\n", 0x1.52f8a8e32e982p-140);
    return 0;
}

Invocations:
# gcc on Windows 10 (Cygwin)
$ gcc t903.c -Wall -Wextra -std=c11 -pedantic -Wfatal-errors && ./a.exe
0.0000000000000000000000000000000000000000010

$ gcc --version
gcc (GCC) 11.1.0

# gcc on Linux
$ gcc t903.c -Wall -Wextra -std=c11 -pedantic -Wfatal-errors && ./a.exe
0.0000000000000000000000000000000000000000009

# clang on Windows
$ clang t903.c -Wall -Wextra -std=c11 -ffp-model=strict -pedantic
-Wfatal-errors && ./a.exe
0.0000000000000000000000000000000000000000009

# cl on Windows
$ cl t903.c /std:c11 /Za /fp:strict && ./t903.exe
0.0000000000000000000000000000000000000000009

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed value is incorrectly rounded
  2021-11-03 21:26 ` Fwd: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed value is incorrectly rounded Pavel M
@ 2021-11-04 12:24   ` Corinna Vinschen
  2021-11-04 16:48     ` Keith Packard
  2021-11-28  7:43     ` Takashi Yano
  0 siblings, 2 replies; 25+ messages in thread
From: Corinna Vinschen @ 2021-11-04 12:24 UTC (permalink / raw)
  To: Pavel M; +Cc: newlib

On Nov  4 00:26, Pavel M wrote:
> ---------- Forwarded message ---------
> From: Pavel M <pavel.morozkin@gmail.com>
> Date: Sat, 12 Jun 2021 at 23:45
> Subject: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed
> value is incorrectly rounded
> To: <cygwin@cygwin.com>
> 
> 
> Sample code (t903.c):
> #include <stdio.h>
> int main(void)
> {
>     printf("%.43f\n", 0x1.52f8a8e32e982p-140);
>     return 0;
> }
> 
> Invocations:
> # gcc on Windows 10 (Cygwin)
> $ gcc t903.c -Wall -Wextra -std=c11 -pedantic -Wfatal-errors && ./a.exe
> 0.0000000000000000000000000000000000000000010
> 
> $ gcc --version
> gcc (GCC) 11.1.0
> 
> # gcc on Linux
> $ gcc t903.c -Wall -Wextra -std=c11 -pedantic -Wfatal-errors && ./a.exe
> 0.0000000000000000000000000000000000000000009

Newlib's ldtoa implementation is lacking.  It's using an algorithm which
defines an upper bound of digits to return to the caller, and currently
the number of digits is retricted to 42.

I was able to raise the max number of digits to 1023 in Newlib's ldtoa,
and I'm going to push the patch in a bit.

However, a much better fix would be to switch to gdtoa, as the BSDs and
Mingw64 do.

Is anybody here willing to take a look and change Newlib to gdtoa?


Thanks,
Corinna


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed value is incorrectly rounded
  2021-11-04 12:24   ` Corinna Vinschen
@ 2021-11-04 16:48     ` Keith Packard
  2021-11-04 17:27       ` Dave Nadler
  2021-11-04 20:57       ` Corinna Vinschen
  2021-11-28  7:43     ` Takashi Yano
  1 sibling, 2 replies; 25+ messages in thread
From: Keith Packard @ 2021-11-04 16:48 UTC (permalink / raw)
  To: Corinna Vinschen, Pavel M; +Cc: newlib

[-- Attachment #1: Type: text/plain, Size: 823 bytes --]

Corinna Vinschen <vinschen@redhat.com> writes:

> Is anybody here willing to take a look and change Newlib to gdtoa?

It might be useful for newlib to adopt the Ryū floating point conversion
code developed by Ulf Adams (currently at Google). This does correct
double conversion in 128 bits, avoiding need for arbitrary precision
math and any allocations.

        https://dl.acm.org/doi/10.1145/3360595

There is a BSD licensed implementation of the core algorithm available
on github; adopting that into complete printf/scanf implementations
isn't a huge amount of work. picolibc uses this implementation.

A friend of mine posited that this could be done, and got started on it
in grad school about 20 years ago. It was very nice to see someone
actually take the time to make it happen.

-- 
-keith

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed value is incorrectly rounded
  2021-11-04 16:48     ` Keith Packard
@ 2021-11-04 17:27       ` Dave Nadler
  2021-11-04 17:58         ` Keith Packard
  2021-11-04 20:57       ` Corinna Vinschen
  1 sibling, 1 reply; 25+ messages in thread
From: Dave Nadler @ 2021-11-04 17:27 UTC (permalink / raw)
  To: Keith Packard; +Cc: newlib

Keith, this Ryū implementation also removes use of malloc in FP 
conversion right?
That would solve lots of problems in the embedded world.
Thanks,
Best Regards, Dave

On 11/4/2021 12:48 PM, Keith Packard wrote:
> Corinna Vinschen<vinschen@redhat.com>  writes:
>
>> Is anybody here willing to take a look and change Newlib to gdtoa?
> It might be useful for newlib to adopt the Ryū floating point conversion
> code developed by Ulf Adams (currently at Google). This does correct
> double conversion in 128 bits, avoiding need for arbitrary precision
> math and any allocations.
>
>          https://dl.acm.org/doi/10.1145/3360595
>
> There is a BSD licensed implementation of the core algorithm available
> on github; adopting that into complete printf/scanf implementations
> isn't a huge amount of work. picolibc uses this implementation.
>
> A friend of mine posited that this could be done, and got started on it
> in grad school about 20 years ago. It was very nice to see someone
> actually take the time to make it happen.


-- 
Dave Nadler, USA East Coast voice (978) 263-0097,drn@nadler.com, Skype
  Dave.Nadler1

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed value is incorrectly rounded
  2021-11-04 17:27       ` Dave Nadler
@ 2021-11-04 17:58         ` Keith Packard
  2021-11-04 21:28           ` Brian Inglis
  0 siblings, 1 reply; 25+ messages in thread
From: Keith Packard @ 2021-11-04 17:58 UTC (permalink / raw)
  To: Dave Nadler; +Cc: newlib

[-- Attachment #1: Type: text/plain, Size: 336 bytes --]

Dave Nadler <drn@nadler.com> writes:

> Keith, this Ryū implementation also removes use of malloc in FP 
> conversion right?
> That would solve lots of problems in the embedded world.
> Thanks,
> Best Regards, Dave

Yes. This is why picolibc uses this code (picolibc also removes malloc
in the rest of stdio).

-- 
-keith

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed value is incorrectly rounded
  2021-11-04 16:48     ` Keith Packard
  2021-11-04 17:27       ` Dave Nadler
@ 2021-11-04 20:57       ` Corinna Vinschen
  1 sibling, 0 replies; 25+ messages in thread
From: Corinna Vinschen @ 2021-11-04 20:57 UTC (permalink / raw)
  To: newlib

[Please don't CC me on list replies.  I set "Reply-To:" for a reason.
 Thanks!]

On Nov  4 09:48, Keith Packard wrote:
> Corinna Vinschen <vinschen@redhat.com> writes:
> 
> > Is anybody here willing to take a look and change Newlib to gdtoa?
> 
> It might be useful for newlib to adopt the Ryū floating point conversion
> code developed by Ulf Adams (currently at Google). This does correct
> double conversion in 128 bits, avoiding need for arbitrary precision
> math and any allocations.
> 
>         https://dl.acm.org/doi/10.1145/3360595
> 
> There is a BSD licensed implementation of the core algorithm available
> on github; adopting that into complete printf/scanf implementations
> isn't a huge amount of work. picolibc uses this implementation.

Sounds like a great idea, too.  This may drop code size as well, which
is always good.


Thanks,
Corinna


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed value is incorrectly rounded
  2021-11-04 17:58         ` Keith Packard
@ 2021-11-04 21:28           ` Brian Inglis
  2021-11-05  2:54             ` Keith Packard
  0 siblings, 1 reply; 25+ messages in thread
From: Brian Inglis @ 2021-11-04 21:28 UTC (permalink / raw)
  To: newlib

On 2021-11-04 11:58, Keith Packard wrote:
> Dave Nadler <drn@nadler.com> writes:
> 
>> Keith, this Ryū implementation also removes use of malloc in FP
>> conversion right?
>> That would solve lots of problems in the embedded world.
>> Thanks,
>> Best Regards, Dave
> 
> Yes. This is why picolibc uses this code (picolibc also removes malloc
> in the rest of stdio).

Keith,

I believe the implementation uses tables: that could be an issue in the 
embedded world; can you comment on the table space required for 32, 64, 
128 bits?

-- 
Take care. Thanks, Brian Inglis, Calgary, Alberta, Canada

This email may be disturbing to some readers as it contains
too much technical detail. Reader discretion is advised.
[Data in binary units and prefixes, physical quantities in SI.]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed value is incorrectly rounded
  2021-11-04 21:28           ` Brian Inglis
@ 2021-11-05  2:54             ` Keith Packard
  2021-11-05 16:00               ` Steven Abner
  2021-11-08  9:57               ` Corinna Vinschen
  0 siblings, 2 replies; 25+ messages in thread
From: Keith Packard @ 2021-11-05  2:54 UTC (permalink / raw)
  To: Brian Inglis, newlib

[-- Attachment #1: Type: text/plain, Size: 1624 bytes --]

Brian Inglis <Brian.Inglis@SystematicSw.ab.ca> writes:

> Keith,
>
> I believe the implementation uses tables: that could be an issue in the 
> embedded world; can you comment on the table space required for 32, 64, 
> 128 bits?

I don't have a long double implementation of the ryu code; 128 bit
doubles would require 256 bit arithmetic (add/mul, fortunately no
divide), and a bunch of analysis to generate the table values. The
sample code on github only provides 32- and 64- bit
implementations. Picolibc currently has an imprecise printf
implementation for long double that works for Intel (80 bit) Risc-V
(IEEE 128 bit) and Power PC ('double double' 128-bit).

The total size of printf using the Ryu code is substantially smaller
than that required by the current newlib bits as it doesn't drag in the
arbitrary precision functions. The tables are 830 bytes.

I did a presentation in September at the Embedded Linux Conference where
I showed some complete binary numbers that involved printf

        #include <stdio.h>

        void main(void)
        {
                printf("%g\n", 355.0/113.0);
        }

On Cortex M3 hardware (an STM32L152 discovery board):

                             ROM     RAM
    Picolibc 64-bit         6872      24
    Picolibc 32-bit         5360      24
    Newlib 64-bit          15584    1200+1084

The newlib number for RAM includes both static and sbrk amounts;
picolibc doesn't call sbrk for this example. These are complete
examples, including semihosting code to display the numbers using
openocd on the target hardware.

-- 
-keith

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed value is incorrectly rounded
  2021-11-05  2:54             ` Keith Packard
@ 2021-11-05 16:00               ` Steven Abner
  2021-11-06 12:06                 ` Steven Abner
  2021-11-08  9:57               ` Corinna Vinschen
  1 sibling, 1 reply; 25+ messages in thread
From: Steven Abner @ 2021-11-05 16:00 UTC (permalink / raw)
  To: Newlib

[-- Attachment #1: Type: text/plain, Size: 3030 bytes --]


  If you are bold enough to try something different here is some code
to examine. I could butcher up something to create full implementation
outside my code. Testing showed faster than gdtoa. Low precision
routines around 0 exponent show near tie. Added code to show how I
have connected to my printf:

      case 'a':  case 'e':  case 'f':  case 'g':
      case 'A':  case 'E':  case 'F':  case 'G':
          /* gcc doesn't permit floats, it converts to doubles */
      {
        unsigned char *(*toStr)(uint32_t [5], unsigned char **,
                                                      int, int, int, 
unsigned);
        uint32_t w160[5];
        uint32_t dp;  /* 4 byte decimal point param */
        int32_t sch;
        __decimalLoad((unsigned char*)&dp, params);
        if ((ch | 0x20) == 'a')  ch -= 'A', toStr = realtohex;
        else                     ch -= 'E', toStr = realtostr;
        sch = format[-1];
          /* force 128bit long double into quad parsing */
        if (sch == 'q') {
#if (__LDBL_MANT_DIG__ != 64)
    quad_parse:
#endif
          sch = (('q' << 8) | ch);
          qtow(((vPtr == NULL) ? va_arg(arg, octle) : *(octle *)vPtr), 
w160);
        } else if (sch == 'L') {
#if (__LDBL_MANT_DIG__ != 64)
          goto quad_parse;
#endif
          sch = (('L' << 8) | ch);
          ldtow(((vPtr == NULL) ? va_arg(arg, long double) : *(long 
double *)vPtr), w160);
        } else {
          sch = (('l' << 8) | ch);
          dtow(((vPtr == NULL) ? va_arg(arg, double) : *(double 
*)vPtr), w160);
        }
        arg_flags |= (strBuf != buffer) << 7;
        strPtr = toStr(w160, &strBuf, sch, arg_prec, (int)arg_flags, 
dp);
      }
        if (strPtr == NULL)  goto error;

        val_ul = (n = (int)(strPtr - strBuf));
        strPtr = strBuf;
        arg_prec = 0;
        arg_flags &= ~ALT_PREFIX;
        if ((arg_flags & GRP_PREFIX) != 0)
          strPtr = __localizeReal(strPtr, &n), val_ul = n;
        goto L300;

This is part of my sys/types so above 'octle' doesn't look so strange:

typedef union {
#if __SIZEOF_INT128__ == 16
  uint128_t   uo;
#endif
#ifdef __BIG_ENDIAN__
  struct { uint64_t ull1, ull0; } ulls;
  struct { uint32_t ul3, ul2, ul1, ul0; } uls;
  struct { uint16_t us7, us6, us5, us4, us3, us2, us1, us0; } uss;
#else  /* __LITTLE_ENDIAN__ */
  struct { uint64_t ull0, ull1; } ulls;
  struct { uint32_t ul0, ul1, ul2, ul3; } uls;
  struct { uint16_t us0, us1, us2, us3, us4, us5, us6, us7; } uss;
#endif
} octle;

And from sysdep.h for attached ldtostr:

/* endian break down of uint64_t */
#ifdef __BIG_ENDIAN__
  typedef struct {  uint16_t w3; uint16_t w2; uint16_t w1; uint16_t w0; 
 } _ull_ws;
  typedef struct {  uint32_t hi; uint32_t lo;  } _ull_ls;
#elif defined (__LITTLE_ENDIAN__)
  typedef struct {  uint16_t w0; uint16_t w1; uint16_t w2; uint16_t w3; 
 } _ull_ws;
  typedef struct {  uint32_t lo; uint32_t hi;  } _ull_ls;
#else
  #error: undefined endianness
#endif
typedef union {  uint64_t ull;  _ull_ls  uls;  _ull_ws  uss;  } _ull_t;

Steve



[-- Attachment #2: ldtostr.c.zip --]
[-- Type: application/zip, Size: 19500 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed value is incorrectly rounded
  2021-11-05 16:00               ` Steven Abner
@ 2021-11-06 12:06                 ` Steven Abner
  2021-11-06 23:25                   ` Steven Abner
  0 siblings, 1 reply; 25+ messages in thread
From: Steven Abner @ 2021-11-06 12:06 UTC (permalink / raw)
  To: Newlib

[-- Attachment #1: Type: text/plain, Size: 936 bytes --]


  I didn't mean to stop the conversion! Here is a butchered, self 
contained use.
Hopefully this provides better means to evaluate. Low precision code 
removed,
since I assume embedded systems won't use. In case of not obvious, 
entry from
printf() into realto functions expected a 64 byte buffer to write to. 
realto functions
has a static buffer to cover double range. It uses malloc() if it 
determines that
with localization and precision, if it needs to increase past 64 byte 
return. realto
functions includes decimal encoding of up to 4 byte utf8 encoding, 
which at the
time of writing no script came close to, think 2 bytes was max?
  There is commented out code for 32 bit float, but not sure would ever 
get used.

  sample use:
steven@steven-ryzen:~/Development/Projects$ gcc  newlib_printf_demo.c 
-o nldemo
steven@steven-ryzen:~/Development/Projects$ ./nldemo
0.0000000000000000000000000000000000000000009
3.14159

Steve

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: newlib_printf_demo.c --]
[-- Type: text/x-csrc, Size: 72783 bytes --]

#include <stdarg.h>

/* must define a data model */
#ifndef __LP64__
 #define __LP32__  1
#endif
/* found out 24 Jan 2019 from new computer build */
/* gcc does not define __LITTLE_ENDIAN__ or __BIG_ENDIAN__ */
#ifndef __LITTLE_ENDIAN__
 #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
  #define __LITTLE_ENDIAN__
 #else
  #define __BIG_ENDIAN__
 #endif
#endif

typedef signed char         int8_t;
typedef unsigned char       uint8_t;
typedef short               int16_t;
typedef unsigned short      uint16_t;
typedef int                 int32_t;
typedef unsigned int        uint32_t;
typedef long long           int64_t;
typedef unsigned long long  uint64_t;

#if __SIZEOF_INT128__ == 16
typedef __int128            int128_t;
typedef unsigned __int128   uint128_t;
#endif

typedef union {
#if __SIZEOF_INT128__ == 16
 uint128_t   uo;
#endif
#ifdef __BIG_ENDIAN__
 struct { uint64_t ull1, ull0; } ulls;
 struct { uint32_t ul3, ul2, ul1, ul0; } uls;
 struct { uint16_t us7, us6, us5, us4, us3, us2, us1, us0; } uss;
#else  /* __LITTLE_ENDIAN__ */
 struct { uint64_t ull0, ull1; } ulls;
 struct { uint32_t ul0, ul1, ul2, ul3; } uls;
 struct { uint16_t us0, us1, us2, us3, us4, us5, us6, us7; } uss;
#endif
} octle;
/* defined in as_stdio.h */
#define quadruple octle

/* gcc appears to only defines _LP64 __LP64__ (2019) */
/* only models with 64bit ints */
#if defined (__ILP64__) || defined (__SILP64__)
typedef  int64_t      intmax_t;
typedef uint64_t     uintmax_t;
#elif defined (__LP32__)
typedef  int16_t      intmax_t;
typedef uint16_t     uintmax_t;
#else /* __LP64__ has 32bit int */
typedef  int32_t      intmax_t;
typedef uint32_t     uintmax_t;
#endif

/* these are all register size based */
#if defined (__LP32__) || defined (__ILP32__)
typedef  int32_t      intptr_t;
typedef uint32_t     uintptr_t;
#define __SIZEOF_REGISTER_T__ 4
#define __SIZEOF_SIZE_T__ 4
#else
typedef  int64_t      intptr_t;
typedef uint64_t     uintptr_t;
#define __SIZEOF_REGISTER_T__ 8
#define __SIZEOF_SIZE_T__ 8
#endif

typedef  intptr_t   register_t;
typedef  intptr_t    _intptr_t;
typedef uintptr_t   u_intptr_t;
typedef  intptr_t      ssize_t;   /* Used for a count of bytes or an error indication. */
typedef uintptr_t       size_t;   /* Used for sizes of objects. */
typedef  intptr_t    ptrdiff_t;   /* Used for subtracting two pointers. */
typedef uintptr_t      clock_t;   /* Used for system times in clock ticks or CLOCKS_PER_SEC . */
typedef  intptr_t       time_t;   /* Used for time in seconds. */

#define NULL        ((void *)0)

#ifdef __APPLE__
  #define FILE FILE_mac
#elif defined __linux  /* !__APPLE__ */
  typedef struct _IO_FILE _IO_FILE;
  #define FILE _IO_FILE
#else    /* !__APPLE__ !__CYGWIN__ !__linux */
  #error: unknown FILE structure
#endif  /* FILE * */
extern void *malloc(size_t);
extern void free(void *);
extern int puts(const char *);
size_t fwrite(const void *restrict, size_t, size_t, FILE *restrict);
extern FILE* stdout;

  /* in ldtostr.c */
extern unsigned char *
realtostr(uint32_t [5], unsigned char **, int, int, int, unsigned);
extern unsigned char *
realtohex(uint32_t [5], unsigned char **, int, int, int, unsigned);

  /* guarentee use of this printf */
int phx_printf(const char *format, ...);

/* local defines */
#define ALT_PREFIX   0002
#define PREC_PREFIX  0400

/* converts to w160 type used by realtostr,
 * current use as 63-63 with implicit '1"-implicit nil */
static void
qtow(quadruple qdbl, uint32_t w160[5]) {

    /* required strict aliasing conversion */
  octle *iqdbl;
  unsigned char *cqdbl = (unsigned char*)&qdbl;
  iqdbl = (octle*)cqdbl;

    /* long double shifted to high bit of uint128_t, with implicit
     * bit becoming explicit at bit 127 */
  w160[4] = iqdbl->uss.us7;
  *(uint64_t*)&w160[2] = (iqdbl->ulls.ull1 << 15)
                       | (iqdbl->uls.ul1 >> 17);
    /* lower 64 set same position as upper, upper gets 'implicit '1' */
  iqdbl->uss.us3 &= 1;
  *(uint64_t*)&w160[0] = (iqdbl->ulls.ull0 << 14);
    /* place implicit bit for all but denormal */
  w160[3] |= (w160[4] != 0) << 31;
}

/* converts to w160 type used by realtostr */
static void
ldtow(long double ldbl, uint32_t w160[5]) {

    /* required strict aliasing conversion */
  octle *ildbl;
  unsigned char *cldbl = (unsigned char*)&ldbl;
  ildbl = (octle*)cldbl;

  w160[4] = ildbl->uss.us4;
  *(uint64_t*)&w160[2] = ildbl->ulls.ull0;
  *(uint64_t*)w160 = 0;
}

/* converts to w160 type used by realtostr */
static void
dtow(double dbl, uint32_t w160[5]) {

    /* required strict aliasing conversion */
  uint64_t *idbl;
  unsigned char *cdbl = (unsigned char*)&dbl;
  idbl = (uint64_t*)cdbl;
  *(uint64_t*)&w160[2] = *idbl << 11;
  w160[4] = (uint32_t)(*idbl >> 52);

  if ((w160[4] & 0x7FF) == 0x7FF)
    w160[4] = (w160[4] << 4) | 0x000F;
  else if (((w160[4] & 0x7FF) == 0) && (*(uint64_t*)&w160[2] == 0)) {
    w160[4] <<= 4;
  } else {
    w160[4] = ((w160[4] & 0x7FF) + 16383 - 1023) | ((w160[4] & 0x800) << 4);
      /* place implicit bit for all but denormal */
    w160[3] |= ((w160[4] & 0x7FFF) != 0x3C00) << 31;
  }
  *(uint64_t*)w160 = 0;
}

/* not sure usefulness, gcc's code forces doubles in printf. Not sure of overhead
 * created by gcc and/or POSIX requirement of double argument.
static void
ftow(float flt, uint32_t w160[5]) {

  *(uint64_t*)w160 = 0;
  *(uint64_t*)&w160[2] = 0;
  w160[4] = (*(uint32_t*)&flt) >> 23;
  w160[3] = (*(uint32_t*)&flt) << 9;
  if ((w160[4] & 0xFF) == 0xFF)
    w160[4] = (w160[4] << 8) | 0x00FF;
  else
    w160[4] = ((w160[4] & 0xFF) + 16383 - 127) | ((w160[4] & 0x100) << 7);
}
*/


/* locate dependent utf8 loading of decimal point */
/* for newlib demo return ascii */
struct __params {
  unsigned char **s;
  unsigned char *slimit;
  //locale_t ld;
};

static unsigned
__decimalLoad(unsigned char *s, struct __params *params) {
  (void)params;
  *s = '.';
  return (1);
}

#define BUFSTRSIZE     64
unsigned char *
__format(const unsigned char *format, struct __params *params, va_list arg) {

  unsigned char   buffer[BUFSTRSIZE]; /* size of 64bit binary ouput  no prec,
                                       * field nor alt goes here */
  unsigned char  **s = params->s;
  unsigned char  *slimit = params->slimit;
  unsigned char  *strBuf = buffer, *strPtr, *strEnd, *sPtr = *s;
  uint64_t        val_ull;            /* for any sizeof() > 4 bytes, if
                                       * unsigned is 64bits it will bypass
                                       * val_ul to go here */
  unsigned        val_ul;             /* need unsigned instead of unsigned long
                                       * incase unsigned 64bits */
  uint32_t        arg_flags;          /* arg_flags needs to be 32bits??? */
  int             arg_prec, arg_field, n;
  unsigned char   ch, sign, arg_size; /* arg_size max value is sizeof(long
                                       * double) if int goes 128bits still
                                       * within char size */
  uintptr_t      *vPtr = NULL;

  --format;
  goto L500;
  do {

    strEnd = strPtr = &strBuf[BUFSTRSIZE];
    arg_flags = 0;
    arg_size  = sizeof(int);
    arg_prec  = arg_field = -1;
    sign = 0;

  next_ch:
    ch = *++format;
  EO_EXTENSIONS:
    if (!ch) break;
    switch (ch) {

        /* Removed Flags for demo */
        /* Removed some Length modifiers for demo */
      case 'l':
        if ((ch = *++format) != 'l') {   /* and ll */
                  arg_size = sizeof(long);         goto EO_EXTENSIONS;  }
                  arg_size = sizeof(long long);    goto next_ch;
      case 'q':   arg_size = sizeof(octle);        goto next_ch;	/* 128bit */
      case 'L':   arg_size = sizeof(long double);  goto next_ch;	/* long double */

        /* Removed some Field-Width / Precision for demo */
      case '.':
        ch = *++format;
        arg_flags |= PREC_PREFIX;

      case '1': case '2': case '3':
      case '4': case '5': case '6':
      case '7': case '8': case '9':
        n = ch - 48;
        while ((unsigned)((ch = *++format) - '0') <= 9)
          n = (n * 10) + (ch - '0');
        if (ch != '$') {
          if (arg_flags & PREC_PREFIX)  arg_prec = n;
          else  arg_field = n;
          arg_flags &= ~PREC_PREFIX;
          goto EO_EXTENSIONS;
        }
        goto next_ch;

        /* Removed all Formats... but real */
      case 'a':  case 'e':  case 'f':  case 'g':
      case 'A':  case 'E':  case 'F':  case 'G':
          /* gcc doesn't permit floats, it converts to doubles */
      {
        unsigned char *(*toStr)(uint32_t [5], unsigned char **,
                                                      int, int, int, unsigned);
        uint32_t w160[5];
        uint32_t dp;  /* 4 byte decimal point param */
        int32_t sch;
        __decimalLoad((unsigned char*)&dp, params);
        if ((ch | 0x20) == 'a')  ch -= 'A', toStr = realtohex;
        else                     ch -= 'E', toStr = realtostr;
        sch = format[-1];
          /* force 128bit long double into quad parsing */
        if (sch == 'q') {
#if (__LDBL_MANT_DIG__ != 64)
    quad_parse:
#endif
          sch = (('q' << 8) | ch);
          qtow(((vPtr == NULL) ? va_arg(arg, octle) : *(octle *)vPtr), w160);
        } else if (sch == 'L') {
#if (__LDBL_MANT_DIG__ != 64)
          goto quad_parse;
#endif
          sch = (('L' << 8) | ch);
          ldtow(((vPtr == NULL) ? va_arg(arg, long double) : *(long double *)vPtr), w160);
        } else {
          sch = (('l' << 8) | ch);
          dtow(((vPtr == NULL) ? va_arg(arg, double) : *(double *)vPtr), w160);
        }
        arg_flags |= (strBuf != buffer) << 7;
        strPtr = toStr(w160, &strBuf, sch, arg_prec, (int)arg_flags, dp);
      }
        if (strPtr == NULL)  goto error;

        val_ul = (n = (int)(strPtr - strBuf));
        strPtr = strBuf;
        arg_prec = 0;
        arg_flags &= ~ALT_PREFIX;
          /* grouping code removed for demo */
    } /* end switch */
                        /* main output section */
      /* adjust the different output factors */
    if ((arg_prec -= n) < 0) arg_prec = 0;
    if ((arg_field -= (arg_prec + val_ul)) < 0) arg_field = 0;
      /* is there output space? removed for demo */
      /* different formatting removed for demo */
    if (sign != 0) *sPtr++ = sign;
    if (arg_prec)  do *sPtr++ = '0'; while ((--arg_prec));
    if (n & 1)
               *sPtr++ = *strPtr++;
    if (n & 2) {
      *(int16_t *)sPtr = *(int16_t *)strPtr;
                  sPtr += sizeof(int16_t); strPtr += sizeof(int16_t);  }
    if ((n >>= 2))
      do {
      *(int32_t *)sPtr = *(int32_t *)strPtr;
                  sPtr += sizeof(int32_t); strPtr += sizeof(int32_t);
      } while ((--n));
    if (arg_field)  do  *sPtr++ = ' ';  while ((--arg_field));

      /* parsing of format string */
    do {
L500: ch = *++format;
      if ((sPtr >= slimit)) {
        --format;
          /* removed buffer extreme */
        puts("this is demo, don't be cute!");
        goto end;
      }
      *sPtr = ch;
      if (!ch) goto end;
      if (ch == '%')  break;
      sPtr++;
    } while (1);
  } while (1);
  *sPtr = 0;
end:
  if (strBuf != buffer)  free(strBuf);
  return sPtr;
error:
  if (strBuf != buffer)  free(strBuf);
  *--sPtr = 0;
  return (*s - 12);
}

#define FORMAT_LINE_MAX  4096

static int
phx_vfprintf(FILE *stream, const char *format, va_list arg) {
//_vfprintf(FILE *stream, const char *format, va_list arg, locale_t ld) {

  unsigned char  *sPtr, *wrPtr, *rdPtr;
  ssize_t         to_write;
  size_t          u8Sz  = FORMAT_LINE_MAX;
  struct __params params;

    /* make sure writable stream, Remove writable for demo */
  if ( (stream == NULL) //|| (!_io_writable(stream))
      || (format == NULL) )  return -1;

    /* create buffer to 'write' into */
  if ((wrPtr = (unsigned char*)malloc(u8Sz)) == NULL)  return -1;

    /* label rdPtr as <format>. If conversion, rdPtr will be allocated
     * and filled with UTF-8 version of <format> */
  rdPtr = (unsigned char*)format;

                        /* UTF-8 <format> input */
  params.s           = &wrPtr;
  params.slimit      = (wrPtr + u8Sz);
  //params.ld          = ld;
  sPtr = __format((const unsigned char *)rdPtr, &params, arg);

                        /* UTF-8 text ouput */
  if ((to_write = (ssize_t)(sPtr - wrPtr)) > 0)
    to_write = fwrite((const void *)wrPtr, (size_t)1, (size_t)to_write, stream);
  free(wrPtr);
  return (int)to_write;
}

int
phx_printf(const char *format, ...) {

  int     written;
  va_list arg;

  va_start(arg, format);
    written = phx_vfprintf((FILE *)stdout, format, arg);
    //written = _vfprintf((FILE *)stdout, format, arg, NULL);
  va_end(arg);
  return written;
}

/*
 *  realtostr - convert real numbers to formated latn numerical string
 *  realtohex - convert real numbers to formated hexadecimal string
 *  qtold - convert quadruple-precision number to a system defined long double
 *  ldtod - convert a system defined long double to a double-precision number
 */
        /* C langauge - string literals */
#ifdef __BIG_ENDIAN__
 #define cconst16_t(a,b)     (uint16_t)(((uint8_t)(a) << 8) | (uint8_t)(b))
 #define cconst32_t(a,b,c,d) (uint32_t)(((uint8_t)(a) << 24) | ((uint8_t)(b) << 16) | ((uint8_t)(c) << 8) | (uint8_t)(d))
#else
 #define cconst16_t(a,b)     (uint16_t)(((uint8_t)(b) << 8) | (uint8_t)(a))
 #define cconst32_t(a,b,c,d) (uint32_t)(((uint8_t)(d) << 24) | ((uint8_t)(c) << 16) | ((uint8_t)(b) << 8) | (uint8_t)(a))
#endif
        /* compiler convience macro */
#ifndef __GNUC_PREREQ
 #if defined __GNUC__ && defined __GNUC_MINOR__
  #define __GNUC_PREREQ(major,minor) \
    (((__GNUC__ << 16) + __GNUC_MINOR__) >= (((major) << 16) + (minor)))
 #else
  #define __GNUC_PREREQ(major,minor) 0
 #endif
#endif  /* __GNUC_PREREQ */

#ifndef __LDBL_MANT_DIG__
#define __LDBL_MANT_DIG__  LDBL_MANT_DIG
#endif

/* endian break down of uint64_t */
#ifdef __BIG_ENDIAN__
  typedef struct {  uint16_t w3; uint16_t w2; uint16_t w1; uint16_t w0;  } _ull_ws;
  typedef struct {  uint32_t hi; uint32_t lo;  } _ull_ls;
#elif defined (__LITTLE_ENDIAN__)
  typedef struct {  uint16_t w0; uint16_t w1; uint16_t w2; uint16_t w3;  } _ull_ws;
  typedef struct {  uint32_t lo; uint32_t hi;  } _ull_ls;
#else
  #error: undefined endianness
#endif
typedef union {  uint64_t ull;  _ull_ls  uls;  _ull_ws  uss;  } _ull_t;

#ifdef __ppc__
  #define CNTLZW(x,y) \
    do __asm__("cntlzw %0,%1" : "=r" (x) : "r" (y)); while(0)
#elif defined (__i386__)
  #define CNTLZW(x,y) \
    do {  __asm__("bsr %1,%0" : "=r" (x) : "r" (y));  x = 31 - x;  } while(0)
#elif defined (__x86_64__)
  #define CNTLZW(x,y) \
    do {  __asm__("bsr %1,%0" : "=r" (x) : "r" (y));  x = 31 - x;  } while(0)
  #define CNTLZD(x,y) \
    do {  __asm__("bsr %1,%0" : "=r" (x) : "r" (y));  x = 63 - x;  } while(0)
#else
    /* about 50% slower, 3 instructions vs 31 instructions */
  #define CNTLZW(x,y) \
    do {  unsigned t = y;   \
      t |= t >> 1;          \
      t |= t >> 2;          \
      t |= t >> 4;          \
      t |= t >> 8;          \
      t |= t >> 16;         \
      t = t - ((t >> 1) & 0x55555555);                            \
      t = (t & 0x33333333) + ((t >> 2) & 0x33333333);             \
      x  = 32 - (((t + (t >> 4) & 0xF0F0F0F) * 0x1010101) >> 24); \
    } while (0);
#endif

  /* used for __fractional128 stack zeroing */
extern void *memset(void *, int, size_t);

long double qtold(quadruple);
double ldtod(long double);

#define _CARRY  1000000000000000000ULL          /* 0x 0DE0B6B3 A7640000 */

  /* for rounding */
static const uint64_t _fcarry[] = {
  5, 50, 500, 5000, 50000, 500000, 5000000, 50000000, 500000000, 5000000000ULL,
  50000000000ULL, 500000000000ULL, 5000000000000ULL, 50000000000000ULL, 500000000000000ULL,
  5000000000000000ULL, 50000000000000000ULL, 500000000000000000ULL,
  /*18*/
  1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000,
  10000000000ULL, 100000000000ULL, 1000000000000ULL, 10000000000000ULL, 100000000000000ULL,
  1000000000000000ULL, 10000000000000000ULL, 100000000000000000ULL, _CARRY
};
  /* for cases: nan, inf, hex */
static const char *_const_outStr =
  "0123456789abcdefnanpinfe0x0.00000123456789ABCDEFNANPINFE0X0.0000";

      /*** internal routines ***/
  /* generic, div() moved to 64_t to address endianess */
static uint64_t divlu2r(uint64_t) __attribute__ ((noinline));
static void  _ulltobuffer_18lr(uint64_t, unsigned char *) __attribute__ ((noinline));
static void  _ulltobuffer_nlr(uint64_t, unsigned char *, int) __attribute__ ((noinline));
static int   _first_digit(uint64_t);
  /* ldtostr specific */
static unsigned char *__n_char_sequence(uint32_t [5], unsigned char *, int);
static uint32_t __fractional(_ull_t *, _ull_t);
static uint32_t __fractional_128(_ull_t *, _ull_t);
static uint32_t __positive_exponent_fp(_ull_t *, int);
static uint32_t __negative_exponent_fp(_ull_t *, int);

/* from fprintf... needs to be the same */
#define ZERO_PREFIX  0001
#define ALT_PREFIX   0002
#define LEFT_PREFIX  0004
#define SIGN_PREFIX  0010
#define SPC_PREFIX   0020
#define STAR_PREFIX  0040
#define GRP_PREFIX   0100
#define USGN_PREFIX  0200
#define PREC_PREFIX  0400
#define ALLOC_BUF    USGN_PREFIX
#define BUFSTRSIZE     64

/* XXX using upper 16 to pass 'unit' max from
 calcation prior to entry of x_exponent */

#define UPPER_TYPE  0x20
#define IS_UPPER_TYPE(a)  (!((a) & UPPER_TYPE))
#define IS_QUAD(a)    ((uint8_t)((a) >> 8) == (uint8_t)'q')
#define IS_LDBL(a)    ((uint8_t)((a) >> 8) == (uint8_t)'L')
#define IS_DBL(a)     ((uint8_t)((a) >> 8) == (uint8_t)'l')
#define IS_FLT(a)     ((uint8_t)((a) >> 8) == 0)
#define TYPE_ZERO   0x40
#define IS_TYPE_ZERO(a)   ((a) & TYPE_ZERO)
#define TYPE_E  0
#define TYPE_F  1
#define TYPE_G  2
#define IS_TYPE_E(a)  (((a) & 3) == 0)
#define IS_TYPE_F(a)  ((a) & TYPE_F)
#define IS_TYPE_G(a)  ((a) & TYPE_G)
#define SURPRESS_NSEQ(a) (((a) & 4) != 0)

#pragma mark *** Support Mathematics ***

static uint64_t
divlu2r(uint64_t c) {

  _ull_t q;
  uint32_t mConst = 2305843009U;  // 2^61 / 10^9
  uint32_t tConst = 1000000000U;
  q.uls.hi = (uint32_t)(c >> 32);
  q.uls.lo = ((uint32_t)c);
  if (q.uls.hi != 0) {
    uint32_t shift;
    CNTLZW(shift, q.uls.hi);
    q.uls.hi = (uint32_t)((((q.uls.hi << shift) | (q.uls.lo >> (32 - shift)))
                                                    * (uint64_t)mConst) >> 32);
    if (shift > 3)  q.uls.hi >>= (shift - 3);
  } else {
    q.uls.hi = (uint32_t)(((q.uls.lo | 1) * (uint64_t)mConst) >> (32 + 29));
  }
  q.uls.lo = (uint32_t)(c - ((uint64_t)q.uls.hi * (uint32_t)tConst));
  if (q.uls.lo >= tConst)
    q.uls.hi += 1, q.uls.lo -= tConst;
  return q.ull;
}

static void
_ulltobuffer_18lr(uint64_t c, unsigned char *buf) {

  _ull_t a, b;
  int n;
  --buf;
    /* in 4.60, 2.30 fixed point integers */
  b.ull = (uint64_t)(((uint32_t)c) << 2) * 2882303762U;
  a.ull = (uint64_t)(((uint32_t)(c >> 32)) << 2) * 2882303762U;
  n = 9;
  goto L1;
  do {
    b.uls.hi = (((b.uls.hi << 4) >> 4) * 10) + (b.uls.lo >> 28);
    a.uls.hi = (((a.uls.hi << 4) >> 4) * 10) + (a.uls.lo >> 28);
    b.uls.lo <<= 4;
    a.uls.lo <<= 4;
L1: *++buf = (a.uls.hi >> 28) + '0';
    buf[9] = (b.uls.hi >> 28) + '0';
  } while ((--n));
}

/* went for speed */
static void
_ulltobuffer_nlr(uint64_t c, unsigned char *buf, int m) {

  _ull_t b;
  int n;
  --buf;
    /* in 4.60, 2.30 fixed point integers */
  c <<= 2;
  b.ull = (uint64_t)((uint32_t)(c >> 32)) * 2882303762U;
  n = (m <= 9) ? m : 9;
  m -= 9;
  goto L1;
  do {
    b.uls.hi = (((b.uls.hi << 4) >> 4) * 10) + (b.uls.lo >> 28);
    b.uls.lo <<= 4;
L1: *++buf = (b.uls.hi >> 28) + '0';
  } while ((--n));
  if (m > 0) {
    n = m;
    b.ull = (uint64_t)((uint32_t)c) * 2882303762U;
    goto L2;
    do {
      b.uls.hi = (((b.uls.hi << 4) >> 4) * 10) + (b.uls.lo >> 28);
      b.uls.lo <<= 4;
  L2: *++buf = (b.uls.hi >> 28) + '0';
    } while ((--n));
  }
}

/*#pragma GCC diagnostic ignored "-Wmisleading-indentation"*/
#if __GNUC_PREREQ(4,5)
 #pragma GCC diagnostic ignored "-Wmisleading-indentation"
#endif
/* uses 2 64s as swap loads, this prevents stalls */
/* returns 1 less than actual digits, the power of 10, or log10 value */
static int
_first_digit(uint64_t a) {

  _ull_t reg;
  const uint64_t *fc;
  uint64_t b;
  reg.ull = a;
  fc = _fcarry;
  if (reg.uls.hi) {
    a = fc[35];
    b = fc[34];
    if (reg.ull >= a)  return 17;  a = fc[33];
    if (reg.ull >= b)  return 16;  b = fc[32];
    if (reg.ull >= a)  return 15;  a = fc[31];
    if (reg.ull >= b)  return 14;  b = fc[30];
    if (reg.ull >= a)  return 13;  a = fc[29];
    if (reg.ull >= b)  return 12;  b = fc[28];
    if (reg.ull >= a)  return 11;
    if (reg.ull >= b)  return 10;
    return 9;
  } else {
    uint32_t c, d;
    c = (uint32_t)fc[27];
    d = (uint32_t)fc[26];
    if (reg.uls.lo >= c)  return 9;  c = (uint32_t)fc[25];
    if (reg.uls.lo >= d)  return 8;  d = (uint32_t)fc[24];
    if (reg.uls.lo >= c)  return 7;  c = (uint32_t)fc[23];
    if (reg.uls.lo >= d)  return 6;
    if (reg.uls.lo >= c)  return 5;
    if (reg.uls.lo >= 10000U)  return 4;
    if (reg.uls.lo >= 1000U)  return 3;
    if (reg.uls.lo >= 100U)  return 2;
    if (reg.uls.lo >= 10U)  return 1;
    return 0;
  }
}
/*#pragma GCC diagnostic pop*/
#if __GNUC_PREREQ(4,5)
 #pragma GCC diagnostic pop
#endif

#pragma mark *** Support Subroutines ***

static unsigned char *
__n_char_sequence(uint32_t w160[5], unsigned char *sPtr, int type) {

  const char   *_outvalues;
  unsigned is_zero;

    /* e80 long double type, 63rd bit required set reguardless if nan or inf */
    /* if is_zero is <zero>, then is infinity, else nan */
    /* any info in nan is considered n-char-sequence */
    /* bit 62 of nan, when 0, and others [61-0] set, is considered signalling nan.
     * bit 62 of nan, when 1, if others 0, special quiet nan, others [61-0] set,
     * considered quiet signaling nan. */
  is_zero = ((w160[3] & 0x7FFFFFFF) | w160[2] | w160[1] | w160[0]);
  _outvalues = _const_outStr + 16;
  if (IS_UPPER_TYPE(type)) _outvalues += 32;
  if (!is_zero){
    *((uint32_t *)sPtr) = ((int32_t *)_outvalues)[1];
    return (sPtr + 3);
  }

  *((uint32_t *)sPtr) = ((int32_t *)_outvalues)[0];
  sPtr += 3;
  if (SURPRESS_NSEQ(type)) return sPtr;

    /* for doubles 53bits exposed, shift off hidden */
  if (!IS_LDBL(type)) *(uint64_t*)&w160[2] <<= 1;
  if (IS_QUAD(type)) {
    w160[2] |= (w160[1] & 0x40000000) >> 30;
    *(uint64_t*)&w160[0] <<= 2;
  }

    /* now output the n-char-sequence */
    /* (0x  hexdigits )
     * e80,16nibbles, doubles,13nibbles, floats,5.5nibbles, */
  *((uint16_t *)sPtr) = cconst16_t('(','0');
  sPtr += 2;
  *sPtr = _outvalues[9]; /* 'x' or 'X' */
  sPtr++;
  _outvalues -= 16;
  sPtr[ 0] = _outvalues[(w160[3]  >> 28)];
  sPtr[ 1] = _outvalues[((w160[3] <<  4) >> 28)];
  sPtr[ 2] = _outvalues[((w160[3] <<  8) >> 28)];
  sPtr[ 3] = _outvalues[((w160[3] << 12) >> 28)];
  sPtr[ 4] = _outvalues[((w160[3] << 16) >> 28)];
  sPtr[ 5] = _outvalues[((w160[3] << 20) >> 28)];
  if (IS_FLT(type)) {  sPtr +=  6; goto end_brace;  }
  sPtr[ 6] = _outvalues[((w160[3] << 24) >> 28)];
  sPtr[ 7] = _outvalues[((w160[3] << 28) >> 28)];
  sPtr[ 8] = _outvalues[(w160[2]  >> 28)];
  sPtr[ 9] = _outvalues[((w160[2] <<  4) >> 28)];
  sPtr[10] = _outvalues[((w160[2] <<  8) >> 28)];
  sPtr[11] = _outvalues[((w160[2] << 12) >> 28)];
  sPtr[12] = _outvalues[((w160[2] << 16) >> 28)];
  if (IS_DBL(type)) {  sPtr += 13; goto end_brace;  }
  sPtr[13] = _outvalues[((w160[2] << 20) >> 28)];
  sPtr[14] = _outvalues[((w160[2] << 24) >> 28)];
  sPtr[15] = _outvalues[((w160[2] << 28) >> 28)];
  sPtr += 16;
  if (IS_LDBL(type))  goto end_brace;
    /* undo w160 formatting of '[0]' for number */
  sPtr[ 0] = _outvalues[(w160[1]  >> 28)];
  sPtr[ 1] = _outvalues[((w160[1] <<  4) >> 28)];
  sPtr[ 2] = _outvalues[((w160[1] <<  8) >> 28)];
  sPtr[ 3] = _outvalues[((w160[1] << 12) >> 28)];
  sPtr[ 4] = _outvalues[((w160[1] << 16) >> 28)];
  sPtr[ 5] = _outvalues[((w160[1] << 20) >> 28)];
  sPtr[ 6] = _outvalues[((w160[1] << 24) >> 28)];
  sPtr[ 7] = _outvalues[((w160[1] << 28) >> 28)];
  sPtr[ 8] = _outvalues[(w160[0]  >> 28)];
  sPtr[ 9] = _outvalues[((w160[0] <<  4) >> 28)];
  sPtr[10] = _outvalues[((w160[0] <<  8) >> 28)];
  sPtr[11] = _outvalues[((w160[0] << 12) >> 28)];
  sPtr += 12;
end_brace:
  *sPtr = ')';
  return (sPtr + 1);
}

/* converts fractional portion of IEEE754 value to
 * base 10 representation, in 10^18 ull format.
 */
static uint32_t
__fractional(_ull_t *uPtr, _ull_t reg) {

  uint32_t last = 1;
  uint64_t mlConst = 3814697265625ULL;  /* 5^18 (42bits) 0x378 2DACE9D9 */
    /*
  0x7FFFFFFF  FFFFFFFF  start
  0x7FFFE 1FFF FFFFFFFF split
     */
  uPtr[0].ull = (reg.uls.hi >> 13) * mlConst; /* 18 + 45 == 63 */
    /* test added, rather than just '&='. This is guess that small 'standard'
     * fractions might be used */
  if (((reg.uls.hi &= 0x00001FFF) | reg.uls.lo) != 0) {
      /* the left over 13bits from hi with 5bits from lo (45-18=>27).
  0x00001FFF FFFFFFFF  start
  0x00001FFFF8 7FFFFFF split
       */
    uint64_t u64;
    last += 1;
    uPtr[0].ull += (u64 = ((uint32_t)(reg.ull >> 27)) * mlConst) >> 18;
    uPtr[1].ull  = ((uint32_t)u64 & 0x3FFFF) * mlConst;
    if ((reg.uls.lo &= 0x7FFFFFF) != 0) {
        /*
  0x00000000 07FFFFFF   start
  0x          7FFFE 1FF split
         */
      _ull_t scratch;
      last += 1;
      uPtr[0].ull += (u64 = (reg.uls.lo >> 9) * mlConst) >> 36;
      scratch.ull  = (uint32_t)((uint32_t)u64 & 0x3FFFF) * mlConst;
      uPtr[2].ull  = (scratch.uls.lo & 0x3FFFF) * mlConst;
      u64 = uPtr[1].ull + (scratch.ull >> 18)
          + (((uint32_t)(u64 >> 18)) & 0x3FFFF) * mlConst;
      if (u64 >= _CARRY)  u64 -= _CARRY, uPtr[0].ull += 1ULL;
      uPtr[1].ull = u64;
      if ((reg.uls.lo &= 0x1FF) != 0) {
          /*
  0x00000000 000001FF end of 63bit resolution
           */
        uint32_t u32;
        last += 1;
          // 54*10^18
        u32 = (uint32_t)((scratch.ull = reg.uls.lo * mlConst) >> 27);
        uPtr[0].ull += (uint64_t)(scratch.uls.hi >> 13);
          // 54*10^18*10^18
          /* first  18 of 45 remainder */
        u64 = ((u32 & 0x3FFFF) * mlConst) + uPtr[1].ull;
          /* second 18 of 45 remainder, scratch.uls.lo &= 0x07FFFFFF; */
        u32 = scratch.uls.lo & 0x07FFFFFF;
        scratch.ull = (u32 >> 9) * mlConst;
        u64 += (scratch.ull >> 18);
        uPtr[2].ull += (scratch.uls.lo & 0x3FFFF) * mlConst;
        if (uPtr[2].ull >= _CARRY)  uPtr[2].ull -= _CARRY, u64 += 1ULL;
        uPtr[1].ull = u64;
          /* last    9 of 45 remainder */
        scratch.ull = ((u32 & 0x000001FF) << 9) * mlConst;
        uPtr[1].ull += (uint64_t)(scratch.uls.hi >> 4);
        if (uPtr[1].ull >= _CARRY)  uPtr[1].ull -= _CARRY, uPtr[0].ull += 1ULL;
          /* of scratch2 36 remainder */
        scratch.uls.hi &= 0x0000000F;
        uPtr[2].ull += ((uint32_t)(scratch.ull >> 18)) * mlConst;
        uPtr[2].ull += ((scratch.uls.lo & 0x3FFFF) * mlConst) >> 18;
        if (uPtr[2].ull >= _CARRY)  uPtr[2].ull -= _CARRY, uPtr[1].ull += 1ULL;
          /* of 18 remainder */
        scratch.uls.lo = (uint32_t)((scratch.uls.lo & 0x3FFFF) * mlConst) & 0x3FFFF;
        uPtr[3].ull = scratch.uls.lo * mlConst;
  } } }
  return last;
}

/* this is for second register of frational */
/* expected entry use: __fractional(uPtr, reg2);
 * expected range of reg2: 0x7fffffffffffc000 thru 0x0000000000004000
 * reg2 expectation: shifted right 1, matching reg 1, where high bit is bit 62
 * to avoid initial allocation problems, create stack use instead of uPtr.
 * also avoids re-zeroing of uPtr regs
 * uPtr parameter for adding to reg1's converted fractional, the final result */
static uint32_t
__fractional_128(_ull_t *uPtr, _ull_t reg) {

  uint32_t last;
  _ull_t sreg[15]; /* StackREGisters */
  memset(sreg, 0, sizeof(sreg));
    /* create regs of multiplly by 5^63 (3 max) */
  __fractional(sreg, reg);

    /* creates sr3-sr6, affects uPtr[4] */
  last = __fractional(&sreg[ 3], sreg[0]);
  if ((sreg[1].ull)) {
    last = 5;  // creates uPtr[5] value
      /* creates sr7-sr10 */
    __fractional(&sreg[ 7], sreg[1]);
    sreg[4].ull += sreg[7].ull;
    sreg[5].ull += sreg[8].ull;
    sreg[6].ull += sreg[9].ull;
    sreg[7].ull  = sreg[10].ull;
    if ((sreg[2].ull)) {
        /* creates sr11-sr14*/
      __fractional(&sreg[11], sreg[2]);
      sreg[5].ull += sreg[11].ull;
      sreg[6].ull += sreg[12].ull;
      sreg[7].ull += sreg[13].ull;
      uPtr[6].ull  = sreg[14].ull;
    }
    if (sreg[7].ull >= _CARRY)  sreg[6].ull += 1ULL, sreg[7].ull -= _CARRY;
    uPtr[5].ull  = sreg[7].ull;
    while (sreg[6].ull >= _CARRY)  sreg[5].ull += 1ULL, sreg[6].ull -= _CARRY;
  }
    /* sreg3-sreg8 set for addin transfer to uPtr */
  uPtr[4].ull  = sreg[6].ull;
  uPtr[3].ull += sreg[5].ull;
  while (uPtr[3].ull >= _CARRY)  uPtr[2].ull += 1ULL, uPtr[3].ull -= _CARRY;
  uPtr[2].ull += sreg[4].ull;
  if (uPtr[2].ull >= _CARRY)  uPtr[1].ull += 1ULL, uPtr[2].ull -= _CARRY;
  uPtr[1].ull += sreg[3].ull;
  if (uPtr[1].ull >= _CARRY)  uPtr[0].ull += 1ULL, uPtr[1].ull -= _CARRY;
  return last;
}

static uint32_t
__positive_lowexp128(_ull_t *uPtr, unsigned pw2, _ull_t reg0, _ull_t reg1) {

  uint32_t last, pw10 = 0;
  uint32_t  unit_18 = 0;
  if (pw2 < 64) {
    /* create shifted reg0, reg1 */
    /* special case: reg1 has 49bits, a shift of >= 49 bits (*2^49+)
     * means only 1 reg used for __fractional() */
    uint32_t shiftb = 63 - pw2;

    if (pw2 <= 48) {
        /* lowest drop of 15 bits, max of 63 */
      uPtr[0].ull = reg0.ull >> shiftb;
        /* pw2 == 0 clears explicit '1' */
      reg0.ull  = reg0.ull << pw2, reg0.uls.hi &= 0x7fffffff;
        /* pw2 == 0 ORs high bit explicit '0' */
      reg0.ull |= reg1.ull >> shiftb;
      reg1.ull  = reg1.ull << pw2, reg1.uls.hi &= 0x7fffffff;
      last = __fractional(&uPtr[1], reg0);
      if (reg1.ull != 0)
        last = __fractional_128(&uPtr[1], reg1);
    } else {

      uint32_t hi;
        /* @49 shiftb = 14, @63 shiftb = 0 */
      if (shiftb != 0) {
        reg1.ull = (reg1.ull >> shiftb);
        reg1.uls.hi |= (reg0.uls.lo << (32 - shiftb)) >> 1;
        reg0.ull >>= shiftb;
      } else {
          /* values 8-15 possible, reducing >= _CARRY loop
           *        8   9  10  11  12  13  14  15
           * actual 9, 10, 11, 12, 13, 14, 16, 17 e18 starting values */
        hi = (uint32_t)((reg0.uss.w3 >> 12) + 1);
        goto hi_adjusted;
      }
        /* reg0 holds shifted whole value */
        /* default action */
      uPtr[0].ull = reg0.ull;
      if ((shiftb < 4) || ((shiftb == 4) && (reg0.ull >= _CARRY))) {
          /* values 0-7 possible, reducing >= _CARRY loop
           *        0  1  2  3  4  5  6  7
           * actual 1, 1, 2, 3, 4, 5, 6, 8,  e18 starting values */
        hi = (uint32_t)(reg0.uss.w3 >> 12);
        if ((hi))
hi_adjusted:
          reg0.ull -= hi * _CARRY;
        while (reg0.ull >= _CARRY)  hi += 1, reg0.ull -= _CARRY;
        uPtr[0].ull = (uint64_t)hi, ++uPtr;
        uPtr[0].ull = reg0.ull;
        pw10 = 18;
      }
      last = __fractional(&uPtr[1], reg1);
      unit_18 = 1;
    }
  } else {
    uint32_t n28s;
    _ull_t    reg;              /* most used 64 bit gpr */

      /* 64 <= pw2 < 112, 1 fractional reg, multiple whole regs */
    uint32_t hi = (uint32_t)((reg0.uss.w3 >> 12) + 1);
    reg0.ull -= hi * _CARRY;
    while (reg0.ull >= _CARRY)  hi += 1, reg0.ull -= _CARRY;
    uPtr[0].ull = (uint64_t)hi;
    uPtr[1].ull = reg0.ull;
      /* max 50 ((111-63) = 49) [0-49] */
    pw2 -= 63;
    uint32_t shiftb = 63 - pw2;
    if ((n28s = (pw2 >= 28)))
      pw2 -= 28;
    if ((pw2)) {
        /* shift range [27-1] */
      _ull_t  scratch;
        /* shift [18-9] left [27-1] */
      uPtr[0].uls.lo <<= pw2;
        /* shift remainder (uPtr[1], size < 10^19) left [27-1] */
      reg.ull = divlu2r(uPtr[1].ull);
      scratch.ull = divlu2r((uint64_t)reg.uls.hi << pw2);
      uPtr[0].ull += scratch.uls.hi;
      reg.ull = ((uint64_t)scratch.uls.lo * 1000000000U)
              + ((uint64_t)reg.uls.lo << pw2);
        /* do carry, set uPtr[1] */
      if (reg.ull >= _CARRY)  uPtr[0].ull += 1ULL, reg.ull -= _CARRY;
      uPtr[1].ull = reg.ull;
    }
    unit_18 = 1;
    pw10 = 18;
    if (n28s) {
        /* shift of 28 multiples */
        /* set initial limiter to current regs valid (<= unit_max) */
      _ull_t *cap = &uPtr[unit_18];
      _ull_t *input, *output, next;
      reg.ull = (output = (input = uPtr))->ull;
      output->ull = 0;
      next.ull = input[1].ull;

      unit_18++;
      if (reg.ull >= 3725290298ULL)  goto L1;
      unit_18--;
      output->ull = reg.ull << 28;
      output--;

      do {
        _ull_t scratch0;
        uint32_t u32;
        reg.ull = next.ull;
        next.ull = (++input)[1].ull;
        output++;
  L1:   scratch0.ull = divlu2r(reg.ull);
        u32 = (uint32_t)(((uint64_t)scratch0.uls.hi * 2305843009) >> 32) >> 1;
        scratch0.ull = ((((uint64_t)scratch0.uls.hi << 28)
                         - ((uint64_t)u32 * 1000000000U)) * 1000000000U)
                     + ((uint64_t)scratch0.uls.lo << 28);
        if (scratch0.ull >= _CARRY)
          u32 += 1, scratch0.ull -= _CARRY;
        output[1].ull = scratch0.ull;
        if ((output->ull += u32) >= _CARRY)
          output->ull -= _CARRY, output[-1].ull += 1;
      } while (input < cap);
    }
    pw10 += ((unit_18 - 1) * 18);

      /* reg0 has addin to shifted whole value */
    pw2 = 63 - shiftb;
    reg0.ull = (reg1.ull >> shiftb);
    reg0.ull += uPtr[1].ull;
    if (reg0.ull >= _CARRY)  uPtr[0].ull += 1, reg0.ull -= _CARRY;
    uPtr[1].ull = reg0.ull;
      /* put fractional bits into place */
    reg1.ull = reg1.ull << pw2, reg1.uls.hi &= 0x7fffffff;
    last = __fractional(&uPtr[2], reg1);
    last++;
  }
  return ((pw10 << 16) | ((last + unit_18) << 4) | last);
}

static uint32_t
__positive_lowexp(_ull_t *uPtr, unsigned pw2, _ull_t reg0) {

    /* do less than 63 code */
  uint16_t last, whole_incr, pw10;
  uint64_t up0;
  pw10 = (whole_incr = 0);
  if (pw2 < 31) {
    up0 = (uint64_t)(reg0.uls.hi >> (31 - pw2));
    reg0.uls.hi = (reg0.uls.hi << (pw2 + 1)) >> (pw2 + 1);
  } else if (pw2 == 31) {
    up0 = (uint64_t)reg0.uls.hi;
    reg0.uls.hi = 0;
  } else {
    uint32_t shift = pw2 - 32;
    up0 = reg0.ull >> (31 - shift);
    reg0.uls.lo = (reg0.uls.lo << (shift + 1)) >> (shift + 1);
    if ((shift > 27) || ((shift == 27) && (up0 >= _CARRY))) {
      do uPtr[0].ull += 1ULL; while ((up0 -= _CARRY) >= _CARRY);
      uPtr++, whole_incr++, pw10 = 18;
    }
  }
  uPtr[0].ull = up0;
  last = 1;
  if ((reg0.ull <<= pw2) != 0)
    last += __fractional(&uPtr[1], reg0);
  return ((pw10 << 16) | ((last + whole_incr) << 4) | last);
}

/* now grows low address to high address, or left to right numerically */
/* expects implicit/explicit 1 as 63rd bit */
/* multiplies by 2^28, 2^28 used to keep large values within 10^18 ulls */
/* addition of such values create at max 'overflow' of 1 */
/* valid division range on /28 [0-16383] */
static uint32_t
__positive_exponent_fp(_ull_t *uPtr, int type) {

  unsigned  pw2, pw10, n28s;  /* power of 2, power of 10, shifts of 28 */
  _ull_t    reg0;              /* most used 64 bit gpr */
    /* track reg expansion, initial is to read 2 registers (&uPtr[unit_18]) */
  uint32_t  unit_18 = 1;

    /* load 'passed' data */
  pw2 = uPtr[0].uss.w0 - 16383;
    /* note: retain explicit '1' */
  reg0.ull = uPtr[1].ull;
  uPtr[1].ull = (uPtr[0].ull = 0);

  if (uPtr[2].ull != 0) {
    _ull_t   reg1;
    uint32_t hi;
    reg1.ull = uPtr[2].ull;
    uPtr[2].ull = 0;
    if (pw2 < 112)
      return __positive_lowexp128(uPtr, pw2, reg0, reg1);
    /* set up with all whole */
    hi = (uint32_t)((reg0.uss.w3 >> 12) + 1);
    reg0.ull -= hi * _CARRY;
    while (reg0.ull >= _CARRY)  hi += 1, reg0.ull -= _CARRY;
    uPtr[0].ull = (uint64_t)hi << 49;
    uPtr[1].ull = reg1.ull >> 14;
      /* reg1 free to use as gpr */
    reg0.ull = divlu2r(reg0.ull);
    reg1.ull = divlu2r((uint64_t)reg0.uls.hi << 21);
    uPtr[0].ull += (uint64_t)reg1.uls.hi << 28;
    reg0.ull = ((uint64_t)reg1.uls.lo * 1000000000U)
             + ((uint64_t)reg0.uls.lo << 21);
    reg0.ull = divlu2r(reg0.ull);
    reg1.ull = divlu2r((uint64_t)reg0.uls.hi << 28);
    uPtr[0].ull += (uint64_t)reg1.uls.hi;
    uPtr[1].ull += ((uint64_t)reg1.uls.lo * 1000000000U)
                 + ((uint64_t)reg0.uls.lo << 28);
    if (uPtr[1].ull >= _CARRY)  uPtr[0].ull += 1, uPtr[1].ull -= _CARRY;
    pw10 = 18;
    pw2 -= 112;
      /* uPtr[0] range [10384593717069655-5192296858534827] */
    if ((pw2 -= ((n28s = (pw2 * 18725U) >> 19) * 28)) != 0) {
      _ull_t next, *output;
      uint32_t u32;
      next.ull = uPtr[1].ull;
      reg0.ull = divlu2r(uPtr[0].ull);
        /* 2^61 / 10^9  based on << 28 forces all into higher register */
      u32 = (uint32_t)(((uint64_t)reg0.uls.hi * 2305843009U) >> 32) >> (29 - pw2);
      reg0.ull = ((((uint64_t)reg0.uls.hi << pw2)
                  - ((uint64_t)u32 * 1000000000U)) * 1000000000U)
                   + ((uint64_t)reg0.uls.lo << pw2);
      if (reg0.ull >= _CARRY)
        u32 += 1, reg0.ull -= _CARRY;
      if ((u32)) {
        uPtr[1].ull = reg0.ull;
        uPtr[0].ull = (uint64_t)u32;
          /* creates new register, increases uPtr[unit_18] limit (3) */
          /* adds pw10 += 18 by return math addition of unit_18 */
        unit_18++;
        output = &uPtr[1];
      } else {
          /* no new register, still uPtr[unit_18] limit (2) */
        uPtr[0].ull = reg0.ull;
        output = &uPtr[0];
      }
      reg0.ull = divlu2r(next.ull);
      u32 = (uint32_t)(((uint64_t)reg0.uls.hi * 2305843009U) >> 32) >> (29 - pw2);
      reg0.ull = ((((uint64_t)reg0.uls.hi << pw2)
                  - ((uint64_t)u32 * 1000000000U)) * 1000000000U)
                   + ((uint64_t)reg0.uls.lo << pw2);
      if (reg0.ull >= _CARRY)
        u32 += 1, reg0.ull -= _CARRY;
      output[1].ull  = reg0.ull;
        /* case:
         * w160[4] = 0x4092, w160[3] = 0x8001a8fb, w160[2] = 0xec8ed23f;
         */
      if ((output[0].ull += u32) >= _CARRY)
        output[-1].ull += 1, output[0].ull -= _CARRY;
      }
  } else {
    uint32_t hi;
    if (pw2 < 63)
      return __positive_lowexp(uPtr, pw2, reg0);
      /* below, all use min of 2 regs (uPtr) */
      /* creates new register, still uPtr[unit_18] limit (2) */
      /* values 8-15 possible, reducing >= _CARRY loop
       *        8   9  10  11  12  13  14  15
       * actual 9, 10, 11, 12, 13, 14, 16, 17 e18 starting values */
    hi = (uint32_t)((reg0.uss.w3 >> 12) + 1);
    reg0.ull -= hi * _CARRY;
    while (reg0.ull >= _CARRY)  hi += 1, reg0.ull -= _CARRY;
    uPtr[0].ull = (uint64_t)hi;
    uPtr[1].ull = reg0.ull;
    pw10 = 18;
    pw2 -= 63;
    if ((pw2 -= ((n28s = (pw2 * 18725U) >> 19) * 28)) != 0) {
        /* shift range [27-1] */
      _ull_t  scratch;
        /* shift [18-9] left [27-1] */
      uPtr[0].uls.lo <<= pw2;
        /* shift remainder (uPtr[1], size < 10^19) left [27-1] */
      reg0.ull = divlu2r(uPtr[1].ull);
      scratch.ull = divlu2r((uint64_t)reg0.uls.hi << pw2);
      uPtr[0].ull += scratch.uls.hi;
      reg0.ull = ((uint64_t)scratch.uls.lo * 1000000000U)
              + ((uint64_t)reg0.uls.lo << pw2);
        /* do carry, set uPtr[1] */
      if (reg0.ull >= _CARRY)  uPtr[0].ull += 1ULL, reg0.ull -= _CARRY;
      uPtr[1].ull = reg0.ull;
    }
  }

  if (n28s != 0) {
      /* shift of 28 multiples */
      /* set max regs use, cap used as pointer compare limiter */
    uint32_t unit_max = type >> 16;
      /* set initial limiter to current regs valid (<= unit_max) */
    _ull_t *cap = &uPtr[unit_18];

    do {
        /* start at base */
        /* create loop counter, each 28 loop expects increase of new
         * reg created. A test used to verify if one is created. loop counter
         * then used to increase both pw10, and possibly the ending of
         * last math reg used (cap) */
      _ull_t *input, *output, next;
      reg0.ull = (output = (input = uPtr))->ull;
      output->ull = 0;
      next.ull = input[1].ull;

        /* critical point where addin to reg0.ull can cause overflow
         * and propagation into a prior ull */
      unit_18++;
      if (reg0.ull >= 3725290298ULL)  goto L1;
      unit_18--;
        /* shift of reg0.ull with addin remains below 10^19 */
      output->ull = reg0.ull << 28;
        /* undo loop increment of first addin location,
         * and lcnt (new reg increase) initial assumption */
      output--;

      do {
        _ull_t scratch0;
        uint32_t u32;
        reg0.ull = next.ull;
        next.ull = (++input)[1].ull;
        output++;
  L1:   scratch0.ull = divlu2r(reg0.ull);
        u32 = (uint32_t)(((uint64_t)scratch0.uls.hi * 2305843009) >> 32) >> 1;
        scratch0.ull = ((((uint64_t)scratch0.uls.hi << 28)
                         - ((uint64_t)u32 * 1000000000U)) * 1000000000U)
                     + ((uint64_t)scratch0.uls.lo << 28);
        if (scratch0.ull >= _CARRY)
          u32 += 1, scratch0.ull -= _CARRY;
        output[1].ull = scratch0.ull;
        if ((output->ull += u32) >= _CARRY)
          output->ull -= _CARRY, output[-1].ull += 1;
      } while (input < cap);
        /* tail pointer update based on new reg add vs needs for precision */
        /* limit allowed to increase above cap for pw10 counter */
      cap = &uPtr[((unit_18 > unit_max) ? unit_max : unit_18)];
    } while ((--n28s));
      /* convert regs used into pw10. add to pre-28 value */
  }
  pw10 += ((unit_18 - 1) * 18);
  return ((pw10 << 16) | ((unit_18 + 1) << 4));
}

static uint32_t
__negative_exponent_fp(_ull_t *uPtr, int type) {

  int      pw2, pw10;         /* power of 2, power of 10 */
  uint32_t index;
  _ull_t   reg0;

  pw10 = -18;
  pw2  = 16383 - uPtr[0].uls.lo;
  pw2 -= (index = ((uint32_t)pw2 == ((IS_DBL(type)) ? 1023U : 16383U)));

    /* remove explicit '1'. add back later as 1e18 if not denormal */
  reg0.ull = uPtr[1].ull;
  reg0.uls.hi &= 0x7FFFFFFF;
  uPtr[1].ull = 0;

  if (uPtr[2].ull != 0) {
    _ull_t   reg1;
    reg1.ull = uPtr[2].ull;
    uPtr[2].ull = 0;
    __fractional(uPtr, reg0);
    __fractional_128(uPtr, reg1);
    if (index == 0)  uPtr->ull += _CARRY;
    index = 8;
  } else if (reg0.ull != 0) {
      /* convert fractional to base 10 */
    __fractional(uPtr, reg0);
      /* 2 cases: denormal, normal */
    if (index == 0)  uPtr->ull += _CARRY;
    index = 5;
  } else {
    if (pw2 < 18) {
        /* straight power of 2 */
        /* first 17, [-1, -17]... shift of 10^18,
         * 10^18/18446744073709551616 =
         * 0.0542101086242752217003726400434970855712
         * 0.0542101086242752217003726400434970855712 * 2^64 =
         * 10^18 = 0x232830643 * 2^32 + 2808348672 */
        /* no whole, all fraction */
      uPtr->uls.lo = ((uint32_t)232830643U << (32 - pw2))
                     | ((uint32_t)2808348672U >> pw2);
      uPtr->uls.hi =  (uint32_t)232830643U >> pw2;
      return (uint32_t)((-(18 << 16)) | (1 << 4) | 8);
    }
      /* there are 18 trailing zeroes to _CARRY */
    uPtr[0].ull = _CARRY >> 18;
    pw2 -= 18;
    index = 5;
  }
    /* 5^18 * 2^2 * 2^16 = 10^18 */
    /* each shift into new ull is multiplied by 10^18.
     * or 2^-16 * 10^18 = shift * 5^18 * 2^2 */
  if (pw2 & 0xf) {
      /* partial 2^-16, use of shorter, quicker multiply */
      /* cant use shift on ulls, when partial gcc adds extra coding, test of 32 */
      /* use this code, smaller, faster than using unsigned long gcc code */
    uint32_t m = pw2 & 0xf;
    uint32_t shift = (16 - m);
    uint32_t shiftb = shift + 16;
    uint64_t fConst = 15258789062500ULL;
    if (index == 8) {
      uPtr[7].ull = ((uint16_t)(uPtr[6].uls.lo << shift)) * fConst;
      uPtr[6].uls.lo = (uPtr[6].uls.hi << shiftb) | (uPtr[6].uls.lo >> m);
      uPtr[6].uls.hi >>= m;
      uPtr[6].ull += ((uint16_t)(uPtr[5].uls.lo << shift)) * fConst;
      uPtr[5].uls.lo = (uPtr[5].uls.hi << shiftb) | (uPtr[5].uls.lo >> m);
      uPtr[5].uls.hi >>= m;
      uPtr[5].ull += ((uint16_t)(uPtr[4].uls.lo << shift)) * fConst;
      uPtr[4].uls.lo = (uPtr[4].uls.hi << shiftb) | (uPtr[4].uls.lo >> m);
      uPtr[4].uls.hi >>= m;
      uPtr[4].ull += ((uint16_t)(uPtr[3].uls.lo << shift)) * fConst;
    } else {
      uPtr[4].ull = ((uint16_t)(uPtr[3].uls.lo << shift)) * fConst;
    }
    uPtr[3].uls.lo = (uPtr[3].uls.hi << shiftb) | (uPtr[3].uls.lo >> m);
    uPtr[3].uls.hi >>= m;
    uPtr[3].ull += ((uint16_t)(uPtr[2].uls.lo << shift)) * fConst;
    uPtr[2].uls.lo = (uPtr[2].uls.hi << shiftb) | (uPtr[2].uls.lo >> m);
    uPtr[2].uls.hi >>= m;
    uPtr[2].ull += ((uint16_t)(uPtr[1].uls.lo << shift)) * fConst;
    uPtr[1].uls.lo = (uPtr[1].uls.hi << shiftb) | (uPtr[1].uls.lo >> m);
    uPtr[1].uls.hi >>= m;
    uPtr[1].ull += ((uint16_t)(uPtr[0].uls.lo << shift)) * fConst;
    uPtr[0].uls.lo = (uPtr[0].uls.hi << shiftb) | (uPtr[0].uls.lo >> m);
    uPtr[0].uls.hi >>= m;
      /* address case of denormals, below 'flag' will write pre-regs otherwise */
    if ((uPtr[0].uls.hi | uPtr[0].uls.lo) == 0) {
      pw10 -= 18;
      uPtr[0].ull = uPtr[1].ull, uPtr[1].ull = uPtr[2].ull;
      uPtr[2].ull = uPtr[3].ull, uPtr[3].ull = uPtr[4].ull;
      if (index == 8) {
        uPtr[4].ull = uPtr[5].ull, uPtr[5].ull = uPtr[6].ull;
        uPtr[6].ull = uPtr[7].ull, uPtr[7].ull = 0;
      } else {
        uPtr[4].ull = 0;
      }
    }
  }
    /* 2^-16, multiples */
  if ((pw2 >> 4) != 0) {

    _ull_t *regPtr, *limit;
    pw2 >>= 4;
    limit = uPtr + (unsigned)(type >> 16);
    int16_t fcnt = 0;
      /* code approaches best written assembler, addressed most stalls
       * inotherwords, use caution rewording, huge penalties. */
    do {
      uint64_t work;
      uint32_t w0;
      int32_t flag;
      regPtr = uPtr;
      w0 = (uint32_t)regPtr->uss.w0;
      fcnt += (flag = -((regPtr->ull = regPtr->ull >> 16) == 0));
      work = (++regPtr)->ull;
      do {
        uint64_t m0 = w0 * 15258789062500ULL;
        w0 = (uint16_t)work;
        regPtr[flag].ull = (work = m0 + (work >> 16));
        ++regPtr;
      } while ((regPtr <= limit) && ((work = regPtr->ull) != 0));
      regPtr[flag].ull = w0 * 15258789062500ULL;
    } while ((--pw2) != 0);
    index = (int)(regPtr - uPtr) + 1;
    pw10 += fcnt * 18;
  }
    /* only pw10 used in function as exponent of power 10 */
  return ((pw10 << 16) | (index << 4) | 8);
}

/* enters with 'sSize = strPtr - sPtr;'.
 * s, sPtr could have been malloc'd on entry, but expected to have been
 * cleared, output used, prior to entry. Possibly previous real allocation,
 * output to 'buffer', FILE or supplied, and not free'd.
 * printf() supplies BUFSTRSIZE on entry, realtostr supplies 45 ulls.
 * BUFSTRSIZE considered large for normal requests,
 * 45 ulls covers all needs for double reals.
 * all real types generally need 8, [±][0][.](precision)[e±000[0]]
 * IS_TYPE_F adds exponent to count, [±][0](exponent)[.](precision)[e±000[0]]
 * IS_TYPE_F has possiblity of grouping:
 * GRP_PREFIX assumes thousands, xxx,xxx,xxx,xxx etc. = 6 per ull
 * can't reuse precision 'reg's as double duty... 18 bytes / 8 byte ull
 * bufS(string) must come first for free'ing of allocation
 */

#pragma mark *** External Interfaces ***

#if (!__GNUC_PREREQ(4,5))
#pragma GCC diagnostic ignored "-Wuninitialized"
#endif

unsigned char *
realtostr(uint32_t w160[5], unsigned char **s, int type,
          int arg_prec, int arg_flags, unsigned decimal) {

/*smash_stack();*/

  int exponent, rpos;   /* Rounding POSition */
  uint32_t (*math_func)(_ull_t *, int);
  unsigned char  *sPtr, dblt_sign;
    /* set up for percision of 792 digits, 18/ull * 44ull */
    /* malloc if exponent and percision dictate, 44ull = 352 bytes */
    /* reg: static reserved, regs: actual reg use address (stack or allocated) */
  _ull_t reg[45], *regs;
  /* supress warning due to zero jumps */
#if __GNUC_PREREQ(4,5)
#pragma GCC diagnostic ignored "-Wuninitialized"
#endif
    /* utPtr: top of stack, ubPtr: bottom of stack, ufPtr: fractional start */
  _ull_t *utPtr, *ubPtr, *ufPtr;
  int d0;   /* Digit0 (first digit) */
#if __GNUC_PREREQ(4,5)
#pragma GCC diagnostic pop
#endif
  uint64_t a;
  unsigned strsz, pw2, packed_return;

                        /*** input defaults ***/
  char *decimalPtr = (char*)&decimal;

  if (arg_prec < 0)  arg_prec = 6;
    /* CASE 'g':  initial zero(or first digit) is significant digit */
  if ((arg_prec) && (IS_TYPE_G(type)))  --arg_prec;

                        /*** sign ***/
  if ((w160[4] & 0x8000) != 0)  dblt_sign = '-';
  else {
    dblt_sign = 0;
    if ((arg_flags & (SIGN_PREFIX | SPC_PREFIX)) != 0)
      dblt_sign = (arg_flags & SPC_PREFIX) ? ' ' : '+';
  }
                        /*** exponent ***/
    /* extra math used for limiting register updating in math units. Also
     * allows allocation size when precision exceeds static buffersize */
  if ((exponent = w160[4] & 0x7FFF) == 0x7FFF) {
      /* inf or nan, nan(n-char-sequence) */
    *(sPtr = *s) = dblt_sign, sPtr += (dblt_sign != 0);
    return __n_char_sequence(w160, sPtr, (type | ((arg_flags & ALT_PREFIX) << 1)));
  }
  if (exponent < 0x3FFF) {
    uint32_t reg_min = (IS_QUAD(type)) ? 7 : 4;
    math_func = __negative_exponent_fp;
    pw2 = reg_min;

      /* these 'need' pw10 pre-calculations for extra decisions */
      /* !E can result in '0', no caculation needed,
       * >> 4 == 0 results in use of default,
       * default pw2 == 4 covers precision < 64 */
/* XXX with !e80, does pw2 cover precision < (NEG_REG_BITS + 1)? */
    if ( (!IS_TYPE_E(type)) ||
        ( (((uint32_t)(0x3FFF - exponent) >> 4) != 0) && (arg_prec >= 63) ) ) {
      pw2 = 0x3FFF - exponent;
        /* number of prefixing zeroes */
      pw2 = (((uint32_t)(((uint64_t)((uint32_t)pw2)
                                * (uint32_t)2585827973U) >> 32)) >> 1);
        /* check for all zeroes on a 'f' request */
      if ( (!IS_TYPE_E(type)) && ((unsigned)arg_prec < pw2) ) {
        if (pw2 > reg_min) {
          pw2 = reg_min;
          exponent = 0;
          *(uint64_t*)&w160[2] = 0;
/* XXX do I need? */
          *(uint64_t*)&w160[0] = 0;
          if (IS_TYPE_G(type))  type |= TYPE_F;
          type |= TYPE_ZERO;
            /* must not see as denormal for doubles */
            /* remove 'double' label, keep or set 'long double' */
          type &= ~(UPPER_TYPE << 8);
        } else {
          pw2 = reg_min;
        }
      } else {
          /* subtract zeroes from significant digits */
        uint32_t bits = (IS_QUAD(type)) ? 112 : 63;
        pw2 = (0x3FFF - exponent) + bits - pw2;
        if (pw2 > (unsigned)arg_prec)  pw2 = arg_prec;
          /* divide by 18 for number ulls needed */
        if (pw2 <= 38)
          pw2 = reg_min;
        else
          pw2 = reg_min + (uint32_t)((((uint64_t)(uint32_t)(pw2 - 38))
                                                * (uint32_t)238609295U) >> 32);
      }
    }
  } else {
    math_func = __positive_exponent_fp;
    pw2 = 2;
      /* when 'f', need maximum value */
    if ( ((exponent >= 0x40ce) && (arg_prec >= 27)) || (IS_TYPE_F(type)) ) {
      pw2 = exponent - 0x3FFF;
      pw2 = (((uint32_t)(((uint64_t)((uint32_t)pw2)
                                                * 2585827973U) >> 32)) >> 1);
        /* 'e' doesn't need full precision */
      if ((IS_TYPE_E(type)) && ((unsigned)arg_prec < pw2))
        pw2 = arg_prec;
        /* divide by 18 for number ulls needed */
      pw2 = 2 + (uint32_t)(((uint64_t)((uint32_t)pw2) * 252645135U) >> 32);
    }
  }
                        /*** allocation ***/
    /* allocate reg here based on exponent/precision, see above notes */
    /* group allocation, fprintf() to free, returning we allocating 's' */
  strsz = arg_prec + 8;
  type |= pw2 << 16;
    /* type F has special requirements, if positive exponent */
  if ((type << 31) & ~(exponent - 0x3FFF)) {
      /* grouping assumption of thousands: 1,000,000 */
      /* add in exponent: [±][0](exponent)[.](precision)[e±000[0]] */
      /* assume all pw2 as 'whole' */
      /* more accuracy, for less allocations, is faster */
    uint32_t triplets = (exponent - 0x3FFF);
    strsz += 1
          + (((uint32_t)(((uint64_t)((uint32_t)triplets) * 2585827973U) >> 32)) >> 1);
    if ((arg_flags & GRP_PREFIX) != 0)
      strsz += ((uint16_t)21845 * (uint32_t)triplets) >> 16;
  }
  regs = reg;
  if ((pw2 > 44) || (strsz > BUFSTRSIZE)) {
      /* if either static exceeds limit, allocate both */
    strsz = (strsz + ((1 << 6) - 1)) & ~((1 << 6) - 1);
      /* test for non-static string buffer */
    if (arg_flags & ALLOC_BUF)  free(*s);
      /* assignment to sPtr, sPtr is one tested and free'd in fprintf() */
    if ((sPtr = malloc((size_t)(strsz + ((pw2 + 1) * sizeof(_ull_t))))) == NULL)
      return sPtr;
    *s = sPtr;
    regs = (_ull_t*)(sPtr + strsz);
  }
    /* zero regs, no longer part of math units */
  do  regs[pw2].uls.hi = 0, regs[pw2].uls.lo = 0;  while ((--pw2));

                        /*** fractional load ***/
    /* assign 'fraction', 'exponent' info for passage to math units */
    /* w160[0,1] used on requested quadruple, or long double 128bit (not e80) */
  regs[0].uls.lo = exponent;
  regs[1].ull = *(uint64_t*)&w160[2];
  regs[2].ull = *(uint64_t*)&w160[0];
  if ((regs[1].ull | regs[2].ull) == 0) {
    exponent = 0;
    if (IS_TYPE_G(type))  type |= TYPE_F;
    type |= TYPE_ZERO;
    goto skip_round;
  }

                        /*** math ***/
  packed_return = (*math_func)(regs, type);
    /* transfer info returned into addresses, exponent */
  ubPtr = (utPtr = regs) + ((packed_return >> 4) & 0x3FF);
  exponent  = (d0 = _first_digit(utPtr->ull));
  exponent += (int32_t)packed_return >> 16;
  packed_return &= 0x0F;
  ufPtr = ((packed_return == 0) ? ubPtr :
          ((packed_return == 0x08) ? regs : ubPtr - (packed_return - 1)));

                        /*** rounding ***/
    /* assign position 1 pass display precision */
  rpos = arg_prec + 1;
  if (IS_TYPE_F(type))  {
      /* this excludes positive exponents, they will not jump to skip */
    if (arg_prec < ~exponent)  goto skip_round;
      /* positive exponents must count pre-radix as precision */
    if (~exponent >> 31)
      arg_prec += exponent;
      /* when negative, remove pre-zero count, positive add in whole portion */
    rpos += exponent;
  }
    /* rounding position <= first digit position, has front end zeroes */
  if ((rpos -= d0) > 0) {
    _ull_t *aPtr = utPtr;
      /* test rounding for second ull or higher, assume not large arg_prec */
    while (((++aPtr) < ubPtr) && (rpos > 18))  rpos -= 18;
      /* verify position has digits to round */
    if (aPtr < ubPtr) {
        /* set last ull, if rpos == 1 then exclude current aPtr */
      ubPtr = aPtr + (rpos != 1);
      if (ufPtr > ubPtr)  ufPtr = ubPtr;
      const uint64_t *fc = _fcarry;
      if ((aPtr->ull += fc[18 - rpos]) >= _CARRY) {
        uint64_t t = aPtr[-1].ull + 1ULL;
          /* carry forced propagation, makes ull == 0 */
        (ubPtr = aPtr)->ull = 0;
        (--aPtr)->ull = t;
        if ((aPtr == utPtr) && (t >= fc[19 + d0])) {
          exponent++;
            /* type 'f' has increase in precision if positive exponent */
            /* condition of == 18 never occurs */
          arg_prec += (type & ((uint32_t)~exponent >> 31));
          ++d0;
        }
      }
    }
  } else {
      /* first ull rounding */
    const uint64_t *fc = _fcarry;
      /* limit reads of ulls to next register */
    ubPtr = utPtr + 1;
    if (ufPtr > ubPtr)  ufPtr = ubPtr;
      /* add '5' to rounding location */
    a = utPtr->ull + fc[-rpos];
    utPtr->ull = a;
      /* test for propagation to new first digit */
    if (a >= fc[19 + d0]) {
      exponent++;
      if ((++d0) == 18) {
          /* rare case. inserted here to avoid alter of ulltobuffer for odd case
           * and testing all cases for this condition. */
          /* occurs @ 1e18, 1e-18
           9.9999950000000026e+17 first precision 6
           9.9999999999999987e+17 last
           9.9999950000000012e-19 first precision 6
           9.9999999999999988e-19 last
           */
        *(sPtr = *s) = dblt_sign, sPtr += (dblt_sign != 0);
          /* type f and negative exponent */
        if (((uint32_t)exponent >> 31) & type) {
          unsigned j, k;
          *sPtr++ = '0';
          *(uint16_t*)sPtr = *(uint16_t*)decimalPtr;
          j = 1 + (decimalPtr[1] != 0);
          sPtr += j, decimalPtr += j;
          if ((j = -exponent - 1)) {
            if (j >= (unsigned)arg_prec) goto L24;
            arg_prec -= j;
            k = j & 3;
            if ((j = (int)((unsigned)j >> 2)))
              do  *(uint32_t*)sPtr = 0x30303030U, sPtr += 4;  while ((--j));
            *(uint32_t*)sPtr = 0x30303030U;
            sPtr += k;
          }
          *sPtr++ = '1';
          if ((arg_prec -= 1) > 0)  goto L245;
          return sPtr;
        }
        *sPtr++ = '1';
        if ( (IS_TYPE_G(type)) && (((unsigned)exponent) <= (unsigned)arg_prec) )
          type |= TYPE_F;
        if ( (arg_prec) && (!(IS_TYPE_G(type)) || (arg_flags & ALT_PREFIX)) ) {
          unsigned dflag = (decimalPtr[1] != 0);
          *(uint16_t*)sPtr = *(uint16_t*)decimalPtr;
          sPtr += dflag + 1, decimalPtr += dflag + 1;
          goto L245;
        }
        goto L25;
      }
    }
  }
                    /*** adjust for entered type... g ***/
    /* rounding can adjust exponent, so now can test if conditions met */
  if (IS_TYPE_G(type)) {
      /* this should exclude negatives */
    if (((unsigned)exponent) <= (unsigned)arg_prec)  goto L23;
    if (((unsigned)(exponent + 4)) <= 4) {
      arg_prec -= exponent;
L23:  type |= TYPE_F;
    }
  }
                        /*** output section ***/
skip_round:
  *(sPtr = *s) = dblt_sign, sPtr += (dblt_sign != 0);
    /* type f and negative exponent, <zero> */
  if ((((uint32_t)exponent >> 31) & type) | (IS_TYPE_ZERO(type))) {
    unsigned j, k;
    *sPtr++ = '0';
    *(uint16_t*)sPtr = *(uint16_t*)decimalPtr;
    j = 1 + (decimalPtr[1] != 0);
    if (!arg_prec) {
      if (IS_TYPE_E(type))  goto L11;
      if (arg_flags & ALT_PREFIX)  return (sPtr + j);
      return sPtr;
    }
    sPtr += j, decimalPtr += j;
    if ((j = -exponent - 1)) {
      if (j >= (unsigned)arg_prec) goto L24;
      arg_prec -= j;
      k = j & 3;
      if ((j = (int)((unsigned)j >> 2)))
        do  *(uint32_t*)sPtr = 0x30303030U, sPtr += 4;  while ((--j));
      *(uint32_t*)sPtr = 0x30303030U;
      sPtr += k;
    }
  }
  {
    /*      first ull
     if utPtr == ufPtr then all digits are part of precision. d0 does not
     count digits but returns log10... log10(1-9) = 0
     if 'f', data starts at sPtr. Otherwise starts sPtr + size of decimal.
     will write on last char of decimal, which then that char copies to sPtr
     then overwritten by decimal.
     (!IS_TYPE_F(type)) stringPtr = sPtr + decimalsz
     To determine if first digit is used as precision use
     (decimalPtr == (char*)&decimal)
     Two-byte decimal determined by (((char*)&decimal)[1] != 0)
     */

      /* deal with d0 */
      /* _fcarry multiplier based on d0, then can adjust d0 */
    const uint64_t *mConst = &_fcarry[35 - d0];
    if ((d0 += ((utPtr == ufPtr) & IS_TYPE_F(type))) > arg_prec)  d0 = arg_prec;

    unsigned char *stringPtr = sPtr;
    if (!IS_TYPE_F(type))
      stringPtr += 1 + (((char*)&decimal)[1] != 0);
      /* traps d0 = [0,9] or all ull multipliers */
    if (utPtr->ull < 1000000000) {
      _ull_t b;
        /* buf output use pre-incr (++) */
      unsigned char *buf = stringPtr - 1;
      uint32_t f = (uint32_t)((uint64_t)utPtr->uls.lo * (uint32_t)mConst[(-9)]);
      uint32_t n = d0 + (decimalPtr == (char*)&decimal);
      b.ull = (uint64_t)(f << 2) * 2882303762U;
      goto L2;
      do {
        b.uls.hi = (((b.uls.hi << 4) >> 4) * 10) + (b.uls.lo >> 28);
        b.uls.lo <<= 4;
    L2: *++buf = (b.uls.hi >> 28) + '0';
      } while ((--n));
    } else {
      _ulltobuffer_nlr((divlu2r(utPtr->ull * (uint32_t)*mConst)), stringPtr,
                                        (d0 + (decimalPtr == (char*)&decimal)));
    }
      /* type 'e' requires radix after first digit */
    if (!IS_TYPE_F(type)) {
        /* move first digit to first spot */
      *sPtr = *stringPtr;
        /* can not use short write here,
         * will overwrite any digits following if sz == 1 */
      *++sPtr = *decimalPtr;
      if (*++decimalPtr != 0)  *++sPtr = *decimalPtr, decimalPtr++;
        /* a must for if arg_prec */
      sPtr++;
      if (!arg_prec) {
        if (arg_flags & ALT_PREFIX)
              sPtr += (((char*)&decimal)[1] != 0);
        else  sPtr -= 1 + (((char*)&decimal)[1] != 0);
        goto L11;
      }
    }
    sPtr += d0 + (decimalPtr == (char*)&decimal);
    if ((arg_prec -= d0) == 0)  goto L25;
  }

  do {
      /* case where has whole/fraction */
    if ((++utPtr) >= ufPtr) {
      if (decimalPtr == (char*)&decimal) {
          /* this also used as delimiter for whole part, stop point for
           * trailing zero removal */
        unsigned dflag = (decimalPtr[1] != 0);
        *(uint16_t*)sPtr = *(uint16_t*)decimalPtr;
        sPtr += dflag + 1, decimalPtr += dflag + 1;
      }
        /* set to last ull, if not already at */
      if (ufPtr == ubPtr)  break;
      ufPtr = ubPtr;
    }
    if ((arg_prec - 18) < 0) {
      _ulltobuffer_nlr(divlu2r(utPtr->ull), sPtr, arg_prec);
      sPtr += arg_prec;
      goto L25;
    }
    arg_prec -= 18;
    _ulltobuffer_18lr(divlu2r(utPtr->ull), sPtr);
    sPtr += 18;
  } while (1);
L24:
  if ( (arg_prec) && (!(IS_TYPE_G(type)) || (arg_flags & ALT_PREFIX)) ) {
      /* safe because of added room for exponent in allocation */
    unsigned k;
  L245:
    k = arg_prec & 3;
    arg_prec = (int)((unsigned)arg_prec >> 2);
    *(uint32_t*)sPtr = 0x30303030U;
    if (arg_prec)
      do  sPtr += 4, *(uint32_t*)sPtr = 0x30303030U;  while ((--arg_prec));
    sPtr += k;
  }
L25:
    /* case 'g', remove any trailing <zero>s */
  if (IS_TYPE_E(type))  goto L11;
  if (!(arg_flags & ALT_PREFIX)) {
      /* test only 'last' byte of decimal point.
       * '== 0' only occurs if written. decimal is at max 2 bytes */
    if (*decimalPtr == 0) {
      unsigned char ch;
      ch = *--sPtr;
      if (IS_TYPE_G(type))
        while (ch == '0')  ch = *--sPtr;
        /* decimal point is at max 2 bytes */
      if (ch != (unsigned char)decimalPtr[-1])  ++sPtr;
      else if (&decimalPtr[-1] != (char*)&decimal) --sPtr;
    }
  } else if (*decimalPtr != 0) {
    unsigned dflag = (decimalPtr[1] != 0);
    *(uint16_t*)sPtr = *(uint16_t*)decimalPtr;
    sPtr += dflag + 1, decimalPtr += dflag + 1;
  }
                        /*** exponent output ***/
  if (IS_TYPE_F(type))  return sPtr;
L11:
    /* converts g,G to e,E and adds sign (portable character set) */
  *(uint16_t*)sPtr = cconst16_t(('e' ^ ((type & 0x20) ^ UPPER_TYPE)),
                                ('+' - ((exponent >> 31) << 1)));
    /* absolute value */
  exponent = (exponent ^ (exponent >> 31)) - (exponent >> 31);
  if (exponent < 10) {
      /* exponent output reqires 2 digit display */
    *(uint16_t*)(&sPtr[2]) = cconst16_t('0',('0' + exponent));
    return (sPtr + 4);
  }
    /* quadruple, long doubles range [10,4966] */
  uint32_t ecd = (uint32_t)(((uint64_t)((uint32_t)exponent << 19)
                                                      * 2199023989U) >> 32);
  ++sPtr;
  if (exponent >= 1000)  *++sPtr = (ecd >> 28) + '0';
  ecd = ((ecd << 4) >> 4) * 10;
  if (exponent >= 100)   *++sPtr = (ecd >> 28) + '0';
  sPtr[1] = ((ecd = (((ecd << 4) >> 4) * 10)) >> 28) + '0';
  sPtr[2] = ((((ecd << 4) >> 4) * 10) >> 28) + '0';
  return (sPtr + 3);
}

/* "[±]0xh.hhhhp±d"
 * normalized: h. force to high nibble for higher precision
 * denornalize: .h force highest nibble as above
 * output precision based on 'g' style
 */
unsigned char *
realtohex(uint32_t w160[5], unsigned char **s, int type,
         int arg_prec, int arg_flags, unsigned decimal) {

  unsigned char *sPtr = *s;
  int exponent;
  uint64_t frac;

                      /*** input defaults ***/
  char *decimalPtr = (char*)&decimal;
  if (arg_prec < 0) {
    arg_prec = (IS_DBL(type)) ? 13 : 15;
    type |= TYPE_G;
  }

    /* determine upper of lower case output */
  const char    *_outvalues = _const_outStr;
  if (IS_UPPER_TYPE(type)) _outvalues += 32;

                      /*** sign && exponent ***/
  exponent = w160[4] & 0x7FFF;
  if ((w160[4] & 0x8000) != 0)  *sPtr++ = '-';
  else {
    if ((arg_flags & (SIGN_PREFIX | SPC_PREFIX)) != 0)
      *sPtr++ =  (arg_flags & SPC_PREFIX) ? ' ' : '+';
  }
  if (exponent == 0x7FFF)
    return __n_char_sequence(w160, sPtr,
                                  (type | ((arg_flags & ALT_PREFIX) << 1)));
  exponent -= 16383;

                      /*** prefix  0x or 0X ***/
  *((uint16_t *)sPtr) = ((uint16_t *)_outvalues)[12];
  sPtr += 2;

                      /*** fractional load ***/
  if ((frac = *(uint64_t*)&w160[2]) == 0) {
    exponent = 0;
    *sPtr++ = '0';
    if (arg_flags & ALT_PREFIX) {
      unsigned dflag = (decimalPtr[1] != 0);
      *(uint16_t*)sPtr = *(uint16_t*)decimalPtr;
      sPtr += dflag + 1, decimalPtr += dflag + 1;
    }
    goto out_exp;
  }
    /* alter exponent by 'shift' amount used to normalize */
  if ((frac & 0x8000000000000000) != 0)
    exponent -= 3;
                        /*** rounding ***/
  if (arg_prec < 15) {
    uint64_t rmask = 0x0FFFFFFFFFFFFFFFULL >> (arg_prec << 2);
    uint64_t radd = (rmask + 1) >> 1;
      /* not sure need to mask result */
    if ((frac & rmask) > radd)  frac = (frac + radd) & ~rmask;
  }

    /* rotate high nibble to low nibble */
  uint32_t snfct = 0;
  if ((frac & 0x8000000000000000ULL) == 0) {
    frac <<= 1;
    snfct = 1;
    *sPtr++ = '0';
  } else {
    frac = (frac >> 60) | (frac << 4);
    *sPtr++ = _outvalues[((uint32_t)frac & 0x0000000F)];
  }
    /* decimal point */
  unsigned dflag = (decimalPtr[1] != 0);
  *(uint16_t*)sPtr = *(uint16_t*)decimalPtr;
  sPtr += dflag + 1, decimalPtr += dflag + 1;
    /* precision based on type, adjust if denormal */
  dflag = (arg_prec < ((IS_DBL(type)) ? 13 : 15))
         ? arg_prec : ((IS_DBL(type)) ? 13 : 15);
  arg_prec -= dflag;
  if (snfct == 1)
    dflag++;
  do {
      /* rotate into position */
    frac = (frac >> 60) | (frac << 4);
    *sPtr++ = _outvalues[((uint32_t)frac & 0x0000000F)];
  } while ((--dflag));

  if (IS_TYPE_G(type)) {
    unsigned char ch = *--sPtr;
    while (ch == '0')  ch = *--sPtr;
    if (ch != (unsigned char)decimalPtr[-1])  ++sPtr;
    else if (&decimalPtr[-1] != (char*)&decimal) --sPtr;
  } else if (arg_prec) {
    dflag = arg_prec & 3;
    arg_prec = (int)((unsigned)arg_prec >> 2);
    *(uint32_t*)sPtr = 0x30303030U;
    if (arg_prec)  do  sPtr += 4, *(uint32_t*)sPtr = 0x30303030U;  while ((--arg_prec));
    sPtr += dflag;
  }

  /*** exponent output (p±d p[-16494,+16383]) ***/
out_exp:
  *sPtr++ = _outvalues[19];
    /* based on portable character set */
  *sPtr++ = '+' - ((exponent >> 31) << 1);
    /* absolute value */
  exponent = (exponent ^ (exponent >> 31)) - (exponent >> 31);

  if (exponent < 10) {
    *sPtr = exponent + '0';
    return (sPtr + 1);
  }
    /* divide exponent by 10000   3518437209 */
  uint32_t ecd = (uint32_t)(((uint64_t)(uint32_t)exponent * 3518437209U) >> 17);
  ecd += 1 << 14;
  if (exponent >= 10000)  *sPtr++ = (ecd >> 28) + '0';
  ecd = ((ecd << 4) >> 4) * 10;
  if (exponent >= 1000)   *sPtr++ = (ecd >> 28) + '0';
  ecd = ((ecd << 4) >> 4) * 10;
  if (exponent >= 100)    *sPtr++ = (ecd >> 28) + '0';
  sPtr[0] = ((ecd = (((ecd << 4) >> 4) * 10)) >> 28) + '0';
  sPtr[1] = ((((ecd << 4) >> 4) * 10) >> 28) + '0';

  return (sPtr + 2);
}

#pragma mark *** Utility External Interfaces ***

/* need different long double definitions 106,64,53 */
long double
qtold(quadruple qdbl) {

  octle iqdbl;
  unsigned char *cdbl = (unsigned char*)&iqdbl;
  iqdbl = qdbl;

#if (__LDBL_MANT_DIG__ == 64)
  iqdbl.ulls.ull0 = (iqdbl.ulls.ull1 << 15) | (iqdbl.uss.us3 >> 1);
  iqdbl.ulls.ull1 >>= 48;
  iqdbl.uls.ul1 = (((iqdbl.uss.us4 & 0x7fff) != 0) << 31)
                 | (iqdbl.uls.ul1 & 0x7fffffff);
#else
  int16_t sign = (idbl.uss.us7 & 0x8000) >> 4;
  int16_t e16 = (idbl.uss.us7 & 0x7fff) - 16383 + 1023;
  iqdbl.uss.us7 = 0;
  iqdbl.ulls.ull1 <<= 4;
  iqdbl.uss.us4 |= iqdbl.uss.us3 >> 12;
    /* double-double and double */
 #if (__LDBL_MANT_DIG__ == 106)
    /* assumes low double exponent different by 2^-52, keeps sign
     * of course this doesnt make sense on denormals
     * thus no extra precision, low double has to be zero */
    /* mantissas into correct positions */
  iqdbl.ulls.ull0 >>= 8;
  iqdbl.uss.us3 |= ((e16 - 52) | sign) << 4;
  if (e16 <= 52) {
    iqdbl.ulls.ull0 = 0;
      /* unknown if benefits hardware when 0 */
    iqdbl.uss.us3 = sign << 4;
  }
 #endif
  if (e16 <= 0) {
    if (e16 <= -52)  iqdbl.ulls.ull1 = 0;
    else             iqdbl.ulls.ull1 >>= (12 - e16);
    e16 = 0;
  } else if (e16 > 2047) {
      /* set to inf */
    iqdbl.ulls.ull1 = 0;
    e16 = 2047;
  }
  iqdbl.uss.us7 |= (e16 | sign) << 4;
#endif
  return (*(long double*)cdbl);
}

double
ldtod(long double ldbl) {

  unsigned char *wc = (unsigned char *)&ldbl;
#if ((__LDBL_MANT_DIG__ == 53) || (__LDBL_MANT_DIG__ == 106))
    /* ppc double-double  XXX untested, just drop lower 64, big endian */
    /* wc will point to highest byte of 128 bit */
  return (*(double*)wc);
#else
    /* since padding occurs, non gpr registers tend towards 128bit use: */
  octle ildbl;
  int16_t e16;
  int16_t sign;
  ildbl = *(octle*)wc;
  wc = (unsigned char *)&ildbl;
    /* 3 known, use IEEE-754 16bit sign/exp, biased */
#if (__LDBL_MANT_DIG__ > 65)
    /* trap binary128 */
  e16 = ildbl.uss.us7;
  ildbl.ulls.ull0 = ildbl.ulls.ull1 >> 12;
#else
    /* trap binary64, e80 (64/63 mantissas) */
  e16 = ildbl.uss.us4;
 #if (__LDBL_MANT_DIG__ == 64)
  ildbl.uss.us3 &= 0x7fff;
  ildbl.ulls.ull0 >>= 11;
 #else
  ildbl.ulls.ull0 = (((ildbl.ulls.ull1 << 4)
                      | (uint64_t)(ildbl.uss.us3 >> 12))) >> 12;
 #endif
#endif
  sign = (e16 & 0x8000) >> 4;
  e16 = (e16 & 0x7FFF) - 16383 + 1023;
  if (e16 <= 0) {
    if (e16 <= -52)  ildbl.ulls.ull0 = 0;
    else             ildbl.ulls.ull0 >>= (12 - e16);
    e16 = 0;
  } else if (e16 > 2047) {
      /* set to inf */
    ildbl.ulls.ull0 = 0;
    e16 = 2047;
  }
  ildbl.uss.us3 |= (e16 | sign) << 4;
  return (*(double*)wc);
#endif
}



int
main(void) {
  phx_printf("%.43f\n", 0x1.52f8a8e32e982p-140);
  phx_printf("%g\n", 355.0/113.0);
  return 0;
}




^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed value is incorrectly rounded
  2021-11-06 12:06                 ` Steven Abner
@ 2021-11-06 23:25                   ` Steven Abner
  0 siblings, 0 replies; 25+ messages in thread
From: Steven Abner @ 2021-11-06 23:25 UTC (permalink / raw)
  To: Newlib

[-- Attachment #1: Type: text/plain, Size: 832 bytes --]


On Sat, Nov 6, 2021 at 8:06 AM, Steven Abner <pheonix.sja@att.net> 
wrote:
>  sample use:
> steven@steven-ryzen:~/Development/Projects$ gcc  newlib_printf_demo.c 
> -o nldemo
> steven@steven-ryzen:~/Development/Projects$ ./nldemo
> 0.0000000000000000000000000000000000000000009
> 3.14159
> 
> Steve

  At least I'll stoke off the list comments:
Apologies, I hadn't synced files, so what I sent was an earlier version
lacking full long double abstract and full 128 mantissas. This also has
easy switching for testing between mantissas. This also voids earlier
ldtostr.c since was also non-synced. This version suppose to allow
running of quadruples along side of long double abstract. If giving
this serious consideration, can provide strtold for total independence
from gdtoa. This a big leap, so TALK amongst yourselves.

Steve



[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: newlib_printf_demo.c --]
[-- Type: text/x-csrc, Size: 84620 bytes --]

#include <stdarg.h>

/* must define a data model */
#ifndef __LP64__
 #define __LP32__  1
#endif
/* found out 24 Jan 2019 from new computer build */
/* gcc does not define __LITTLE_ENDIAN__ or __BIG_ENDIAN__ */
#ifndef __LITTLE_ENDIAN__
 #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
  #define __LITTLE_ENDIAN__
 #else
  #define __BIG_ENDIAN__
 #endif
#endif

typedef signed char         int8_t;
typedef unsigned char       uint8_t;
typedef short               int16_t;
typedef unsigned short      uint16_t;
typedef int                 int32_t;
typedef unsigned int        uint32_t;
typedef long long           int64_t;
typedef unsigned long long  uint64_t;

#if __SIZEOF_INT128__ == 16
typedef __int128            int128_t;
typedef unsigned __int128   uint128_t;
#endif

typedef union {
#if __SIZEOF_INT128__ == 16
 uint128_t   uo;
#endif
#ifdef __BIG_ENDIAN__
 struct { uint64_t ull1, ull0; } ulls;
 struct { uint32_t ul3, ul2, ul1, ul0; } uls;
 struct { uint16_t us7, us6, us5, us4, us3, us2, us1, us0; } uss;
#else  /* __LITTLE_ENDIAN__ */
 struct { uint64_t ull0, ull1; } ulls;
 struct { uint32_t ul0, ul1, ul2, ul3; } uls;
 struct { uint16_t us0, us1, us2, us3, us4, us5, us6, us7; } uss;
#endif
} octle;
/* defined in as_stdio.h */
#define quadruple octle

/* gcc appears to only defines _LP64 __LP64__ (2019) */
/* only models with 64bit ints */
#if defined (__ILP64__) || defined (__SILP64__)
typedef  int64_t      intmax_t;
typedef uint64_t     uintmax_t;
#elif defined (__LP32__)
typedef  int16_t      intmax_t;
typedef uint16_t     uintmax_t;
#else /* __LP64__ has 32bit int */
typedef  int32_t      intmax_t;
typedef uint32_t     uintmax_t;
#endif

/* these are all register size based */
#if defined (__LP32__) || defined (__ILP32__)
typedef  int32_t      intptr_t;
typedef uint32_t     uintptr_t;
#define __SIZEOF_REGISTER_T__ 4
#define __SIZEOF_SIZE_T__ 4
#else
typedef  int64_t      intptr_t;
typedef uint64_t     uintptr_t;
#define __SIZEOF_REGISTER_T__ 8
#define __SIZEOF_SIZE_T__ 8
#endif

typedef  intptr_t   register_t;
typedef  intptr_t    _intptr_t;
typedef uintptr_t   u_intptr_t;
typedef  intptr_t      ssize_t;   /* Used for a count of bytes or an error indication. */
typedef uintptr_t       size_t;   /* Used for sizes of objects. */
typedef  intptr_t    ptrdiff_t;   /* Used for subtracting two pointers. */
typedef uintptr_t      clock_t;   /* Used for system times in clock ticks or CLOCKS_PER_SEC . */
typedef  intptr_t       time_t;   /* Used for time in seconds. */

#define NULL        ((void *)0)

/* for testing on non double-double machines,
 * replace actual when ready to release */
/* testing of abstract long doubles,
 * other files needing support, to use:
 *  stdio.h - ftold prototype
 *  stdlib.h - strtold, stold prototypes
 *  strtold.c - interface code supporting prototypes */
/* system testing on is __LDBL_MANT_DIG__ == 64 */
//#undef __LDBL_MANT_DIG__
//#define __LDBL_MANT_DIG__ 113
//#define __LDBL_MANT_DIG__ 106
//#define __LDBL_MANT_DIG__ 53

#if ((__LDBL_MANT_DIG__ == 106) || (__LDBL_MANT_DIG__ == 113))
 #define LD_SUBST  quadruple
#elif (__LDBL_MANT_DIG__ == 53)
 #define LD_SUBST  double
#else
 #define LD_SUBST  long double
#endif


#ifdef __APPLE__
  #define FILE FILE_mac
#elif defined __linux  /* !__APPLE__ */
  typedef struct _IO_FILE _IO_FILE;
  #define FILE _IO_FILE
#else    /* !__APPLE__ !__CYGWIN__ !__linux */
  #error: unknown FILE structure
#endif  /* FILE * */
extern void *malloc(size_t);
extern void free(void *);
extern int puts(const char *);
size_t fwrite(const void *restrict, size_t, size_t, FILE *restrict);
extern FILE* stdout;

  /* in ldtostr.c */
unsigned char *
realtostr(uint32_t [5], unsigned char **, int, int, int, unsigned);
unsigned char *
realtohex(uint32_t [5], unsigned char **, int, int, int, unsigned);
void qtow(quadruple, uint32_t [5]);
void ldtow(long double, uint32_t [5]);
void dtow(double, uint32_t [5]);
  /* in strtold.c for utilies */
double wtod(uint32_t [5]);

  /* guarentee use of this printf */
int phx_printf(const char *format, ...);

/* local defines */
#define ALT_PREFIX   0002
#define PREC_PREFIX  0400

/* locate dependent utf8 loading of decimal point */
/* for newlib demo return ascii */
struct __params {
  unsigned char **s;
  unsigned char *slimit;
  //locale_t ld;
};

static unsigned
__decimalLoad(unsigned char *s, struct __params *params) {
  (void)params;
  *s = '.';
  return (1);
}

#define BUFSTRSIZE     64
unsigned char *
__format(const unsigned char *format, struct __params *params, va_list arg) {

  unsigned char   buffer[BUFSTRSIZE]; /* size of 64bit binary ouput  no prec,
                                       * field nor alt goes here */
  unsigned char  **s = params->s;
  unsigned char  *slimit = params->slimit;
  unsigned char  *strBuf = buffer, *strPtr, *strEnd, *sPtr = *s;
  uint64_t        val_ull;            /* for any sizeof() > 4 bytes, if
                                       * unsigned is 64bits it will bypass
                                       * val_ul to go here */
  unsigned        val_ul;             /* need unsigned instead of unsigned long
                                       * incase unsigned 64bits */
  uint32_t        arg_flags;          /* arg_flags needs to be 32bits??? */
  int             arg_prec, arg_field, n;
  unsigned char   ch, sign, arg_size; /* arg_size max value is sizeof(long
                                       * double) if int goes 128bits still
                                       * within char size */
  uintptr_t      *vPtr = NULL;

  --format;
  goto L500;
  do {

    strEnd = strPtr = &strBuf[BUFSTRSIZE];
    arg_flags = 0;
    arg_size  = sizeof(int);
    arg_prec  = arg_field = -1;
    sign = 0;

  next_ch:
    ch = *++format;
  EO_EXTENSIONS:
    if (!ch) break;
    switch (ch) {

        /* Removed Flags for demo */
        /* Removed some Length modifiers for demo */
      case 'l':
        if ((ch = *++format) != 'l') {   /* and ll */
                  arg_size = sizeof(long);         goto EO_EXTENSIONS;  }
                  arg_size = sizeof(long long);    goto next_ch;
      case 'q':   arg_size = sizeof(octle);        goto next_ch;	/* 128bit */
      case 'L':   arg_size = sizeof(long double);  goto next_ch;	/* long double */

        /* Removed some Field-Width / Precision for demo */
      case '.':
        ch = *++format;
        arg_flags |= PREC_PREFIX;

      case '1': case '2': case '3':
      case '4': case '5': case '6':
      case '7': case '8': case '9':
        n = ch - 48;
        while ((unsigned)((ch = *++format) - '0') <= 9)
          n = (n * 10) + (ch - '0');
        if (ch != '$') {
          if (arg_flags & PREC_PREFIX)  arg_prec = n;
          else  arg_field = n;
          arg_flags &= ~PREC_PREFIX;
          goto EO_EXTENSIONS;
        }
        goto next_ch;

        /* Removed all Formats... but real */
      case 'a':  case 'e':  case 'f':  case 'g':
      case 'A':  case 'E':  case 'F':  case 'G':
          /* gcc doesn't permit floats, it converts to doubles */
      {
        unsigned char *(*toStr)(uint32_t [5], unsigned char **,
                                                      int, int, int, unsigned);
        uint32_t w160[5];
        uint32_t dp;  /* 4 byte decimal point param */
        int32_t sch;
        __decimalLoad((unsigned char*)&dp, params);
        if ((ch | 0x20) == 'a')  ch -= 'A', toStr = realtohex;
        else                     ch -= 'E', toStr = realtostr;
        sch = format[-1];
          /* force 128bit long double into quad parsing */
        if (sch == 'q') {
          //sch = (('q' << 8) | ch);
          sch = ((34 << 8) | ch);
          qtow(((vPtr == NULL) ? va_arg(arg, octle) : *(octle *)vPtr), w160);
        } else if (sch == 'L') {
#if   (__LDBL_MANT_DIG__ == 53)
          sch = (( 9 << 8) | ch);
#elif (__LDBL_MANT_DIG__ == 64)
          sch = ((18 << 8) | ch);
#elif (__LDBL_MANT_DIG__ == 106)
          sch = ((25 << 8) | ch);
#elif (__LDBL_MANT_DIG__ == 113)
          sch = ((34 << 8) | ch);
#else
  #error: undefined mantissa digits
#endif
          //sch = (('L' << 8) | ch);
          ldtow(((vPtr == NULL) ? va_arg(arg, long double) : *(long double *)vPtr), w160);
        } else {
          //sch = (('l' << 8) | ch);
          sch = ((9 << 8) | ch);
          dtow(((vPtr == NULL) ? va_arg(arg, double) : *(double *)vPtr), w160);
        }
        arg_flags |= (strBuf != buffer) << 7;
        strPtr = toStr(w160, &strBuf, sch, arg_prec, (int)arg_flags, dp);
      }
        if (strPtr == NULL)  goto error;

        val_ul = (n = (int)(strPtr - strBuf));
        strPtr = strBuf;
        arg_prec = 0;
        arg_flags &= ~ALT_PREFIX;
          /* grouping code removed for demo */
    } /* end switch */
                        /* main output section */
      /* adjust the different output factors */
    if ((arg_prec -= n) < 0) arg_prec = 0;
    if ((arg_field -= (arg_prec + val_ul)) < 0) arg_field = 0;
      /* is there output space? removed for demo */
      /* different formatting removed for demo */
    if (sign != 0) *sPtr++ = sign;
    if (arg_prec)  do *sPtr++ = '0'; while ((--arg_prec));
    if (n & 1)
               *sPtr++ = *strPtr++;
    if (n & 2) {
      *(int16_t *)sPtr = *(int16_t *)strPtr;
                  sPtr += sizeof(int16_t); strPtr += sizeof(int16_t);  }
    if ((n >>= 2))
      do {
      *(int32_t *)sPtr = *(int32_t *)strPtr;
                  sPtr += sizeof(int32_t); strPtr += sizeof(int32_t);
      } while ((--n));
    if (arg_field)  do  *sPtr++ = ' ';  while ((--arg_field));

      /* parsing of format string */
    do {
L500: ch = *++format;
      if ((sPtr >= slimit)) {
        --format;
          /* removed buffer extreme */
        puts("this is demo, don't be cute!");
        goto end;
      }
      *sPtr = ch;
      if (!ch) goto end;
      if (ch == '%')  break;
      sPtr++;
    } while (1);
  } while (1);
  *sPtr = 0;
end:
  if (strBuf != buffer)  free(strBuf);
  return sPtr;
error:
  if (strBuf != buffer)  free(strBuf);
  *--sPtr = 0;
  return (*s - 12);
}

#define FORMAT_LINE_MAX  4096

static int
phx_vfprintf(FILE *stream, const char *format, va_list arg) {
//_vfprintf(FILE *stream, const char *format, va_list arg, locale_t ld) {

  unsigned char  *sPtr, *wrPtr, *rdPtr;
  ssize_t         to_write;
  size_t          u8Sz  = FORMAT_LINE_MAX;
  struct __params params;

    /* make sure writable stream, Remove writable for demo */
  if ( (stream == NULL) //|| (!_io_writable(stream))
      || (format == NULL) )  return -1;

    /* create buffer to 'write' into */
  if ((wrPtr = (unsigned char*)malloc(u8Sz)) == NULL)  return -1;

    /* label rdPtr as <format>. If conversion, rdPtr will be allocated
     * and filled with UTF-8 version of <format> */
  rdPtr = (unsigned char*)format;

                        /* UTF-8 <format> input */
  params.s           = &wrPtr;
  params.slimit      = (wrPtr + u8Sz);
  //params.ld          = ld;
  sPtr = __format((const unsigned char *)rdPtr, &params, arg);

                        /* UTF-8 text ouput */
  if ((to_write = (ssize_t)(sPtr - wrPtr)) > 0)
    to_write = fwrite((const void *)wrPtr, (size_t)1, (size_t)to_write, stream);
  free(wrPtr);
  return (int)to_write;
}

int
phx_printf(const char *format, ...) {

  int     written;
  va_list arg;

  va_start(arg, format);
    written = phx_vfprintf((FILE *)stdout, format, arg);
    //written = _vfprintf((FILE *)stdout, format, arg, NULL);
  va_end(arg);
  return written;
}

/*
 *  realtostr - convert real numbers to formated latn numerical string
 *  realtohex - convert real numbers to formated hexadecimal string
 *  qtold - convert quadruple-precision number to a system defined long double
 *  ldtod - convert a system defined long double to a double-precision number
 */
        /* C langauge - string literals */
#ifdef __BIG_ENDIAN__
 #define cconst16_t(a,b)     (uint16_t)(((uint8_t)(a) << 8) | (uint8_t)(b))
 #define cconst32_t(a,b,c,d) (uint32_t)(((uint8_t)(a) << 24) | ((uint8_t)(b) << 16) | ((uint8_t)(c) << 8) | (uint8_t)(d))
#else
 #define cconst16_t(a,b)     (uint16_t)(((uint8_t)(b) << 8) | (uint8_t)(a))
 #define cconst32_t(a,b,c,d) (uint32_t)(((uint8_t)(d) << 24) | ((uint8_t)(c) << 16) | ((uint8_t)(b) << 8) | (uint8_t)(a))
#endif
        /* compiler convience macro */
#ifndef __GNUC_PREREQ
 #if defined __GNUC__ && defined __GNUC_MINOR__
  #define __GNUC_PREREQ(major,minor) \
    (((__GNUC__ << 16) + __GNUC_MINOR__) >= (((major) << 16) + (minor)))
 #else
  #define __GNUC_PREREQ(major,minor) 0
 #endif
#endif  /* __GNUC_PREREQ */

#ifndef __LDBL_MANT_DIG__
#define __LDBL_MANT_DIG__  LDBL_MANT_DIG
#endif

/* endian break down of uint64_t */
#ifdef __BIG_ENDIAN__
  typedef struct {  uint16_t w3; uint16_t w2; uint16_t w1; uint16_t w0;  } _ull_ws;
  typedef struct {  uint32_t hi; uint32_t lo;  } _ull_ls;
#elif defined (__LITTLE_ENDIAN__)
  typedef struct {  uint16_t w0; uint16_t w1; uint16_t w2; uint16_t w3;  } _ull_ws;
  typedef struct {  uint32_t lo; uint32_t hi;  } _ull_ls;
#else
  #error: undefined endianness
#endif
typedef union {  uint64_t ull;  _ull_ls  uls;  _ull_ws  uss;  } _ull_t;

#ifdef __ppc__
  #define CNTLZW(x,y) \
    do __asm__("cntlzw %0,%1" : "=r" (x) : "r" (y)); while(0)
#elif defined (__i386__)
  #define CNTLZW(x,y) \
    do {  __asm__("bsr %1,%0" : "=r" (x) : "r" (y));  x = 31 - x;  } while(0)
#elif defined (__x86_64__)
  #define CNTLZW(x,y) \
    do {  __asm__("bsr %1,%0" : "=r" (x) : "r" (y));  x = 31 - x;  } while(0)
  #define CNTLZD(x,y) \
    do {  __asm__("bsr %1,%0" : "=r" (x) : "r" (y));  x = 63 - x;  } while(0)
#else
    /* about 50% slower, 3 instructions vs 31 instructions */
  #define CNTLZW(x,y) \
    do {  unsigned t = y;   \
      t |= t >> 1;          \
      t |= t >> 2;          \
      t |= t >> 4;          \
      t |= t >> 8;          \
      t |= t >> 16;         \
      t = t - ((t >> 1) & 0x55555555);                            \
      t = (t & 0x33333333) + ((t >> 2) & 0x33333333);             \
      x  = 32 - (((t + (t >> 4) & 0xF0F0F0F) * 0x1010101) >> 24); \
    } while (0);
#endif

/* gcc needed help doing 32 bit shifts */
#if (defined __i386__) || (defined __x86_64__)
 #define SHRDU32(hi, lo, shift)               \
 do {  __asm__ (                              \
         "mov   %4,%%ecx\n\t"                 \
         "shrdl %%cl,%2,%1\n\t"               \
         "shrl %%cl,%0"                       \
         : "=&r" (hi), "=&r" (lo)             \
         : "0" (hi), "1" (lo), "rm" (shift)   \
         : "%ecx", "cc");           \
 } while(0)
 #define SHRDU32I(hi, lo, shift)              \
 do {  __asm__ (                              \
         "shrdl %4,%2,%1\n\t"                 \
         "shrl %4,%0"                         \
         : "=&r" (hi), "=&r" (lo)             \
         : "0" (hi), "1" (lo), "i" (shift)    \
         : "cc");                   \
 } while(0)
 #define SHLDU32(hi, lo, shift)               \
 do {  __asm__ (                              \
         "mov %4,%%ecx\n\t"                   \
         "shldl %%cl,%3,%0\n\t"               \
         "shll %%cl,%1"                       \
         : "=&r" (hi), "=&r" (lo)             \
         : "0" (hi), "1" (lo), "rm" (shift)  \
         : "%ecx", "cc");           \
 } while(0)
 #define SHLDU32I(hi, lo, shift)              \
 do {  __asm__ (                              \
         "shldl %4,%3,%0\n\t"                 \
         "shll %4,%1"                         \
         : "=&r" (hi), "=&r" (lo)           \
         : "0" (hi), "1" (lo), "i" (shift)  \
         : "cc");                   \
 } while(0)
#else
 #define SHRDU32(hi, lo, shift)               \
  lo = (hi << (32 - shift)) | (lo >> shift);  \
  hi >>= shift
 #define SHRDU32I SHRDU32
 #define SHLDU32(hi, lo, shift)               \
  hi = (lo >> (32 - shift)) | (hi << shift);  \
  lo <<= shift
 #define SHLDU32I SHLDU32
#endif

/* if defined, code keeps denormal ability, else treats
 * exponent 0 as zero, does not touch floats as may need range, since
 * accuracy not a concern when using floats. */
#define LEGACY_DENORMAL
#if (__LDBL_MANT_DIG__ == 106)
  /* required to extend precision <= 10^-292 */
#define LEGACY_DENORMAL
  /* required for double-double translation */
extern int ffs(int);
#endif

/* defined in as_stdio.h, needed for utilities */
#define quadruple octle
/* utilities */
void qtow(quadruple, uint32_t [5]);
void ldtow(LD_SUBST ldbl, uint32_t w160[5]);
void dtow(double, uint32_t [5]);
void ftow(float, uint32_t [5]);
LD_SUBST qtold(quadruple);
double ldtod(LD_SUBST);
double qtod(quadruple);

#define _CARRY  1000000000000000000ULL          /* 0x 0DE0B6B3 A7640000 */

  /* for rounding */
static const uint64_t _fcarry[] = {
  5, 50, 500, 5000, 50000, 500000, 5000000, 50000000, 500000000, 5000000000ULL,
  50000000000ULL, 500000000000ULL, 5000000000000ULL, 50000000000000ULL, 500000000000000ULL,
  5000000000000000ULL, 50000000000000000ULL, 500000000000000000ULL,
  /*18*/
  1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000,
  10000000000ULL, 100000000000ULL, 1000000000000ULL, 10000000000000ULL, 100000000000000ULL,
  1000000000000000ULL, 10000000000000000ULL, 100000000000000000ULL, _CARRY
};
  /* for cases: nan, inf, hex */
static const char *_const_outStr =
  "0123456789abcdefnanpinfe0x0.00000123456789ABCDEFNANPINFE0X0.0000";

      /*** internal routines ***/
  /* generic */
static uint64_t _divlu2r(uint64_t) __attribute__ ((noinline));
static void _ulltobuffer_nlr(uint64_t, unsigned char *, int);
static int  _first_digit(uint64_t);
  /* ldtostr specific */
static unsigned char *__n_char_sequence(uint32_t [5], unsigned char *, int);
static uint32_t __fractional(_ull_t *, _ull_t);
static uint32_t __fractional_128(_ull_t *, _ull_t);
static uint32_t __positive_lowexp128(_ull_t *, uint32_t [5], unsigned);
static uint32_t __positive_exponent_fp(_ull_t *, uint32_t [5], int);
static uint32_t __negative_exponent_fp(_ull_t *, uint32_t [5], int);

/* from fprintf... needs to be the same */
#define ZERO_PREFIX  0001
#define ALT_PREFIX   0002
#define LEFT_PREFIX  0004
#define SIGN_PREFIX  0010
#define SPC_PREFIX   0020
#define STAR_PREFIX  0040
#define GRP_PREFIX   0100
#define USGN_PREFIX  0200
#define PREC_PREFIX  0400
#define ALLOC_BUF    USGN_PREFIX
#define BUFSTRSIZE     64

/* upper 16 of 32bit 'type' to pass 'unit' max from
 calcation prior to entry of x_exponent */
#define UPPER_TYPE  0x20
#define IS_UPPER_TYPE(a)  (!((a) & UPPER_TYPE))
#define TYPE_ZERO   0x40
#define IS_TYPE_ZERO(a)   ((a) & TYPE_ZERO)
#define TYPE_E  0
#define TYPE_F  1
#define TYPE_G  2
#define IS_TYPE_E(a)  (((a) & 3) == 0)
#define IS_TYPE_F(a)  ((a) & TYPE_F)
#define IS_TYPE_G(a)  ((a) & TYPE_G)
#define SURPRESS_NSEQ(a) (((a) & 4) != 0)

/* Setup for information passed, second byte.
 * 5:3 field setup. Mantissa uses 5, Exponent uses 3.
 * 0 => 127 bias
 * 1 => 1023 bias
 * 2 => 16383 bias
 * 3-7 => unused (262143 no setup)
 *  These correspond to '__LDBL_MANT_DIG__' :
 * 0 << 3 => 24 bit mantissa
 * 1 << 3 => 53 bit mantissa
 * 2 << 3 => 64 bit mantissa
 * 3 << 3 => 106 bit mantissa
 * 4 << 3 => 113 bit mantissa
 * 5-31 << 3 => unused
 */
 /* LDBL removed, label to an abstract C type 'long double' */
#define IS_FLT(a)     ((uint8_t)((a) >> 8) ==  0)  /* 000000 */
#define IS_DBL(a)     ((uint8_t)((a) >> 8) ==  9)  /* 001001 */
#define IS_E80(a)     ((uint8_t)((a) >> 8) == 18)  /* 010010 */
#define IS_DBL_DBL(a) ((uint8_t)((a) >> 8) == 25)  /* 011001 */
#define IS_QUAD(a)    ((uint8_t)((a) >> 8) == 34)  /* 100010 */

static uint16_t __mbits[ ] = {  24, 53, 64, 106, 113  };

#pragma mark *** Support Mathematics ***

static uint64_t
_divlu2r(uint64_t c) {

  _ull_t q;
  uint32_t mConst = 2305843009U;  /* 2^61 / 10^9 */
  uint32_t tConst = 1000000000U;
  q.uls.hi = (uint32_t)(c >> 32);
  q.uls.lo = ((uint32_t)c);
  if (q.uls.hi != 0) {
    uint32_t shift;
    CNTLZW(shift, q.uls.hi);
    SHLDU32(q.uls.hi, q.uls.lo, shift);
    q.uls.hi = (uint32_t)((q.uls.hi * (uint64_t)mConst) >> 32);
      /* should be 4 or more, but found have slipped 3.
       * When adding to above, gcc adds extra code, slows too much */
    if (shift > 3)  q.uls.hi >>= (shift - 3);
  } else {
    q.uls.hi = (uint32_t)(((q.uls.lo | 1) * (uint64_t)mConst) >> (32 + 29));
  }
  q.uls.lo = (uint32_t)(c - ((uint64_t)q.uls.hi * (uint32_t)tConst));
  if (q.uls.lo >= tConst)
    q.uls.hi += 1, q.uls.lo -= tConst;
  return q.ull;
}

/* best C written that gcc can interept. Size/Speed -02 */
/* must accept 18 */
static void
_ulltobuffer_nlr(uint64_t c, unsigned char *buf, int m) {

  _ull_t b;
  int n;

    /* in 4.60, 2.30 fixed point integers */
  c = _divlu2r(c) << 2;
  b.ull = ((uint32_t)(c >> 32)) * 2882303762ULL;
  n = (m <= 9) ? m : 9;
  *buf = (b.uls.hi >> 28) + '0';
  if ((--n) == 0)  return;
  do {
    b.uls.hi = (((b.uls.hi << 4) >> 4) * 10) + (b.uls.lo >> 28);
    b.uls.lo <<= 4;
    *++buf = (b.uls.hi >> 28) + '0';
  } while ((--n));
  if (m > 9) {
    n = 9;
    b.ull = ((uint32_t)c) * 2882303762ULL;
    goto L2;
    do {
      b.uls.hi = (((b.uls.hi << 4) >> 4) * 10) + (b.uls.lo >> 28);
      b.uls.lo <<= 4;
  L2: buf[(n - 8)] = (b.uls.hi >> 28) + '0';
    } while ((++n) < m);
  }
}


/*#pragma GCC diagnostic ignored "-Wmisleading-indentation"*/
#if __GNUC_PREREQ(4,5)
 #pragma GCC diagnostic ignored "-Wmisleading-indentation"
#endif
/* uses 2 64s as swap loads, this prevents stalls */
/* returns 1 less than actual digits, the power of 10, or log10 value */
static int
_first_digit(uint64_t a) {

  _ull_t reg;
  const uint64_t *fc;
  uint64_t b;
  reg.ull = a;
  fc = _fcarry;
  if (reg.uls.hi) {
    a = fc[35];
    b = fc[34];
    if (reg.ull >= a)  return 17;  a = fc[33];
    if (reg.ull >= b)  return 16;  b = fc[32];
    if (reg.ull >= a)  return 15;  a = fc[31];
    if (reg.ull >= b)  return 14;  b = fc[30];
    if (reg.ull >= a)  return 13;  a = fc[29];
    if (reg.ull >= b)  return 12;  b = fc[28];
    if (reg.ull >= a)  return 11;
    if (reg.ull >= b)  return 10;
    return 9;
  } else {
    uint32_t c, d;
    c = (uint32_t)fc[27];
    d = (uint32_t)fc[26];
    if (reg.uls.lo >= c)  return 9;  c = (uint32_t)fc[25];
    if (reg.uls.lo >= d)  return 8;  d = (uint32_t)fc[24];
    if (reg.uls.lo >= c)  return 7;  c = (uint32_t)fc[23];
    if (reg.uls.lo >= d)  return 6;
    if (reg.uls.lo >= c)  return 5;
    if (reg.uls.lo >= 10000U)  return 4;
    if (reg.uls.lo >= 1000U)  return 3;
    if (reg.uls.lo >= 100U)  return 2;
    if (reg.uls.lo >= 10U)  return 1;
    return 0;
  }
}
/*#pragma GCC diagnostic pop*/
#if __GNUC_PREREQ(4,5)
 #pragma GCC diagnostic pop
#endif

#pragma mark *** Support Subroutines ***

static unsigned char *
__n_char_sequence(uint32_t w160[5], unsigned char *sPtr, int type) {

  const char   *_outvalues;
  unsigned is_zero;

    /* e80 long double type, 63rd bit required set reguardless if nan or inf */
    /* if is_zero is <zero>, then is infinity, else nan */
    /* any info in nan is considered n-char-sequence */
    /* bit 62 of nan, when 0, and others [61-0] set, is considered signal nan.
     * bit 62 of nan, when 1, if others 0, special quiet nan, others [61-0] set,
     * considered quiet signaling nan. */
  is_zero = (w160[2] | w160[1] | w160[0]);
  if (IS_E80(type))
        is_zero |= w160[3] & 0x7FFFFFFF;
  else  is_zero |= w160[3];
  _outvalues = _const_outStr + 16;
  if (IS_UPPER_TYPE(type)) _outvalues += 32;
  if (!is_zero){
    *((uint32_t *)sPtr) = ((int32_t *)_outvalues)[1];
    return (sPtr + 3);
  }

  *((uint32_t *)sPtr) = ((int32_t *)_outvalues)[0];
  sPtr += 3;
  if (SURPRESS_NSEQ(type)) return sPtr;

    /* now output the n-char-sequence */
    /* (0x  hexdigits )
     * e80,16nibbles, doubles,13nibbles, floats,5.5nibbles, */
  *((uint16_t *)sPtr) = cconst16_t('(','0');
  sPtr += 2;
  *sPtr = _outvalues[9]; /* 'x' or 'X' */
  sPtr++;
  _outvalues -= 16;
  sPtr[ 0] = _outvalues[(w160[3]  >> 28)];
  sPtr[ 1] = _outvalues[((w160[3] <<  4) >> 28)];
  sPtr[ 2] = _outvalues[((w160[3] <<  8) >> 28)];
  sPtr[ 3] = _outvalues[((w160[3] << 12) >> 28)];
  sPtr[ 4] = _outvalues[((w160[3] << 16) >> 28)];
  sPtr[ 5] = _outvalues[((w160[3] << 20) >> 28)];
  if (IS_FLT(type)) {  sPtr +=  6; goto end_brace;  }
  sPtr[ 6] = _outvalues[((w160[3] << 24) >> 28)];
  sPtr[ 7] = _outvalues[((w160[3] << 28) >> 28)];
  sPtr[ 8] = _outvalues[(w160[2]  >> 28)];
  sPtr[ 9] = _outvalues[((w160[2] <<  4) >> 28)];
  sPtr[10] = _outvalues[((w160[2] <<  8) >> 28)];
  sPtr[11] = _outvalues[((w160[2] << 12) >> 28)];
  sPtr[12] = _outvalues[((w160[2] << 16) >> 28)];
  if (IS_DBL(type)) {  sPtr += 13; goto end_brace;  }
  sPtr[13] = _outvalues[((w160[2] << 20) >> 28)];
  sPtr[14] = _outvalues[((w160[2] << 24) >> 28)];
  sPtr[15] = _outvalues[((w160[2] << 28) >> 28)];
  sPtr += 16;
  if (IS_E80(type))  goto end_brace;
    /* undo w160 formatting of '[0]' for number */
  sPtr[ 0] = _outvalues[(w160[1]  >> 28)];
  sPtr[ 1] = _outvalues[((w160[1] <<  4) >> 28)];
  sPtr[ 2] = _outvalues[((w160[1] <<  8) >> 28)];
  sPtr[ 3] = _outvalues[((w160[1] << 12) >> 28)];
  sPtr[ 4] = _outvalues[((w160[1] << 16) >> 28)];
  sPtr[ 5] = _outvalues[((w160[1] << 20) >> 28)];
  sPtr[ 6] = _outvalues[((w160[1] << 24) >> 28)];
  sPtr[ 7] = _outvalues[((w160[1] << 28) >> 28)];
  sPtr[ 8] = _outvalues[(w160[0]  >> 28)];
  sPtr[ 9] = _outvalues[((w160[0] <<  4) >> 28)];
  if (IS_QUAD(type)) {
    sPtr[10] = _outvalues[((w160[0] <<  8) >> 28)];
    sPtr[11] = _outvalues[((w160[0] << 12) >> 28)];
    sPtr += 12;
  } else {
    sPtr += 10;
  }
end_brace:
  *sPtr = ')';
  return (sPtr + 1);
}

/* converts fractional portion of IEEE754 value to
 * base 10 representation, in 10^18 ull format.
 */
static uint32_t
__fractional(_ull_t *uPtr, _ull_t reg) {

  uint32_t last = 1;
  uint64_t mlConst = 3814697265625ULL;  /* 5^18 (42bits) 0x378 2DACE9D9 */
    /*
  0xFFFFFFFF  FFFFFFFF  start
  0xFFFFC 3FFF FFFFFFFF split
     */
  uPtr[0].ull = (reg.uls.hi >> 14) * mlConst; /* 18 + 46 == 64 */
    /* test added, rather than just '&='. This is guess that small 'standard'
     * fractions might be used */
  if (((reg.uls.hi &= 0x00003FFF) | reg.uls.lo) != 0) {
      /* the left over 14bits from hi with 4bits from lo (46-18=>28).
  0x00003FFF FFFFFFFF  start
  0x00003FFFF FFFFFFF split
       */
    uint64_t u64;
    last += 1;
    uPtr[0].ull += (u64 = ((uint32_t)(reg.ull >> 28)) * mlConst) >> 18;
      /* grab dropped 18 */
    uint32_t gcc_helper = (uint32_t)u64 & 0x3FFFF;
    uPtr[1].ull = gcc_helper * mlConst;
    if ((reg.uls.lo &= 0xFFFFFFF) != 0) {
        /*
  0x00000000 0FFFFFFF   start
  0x          FFFFC 3FF split
         */
      _ull_t scratch;
      last += 1;
        /* (28-18=>10) */
      uPtr[0].ull += (u64 = (reg.uls.lo >> 10) * mlConst) >> 36;
      uint32_t gcc_helper1 = (uint32_t)u64 & 0x3FFFF;
      scratch.ull  = gcc_helper1 * mlConst;
      uint32_t gcc_helper2 = (((uint32_t)(u64 >> 18)) & 0x3FFFF);
      u64 = ((gcc_helper2 * mlConst) + (scratch.ull >> 18));
      uint32_t gcc_helper3 = (scratch.uls.lo & 0x3FFFF);
      uPtr[2].ull  = gcc_helper3 * mlConst;
      u64 += uPtr[1].ull;
      if (u64 >= _CARRY)  u64 -= _CARRY, uPtr[0].ull += 1ULL;
      uPtr[1].ull = u64;
      if ((reg.uls.lo &= 0x3FF) != 0) {
          /*
  0x00000000 000003FF end of 64bit resolution
           */
        uint32_t u32;
        last += 1;
          // 54*10^18, 64-18=54
        u32 = (uint32_t)((scratch.ull = reg.uls.lo * mlConst) >> 28);
        uPtr[0].ull += (uint64_t)(scratch.uls.hi >> 14);
          // 54*10^18*10^18
          /* first  18 of 46 remainder */
        u64 = ((u32 & 0x3FFFF) * mlConst) + uPtr[1].ull;
          /* second 18 of 46 remainder, scratch.uls.lo &= 0x0FFFFFFF; */
        u32 = scratch.uls.lo & 0x0FFFFFFF;
        scratch.ull = (u32 >> 10) * mlConst;
        u64 += (scratch.ull >> 18);
        uPtr[2].ull += (scratch.uls.lo & 0x3FFFF) * mlConst;
        if (uPtr[2].ull >= _CARRY)  uPtr[2].ull -= _CARRY, u64 += 1ULL;
        uPtr[1].ull = u64;
          /* last   10 of 45 remainder */
        scratch.ull = ((u32 & 0x000003FF) << 8) * mlConst;
        uPtr[1].ull += (uint64_t)(scratch.uls.hi >> 4);
        if (uPtr[1].ull >= _CARRY)  uPtr[1].ull -= _CARRY, uPtr[0].ull += 1ULL;
          /* of scratch2 36 remainder */
        scratch.uls.hi &= 0x0000000F;
        uPtr[2].ull += ((uint32_t)(scratch.ull >> 18)) * mlConst;
        uPtr[2].ull += ((scratch.uls.lo & 0x3FFFF) * mlConst) >> 18;
        if (uPtr[2].ull >= _CARRY)  uPtr[2].ull -= _CARRY, uPtr[1].ull += 1ULL;
          /* of 18 remainder */
        scratch.uls.lo = (uint32_t)((scratch.uls.lo & 0x3FFFF)
                                                           * mlConst) & 0x3FFFF;
        uPtr[3].ull = scratch.uls.lo * mlConst;
  } } }
  return last;
}

/* this is for second register of fractional */
/* expected entry use: __fractional(uPtr, reg2);
 * to avoid initial allocation problems, create stack use instead of uPtr.
 * also avoids re-zeroing of uPtr regs
 * uPtr parameter for adding to reg1's converted fractional, the final result */
static uint32_t
__fractional_128(_ull_t *uPtr, _ull_t reg) {

  uint32_t last;
  _ull_t sreg[15]; /* StackREGisters */
    /* need these cleared, used as flags */
  sreg[2].ull = (sreg[1].ull = 0);
    /* create regs of multiplied by 5^64 (3 max) */
  __fractional(sreg, reg);

    /* creates sr3-sr6, affects uPtr[4] */
  sreg[6].ull = (sreg[5].ull = 0);
  last = 1 + __fractional(&sreg[ 3], sreg[0]);
  if ((sreg[1].ull)) {
    last = 5;  /* creates uPtr[5] value */
    sreg[9].ull = (sreg[10].ull = 0);
      /* creates sr7-sr10 */
    __fractional(&sreg[ 7], sreg[1]);
    sreg[4].ull += sreg[ 7].ull;
    sreg[5].ull += sreg[ 8].ull;
    sreg[6].ull += sreg[ 9].ull;
    sreg[7].ull  = sreg[10].ull;
    if ((sreg[2].ull)) {
      last++;
        /* creates sr11-sr14*/
      __fractional(&sreg[11], sreg[2]);
      sreg[5].ull += sreg[11].ull;
      sreg[6].ull += sreg[12].ull;
      sreg[7].ull += sreg[13].ull;
        /* increase in last */
      uPtr[6].ull  = sreg[14].ull;
    }
    if (sreg[7].ull >= _CARRY)  sreg[6].ull += 1ULL, sreg[7].ull -= _CARRY;
    uPtr[5].ull  = sreg[7].ull;
    if ((uPtr[5].ull))  last++;
    while (sreg[6].ull >= _CARRY)  sreg[5].ull += 1ULL, sreg[6].ull -= _CARRY;
  }
    /* sreg3-sreg8 set for addin transfer to uPtr */
  uPtr[4].ull  = sreg[6].ull;
  uint32_t n = 3;
  do {
    uPtr[n].ull += sreg[(n+2)].ull;
    while (uPtr[n].ull >= _CARRY)
      uPtr[n].ull -= _CARRY, uPtr[(n-1)].ull += 1ULL;
  } while ((--n));
  return last;
}

/* enters uPtr[0] = 0, assumes inlined */
static uint32_t
__positive_lowexp128(_ull_t *uPtr, uint32_t w160[5], unsigned pw2) {

  _ull_t reg0, reg1;
  reg0.ull = *(uint64_t*)&w160[2];
  reg1.ull = *(uint64_t*)&w160[0];

  uint32_t last = 0, pw10 = 0, unit_18 = 0, hi;
  _ull_t *fractionalPtr = &uPtr[1];

  if (pw2 == 0) {
    uPtr[0].uls.lo = 1;
    goto add_frac;
  }
  if ((pw2 & 63) != 0) {
    uint32_t cl = pw2 & 63;
      /* need room for implicit '1' */
    if (cl < 32) {
      uPtr[0].uls.lo =        (1 << cl) | (reg0.uls.hi >> (32 - cl));
      reg0.uls.hi = (reg0.uls.hi << cl) | (reg0.uls.lo >> (32 - cl));
      reg0.uls.lo = (reg0.uls.lo << cl) | (reg1.uls.hi >> (32 - cl));
      reg1.uls.hi = (reg1.uls.hi << cl) | (reg1.uls.lo >> (32 - cl));
      reg1.uls.lo = (reg1.uls.lo << cl);
    } else if (cl == 32) {
      uPtr[0].uls.hi = 1, uPtr[0].uls.lo = reg0.uls.hi;
         reg0.uls.hi = reg0.uls.lo;
         reg0.uls.lo = reg1.uls.hi;
         reg1.uls.hi = reg1.uls.lo;
         reg1.uls.lo = 0;
    } else {
      cl -= 32;
      uPtr[0].uls.hi =           (1 << cl) | (reg0.uls.hi >> (32 - cl));
      uPtr[0].uls.lo = (reg0.uls.hi << cl) | (reg0.uls.lo >> (32 - cl));
         reg0.uls.hi = (reg0.uls.lo << cl) | (reg1.uls.hi >> (32 - cl));
         reg0.uls.lo = (reg1.uls.hi << cl) | (reg1.uls.lo >> (32 - cl));
         reg1.uls.hi = (reg1.uls.lo << cl);
         reg1.uls.lo = 0;
        /* make sure whole in 10^18 ull format */
      if ((cl > 27) || ((cl == 27) && (uPtr[0].ull >= _CARRY))) {
        uint64_t gcc_helper;
        gcc_helper = uPtr[0].ull - ((hi = uPtr[0].uls.hi >> 28) * _CARRY);
        while (((uint32_t)(gcc_helper >> 32) >> 28))  gcc_helper -= _CARRY, hi++;
        if (gcc_helper  >= _CARRY)  gcc_helper -= _CARRY, hi++;
        uPtr[1].ull = gcc_helper;
        uPtr[0].ull = (uint64_t)hi;
          /* increase base since 2 whole ulls */
        fractionalPtr++, pw10 += 18, unit_18++;
      }
    }
      /* Is rest to be fraction? */
    if ((pw2 & ~63) == 0) {
  add_frac:
      if (reg0.ull != 0)  last = __fractional(fractionalPtr, reg0);
      if (reg1.ull != 0)  last = __fractional_128(fractionalPtr, reg1);
      return ((pw10 << 16) | ((last + unit_18 + 1) << 4) | (last + 1));
    }
  } else {
      /* case: entry == 2^64, 2^128 */
    if (reg0.ull >= _CARRY) {
      reg0.ull -= _CARRY - 446744073709551616ULL;
      hi = reg0.uls.hi >> 28;
      reg0.ull -= (hi += (hi >= 7)) * _CARRY;
      while (reg0.ull >= _CARRY)  hi += 1, reg0.ull -= _CARRY;
      hi++;
    } else {
      reg0.ull += 446744073709551616ULL;
      if ((hi = (reg0.ull >= _CARRY)))  reg0.ull -= _CARRY;
    }
    uPtr[0].uls.lo = hi + 18;
    uPtr[1].ull = reg0.ull;
    fractionalPtr++, pw10 += 18, unit_18++;
      /* Is rest to be fraction? */
    if (pw2 != 128) {
      if (reg1.ull != 0)
        last = __fractional(fractionalPtr, reg1);
      return ((pw10 << 16) | ((last + unit_18 + 1) << 4) | (last + 1));
    }
    reg0.ull = 0;
  }
    /* Multiply by 2^64, found this larger code-wise, but around 13% faster. */
    /* When used in terms of realtostr(), a 3% increase. */
  _ull_t sreg0, sreg1;
  fractionalPtr++, pw10 += 18, unit_18++;
  if (pw10 == 36) {
    uPtr[1].ull = _divlu2r(uPtr[1].ull);
    sreg0.ull = _divlu2r((446744073U * (uint64_t)uPtr[0].uls.lo)
                        + (18U * (uint64_t)uPtr[1].uls.hi));
    sreg1.ull = ((18U * (uint64_t)uPtr[1].uls.lo)
                 + (446744073U * (uint64_t)uPtr[1].uls.hi)
                 + (709551616U * (uint64_t)uPtr[0].uls.lo)
                 + ((uint64_t)sreg0.uls.lo * 1000000000U));
    uPtr[0].uls.lo = (uPtr[0].uss.w0 * 18U) + sreg0.uls.hi;
    sreg0.ull = _divlu2r((709551616U * (uint64_t)uPtr[1].uls.hi)
                        + (446744073U * (uint64_t)uPtr[1].uls.lo));
    uPtr[2].ull = (((uint64_t)uPtr[1].uls.lo * 709551616U)
                   + ((uint64_t)sreg0.uls.lo * 1000000000U));
    sreg1.ull += (uint64_t)sreg0.uls.hi;
    if (uPtr[2].ull >= _CARRY)  sreg1.ull += 1ULL, uPtr[2].ull -= _CARRY;
    if (sreg1.ull >= _CARRY)  uPtr[0].ull += 1ULL, sreg1.ull -= _CARRY;
    uPtr[1].ull = sreg1.ull;
  } else {
    if (uPtr[0].ull > 1000000000ULL) {
      uint64_t gcc_helper0, gcc_helper1;
      uPtr[0].ull = _divlu2r(uPtr[0].ull);
      sreg0.ull = _divlu2r((uint64_t)uPtr[0].uls.hi * 18U);
      gcc_helper0 = ((uint64_t)uPtr[0].uls.lo * 709551616U);
      gcc_helper1 = ((uint64_t)uPtr[0].uls.lo * 18U)
                  + ((uint64_t)uPtr[0].uls.hi * 446744073U);
      sreg1.ull = _divlu2r(((uint64_t)uPtr[0].uls.hi * 709551616U)
                          + ((uint64_t)uPtr[0].uls.lo * 446744073U));
      gcc_helper0 += ((uint64_t)sreg1.uls.lo * 1000000000U);
      sreg1.ull = (((uint64_t)sreg0.uls.lo * 1000000000U)
                   + (uint64_t)sreg1.uls.hi
                   + gcc_helper1);
      if (gcc_helper0 >= _CARRY)  sreg1.ull += 1ULL, gcc_helper0 -= _CARRY;
      uPtr[2].ull = gcc_helper0;
      if (sreg1.ull >= _CARRY)  sreg0.uls.hi += 1, sreg1.ull -= _CARRY;
      if (sreg0.uls.hi != 0) {
        uPtr[0].uls.lo = sreg0.uls.hi, uPtr[0].uls.hi = 0;
        uPtr[1].ull = sreg1.ull;
        fractionalPtr++, pw10 += 18, unit_18++;
      } else {
        uPtr[0].ull = sreg1.ull;
        uPtr[1].ull = uPtr[2].ull;
        uPtr[2].ull = 0;
      }
    } else {
/* wtf? */
      uint32_t a0 = uPtr[0].uls.lo;
      uint64_t gcc_helper0 = (uint64_t)a0 * 18U;
      uint64_t gcc_helper1 = (uint64_t)a0 * 709551616U;
      sreg0.ull = _divlu2r((uint64_t)a0 * 446744073U);
      gcc_helper0 += (uint64_t)sreg0.uls.hi;
      gcc_helper1 += ((uint64_t)sreg0.uls.lo * 1000000000U);
      if (gcc_helper1 >= _CARRY)  gcc_helper1 -= _CARRY, gcc_helper0 += 1ULL;
      uPtr[0].ull = gcc_helper0;
      uPtr[1].ull = gcc_helper1;
    }
  }
    /* deal with fraction part multiply by 2^64 */
  if (reg0.ull != 0) {
      /* add in first fractional when used & 63 */
    hi = reg0.uls.hi >> 28;
    reg0.ull -= (hi += (hi >= 7)) * _CARRY;
    reg0.ull += fractionalPtr[-1].ull;
    while (reg0.ull >= _CARRY)  hi += 1, reg0.ull -= _CARRY;
    fractionalPtr[-1].ull = reg0.ull;
    fractionalPtr[-2].ull += (uint64_t)hi;
    if (reg1.ull != 0)
      last = __fractional(fractionalPtr, reg1);
  } else if (reg1.ull != 0) {
    hi = 0;
    if (reg1.ull >= _CARRY) {
      hi = reg1.uls.hi >> 28;
      reg1.ull -= (hi += (hi >= 7)) * _CARRY;
    }
    reg1.ull += fractionalPtr[-1].ull;
    while (reg1.ull >= _CARRY)  hi += 1, reg1.ull -= _CARRY;
    fractionalPtr[-1].ull = reg1.ull;
    fractionalPtr[-2].ull += (uint64_t)hi;
  }
    /* valid wholes (1st, u18 count) and fractional count */
  return ((pw10 << 16) | ((last + unit_18 + 1) << 4) | (last + 1));
}

static uint32_t
__positive_exponent_fp(_ull_t *uPtr, uint32_t w160[5], int type) {

  uint32_t  pw2;  /* power of 2 */
  uint32_t  unit_18;
  uint32_t  u32;

    /* load 'passed' data */
  pw2 = (w160[4] & 0x7FFF) - 16383;

    /* handle up to/including 129bit mantissa */
  uint32_t  packed_return;
  packed_return = __positive_lowexp128(uPtr, w160, (pw2 < 128 ? pw2 : 128));
  if (pw2 <= 128)  return packed_return;
  pw2 -= 128;

  if ((pw2 & 0xf) != 0) {
    uint32_t m = pw2 & 0xf;
    uint32_t n = 16 - m;
    uPtr[0].uls.lo = ((uPtr[0].uls.lo << m)
                      + (u32 = (((uint32_t)((uPtr[1].uls.hi
                                        * 2475880078ULL) >> 32)) >> (11 + n))));
    _ull_t gcc_helper;
    gcc_helper.ull = (uPtr[1].ull - ((u32 << n) * 15258789062500ULL));
    SHLDU32(gcc_helper.uls.hi, gcc_helper.uls.lo, m);
    gcc_helper.ull += (uint64_t)(u32 = (((uint32_t)((uPtr[2].uls.hi
                                        * 2475880078ULL) >> 32)) >> (11 + n)));
    if (gcc_helper.ull >= _CARRY)
      uPtr[0].uls.lo++, gcc_helper.ull -= _CARRY;
    uPtr[1].ull = gcc_helper.ull;
    uPtr[2].ull = (uPtr[2].ull -= (u32 << n) * 15258789062500ULL) << m;
    if (uPtr[2].ull >= _CARRY)
      uPtr[1].uls.lo++, uPtr[2].ull -= _CARRY;
  }
  unit_18 = 2;
  if ((pw2 >> 4) != 0) {
    uint32_t unit_max = type >> 16;
    pw2 >>= 4;
    do {
      uint64_t *cap = &uPtr[((unit_18 > unit_max) ? unit_max : unit_18)].ull;
      _ull_t work;
      uint64_t *input, *output, next;
      input = output = &uPtr->ull;
      next = input[1];
      if ((work.ull = *input) >= 15258789062500) {
        unit_18++;
        *output =
              (uint64_t)(u32 = (uint32_t)((work.uls.hi * 2475880078ULL) >> 43));
        work.ull -= u32 * 15258789062500ULL;
        output++;
      }
      *output = work.ull << 16;
      ++input;
      do {
        work.ull = next;
        next = *(++input);
        *output += (uint64_t)(u32 = (uint32_t)(((work.uls.hi * 2475880078ULL)
                                                  + (work.uls.hi >> 1)) >> 43));
          /* >= _CARRY does not occur, just forces better gcc code,
           * but probably does occur. approx 2% speed increase using dead code */
        if (*output >= _CARRY)  output[-1] += 1, *output -= _CARRY;
        *(++output) = (work.ull - (u32 * 15258789062500ULL)) << 16;
        if (*output >= _CARRY)  output[-1] += 1, *output -= _CARRY;
      } while (input <= cap);
    } while ((--pw2));
  }
  return (((unit_18 * 18) << 16) | ((unit_18 + 1) << 4));
}

static uint32_t
__negative_exponent_fp(_ull_t *uPtr, uint32_t w160[5], int type) {

  const uint64_t fConst = 15258789062500ULL; /* 0xDE0 B6B3A764 */
  int      pw2, pw10;         /* power of 2, power of 10 */
  uint32_t index;             /* pre-use as flag */
  _ull_t   reg0;

  pw10 = -18;
  pw2  = 16383 - (w160[4] & 0x7FFF);

#ifdef LEGACY_DENORMAL
  pw2 -= (index = ((uint32_t)pw2 == 16383U));
#endif

  reg0.ull = *(uint64_t*)&w160[2];

  if (*(uint64_t*)&w160[0] != 0) {
    _ull_t   reg1;
    reg1.ull = *(uint64_t*)&w160[0];
    __fractional(uPtr, reg0);
    __fractional_128(uPtr, reg1);
#ifdef LEGACY_DENORMAL
    if (index == 0)  uPtr->ull += _CARRY;
#else
    uPtr->ull += _CARRY;
#endif
    index = 8;
  } else if (reg0.ull != 0) {
      /* convert fractional to base 10 */
    __fractional(uPtr, reg0);
#ifdef LEGACY_DENORMAL
      /* 2 cases: denormal, normal */
    if (index == 0)  uPtr->ull += _CARRY;
#else
    uPtr->ull += _CARRY;
#endif
    index = 5;
  } else {
    if (pw2 < 18) {
        /* straight power of 2 */
        /* first 17, [-1, -17]... shift of 10^18,
         * 10^18/18446744073709551616 =
         * 0.0542101086242752217003726400434970855712
         * 0.0542101086242752217003726400434970855712 * 2^64 =
         * 10^18 = 0x232830643 * 2^32 + 2808348672 */
        /* no whole, all fraction */
      uPtr->uls.lo = ((uint32_t)232830643U << (32 - pw2))
                     | ((uint32_t)2808348672U >> pw2);
      uPtr->uls.hi =  (uint32_t)232830643U >> pw2;
      return (uint32_t)((-(18 << 16)) | (1 << 4) | 8);
    }
      /* there are 18 trailing zeroes to _CARRY */
    uPtr[0].ull = _CARRY >> 18;
    pw2 -= 18;
    index = 5;
  }
    /* 5^18 * 2^2 * 2^16 = 10^18 */
    /* each shift into new ull is multiplied by 10^18.
     * or 2^-16 * 10^18 = shift * 5^18 * 2^2 */
  if (pw2 & 0xf) {
      /* partial 2^-16, odd wording to assist gcc */
    uint32_t m = pw2 & 0xf;
    uint32_t shift = (16 - m);
    uint32_t gcc_helper;
    if (index == 8) {
      gcc_helper = (uPtr[7].uls.lo << shift) & 0xFFFF;
      uPtr[7].ull = gcc_helper * fConst;
      SHRDU32(uPtr[6].uls.hi, uPtr[6].uls.lo, m);
      gcc_helper = (uPtr[5].uls.lo << shift) & 0xFFFF;
      uPtr[6].ull += gcc_helper * fConst;
      SHRDU32(uPtr[5].uls.hi, uPtr[5].uls.lo, m);
      gcc_helper = (uPtr[4].uls.lo << shift) & 0xFFFF;
      uPtr[5].ull += gcc_helper * fConst;
      SHRDU32(uPtr[4].uls.hi, uPtr[4].uls.lo, m);
      gcc_helper = (uPtr[3].uls.lo << shift) & 0xFFFF;
      uPtr[4].ull += gcc_helper * fConst;
    } else {
      gcc_helper = (uPtr[3].uls.lo << shift) & 0xFFFF;
      uPtr[4].ull = gcc_helper * fConst;
    }
    SHRDU32(uPtr[3].uls.hi, uPtr[3].uls.lo, m);
    gcc_helper = (uPtr[2].uls.lo << shift) & 0xFFFF;
    uPtr[3].ull += gcc_helper * fConst;
    SHRDU32(uPtr[2].uls.hi, uPtr[2].uls.lo, m);
    gcc_helper = (uPtr[1].uls.lo << shift) & 0xFFFF;
    uPtr[2].ull += gcc_helper * fConst;
    SHRDU32(uPtr[1].uls.hi, uPtr[1].uls.lo, m);
    gcc_helper = (uPtr[0].uls.lo << shift) & 0xFFFF;
    uPtr[1].ull += gcc_helper * fConst;
    SHRDU32(uPtr[0].uls.hi, uPtr[0].uls.lo, m);
    if ((uPtr[0].uls.hi | uPtr[0].uls.lo) == 0) {
      pw10 -= 18;
      uPtr[0].ull = uPtr[1].ull, uPtr[1].ull = uPtr[2].ull;
      uPtr[2].ull = uPtr[3].ull, uPtr[3].ull = uPtr[4].ull;
      if (index == 8) {
        uPtr[4].ull = uPtr[5].ull, uPtr[5].ull = uPtr[6].ull;
        uPtr[6].ull = uPtr[7].ull, uPtr[7].ull = 0;
      } else {
        uPtr[4].ull = 0;
      }
    }
  }
    /* 2^-16, multiples */
  if ((pw2 >> 4) != 0) {
    _ull_t *regPtr, *cap;
    pw2 >>= 4;
      /* min regs reqired to represent arg_prec */
    cap = uPtr + (unsigned)(type >> 16);
      /* track 10^18 ull expansion */
    int16_t fcnt = 0;
    do {
      uint64_t work;
      uint32_t w0;
      int32_t flag;
      regPtr = uPtr;
      w0 = (uint32_t)regPtr->uss.w0;
      fcnt += (flag = -((regPtr->ull = regPtr->ull >> 16) == 0));
      work = (++regPtr)->ull;
      do {
        uint64_t m0 = w0 * fConst;
        w0 = (uint16_t)work;
        regPtr[flag].ull = m0 + (work >> 16);
        ++regPtr;
      } while ((regPtr <= cap) && ((work = regPtr->ull) != 0));
      (regPtr += flag)->ull = w0 * fConst;
    } while ((--pw2) != 0);
    index = (int)(regPtr - uPtr) + 1;
    pw10 += fcnt * 18;
  }
  return ((pw10 << 16) | (index << 4) | 8);
}

/* enters with 'sSize = strPtr - sPtr;'.
 * s, sPtr could have been malloc'd on entry, but expected to have been
 * cleared, output used, prior to entry. Possibly previous real allocation,
 * output to 'buffer', FILE or supplied, and not free'd.
 * printf() supplies BUFSTRSIZE on entry, realtostr supplies 45 ulls.
 * BUFSTRSIZE considered large for normal requests,
 * 45 ulls covers all needs for double reals.
 * all real types generally need 9, [±][0][.](precision)[e±000[0]]
 * IS_TYPE_F adds exponent to count, [±][0](exponent)[.](precision)[e±000[0]]
 * IS_TYPE_F has possiblity of grouping:
 * GRP_PREFIX assumes thousands, xxx,xxx,xxx,xxx etc. = 6 per ull
 * can't reuse precision 'reg's as double duty... 18 bytes / 8 byte ull
 * bufS(string) must come first for free'ing of allocation
 */

#pragma mark *** External Interfaces ***

#if (!__GNUC_PREREQ(4,5))
#pragma GCC diagnostic ignored "-Wuninitialized"
#endif

unsigned char *
realtostr(uint32_t w160[5], unsigned char **s, int type,
          int arg_prec, int arg_flags, unsigned decimal) {

  int exponent, rpos;   /* Rounding POSition */
    /* function used based on exponent, math unit */
  uint32_t (*math_func)(_ull_t *, uint32_t [5], int);
  unsigned char  *sPtr, dblt_sign, *decimalPtr;
    /* set up for precision of 792 digits, 18/ull * 44ull */
    /* malloc if exponent and precision dictate, 44ull = 352 bytes */
    /* reg: static reserved,
     * regs: actual reg use address (stack or allocated) */
  _ull_t reg[45], *regs;
  /* surpress warning due to zero jump, zero runs through allocation unit
   * incase of large precision requests. */
#if __GNUC_PREREQ(4,5)
#pragma GCC diagnostic ignored "-Wuninitialized"
#endif
    /* regs: top of stack, ubPtr: bottom of stack, ufPtr: fractional start */
  _ull_t *ubPtr, *ufPtr;
  int d0;   /* Digit0 (first digit) */
#if __GNUC_PREREQ(4,5)
#pragma GCC diagnostic pop
#endif
  unsigned strsz, pw2, packed_return;

                        /*** input defaults ***/
  if (arg_prec < 0)  arg_prec = 6;
    /* CASE 'g':  initial zero(or first digit) is significant digit */
  if ((arg_prec) && (IS_TYPE_G(type)))  --arg_prec;

                        /*** sign ***/
  if ((w160[4] & 0x8000) != 0)  dblt_sign = '-';
  else {
    dblt_sign = 0;
    if ((arg_flags & (SIGN_PREFIX | SPC_PREFIX)) != 0)
      dblt_sign = (arg_flags & SPC_PREFIX) ? ' ' : '+';
  }
                        /*** exponent ***/
    /* Case where bypasses all below code */
  if ((exponent = w160[4] & 0x7FFF) == 0x7FFF) {
      /* inf or nan, nan(n-char-sequence) */
    *(sPtr = *s) = dblt_sign, sPtr += (dblt_sign != 0);
    return __n_char_sequence(w160, sPtr,
                                      (type | ((arg_flags & ALT_PREFIX) << 1)));
  }
    /* Mantissa greater than 64 can use up to 7 ulls. Establish default. */
    /* digits calculations error on overestimate needed */
  uint32_t mbit = __mbits[(type >> 11)];
  pw2 = (mbit > 64) ? 7 : 4;
    /* Decide ulls needed (pw2), and math_func, based on exponent. */
  if (exponent < 0x3FFF) {
#ifdef LOW_PRECISION
    if ( ((exponent <= NEG_CUTIN) && (exponent >= NEG_CUTOUT)) &&
                                            (arg_prec < NEG_FULL_IN) ) {
      math_func = __negative_exponent_lp;
    } else
#endif
    {
      math_func = __negative_exponent_fp;
        /* Type 'f' or large precisions must calculate needed ulls. */
      if ( ((((uint32_t)(0x3FFF - exponent) >> 4) != 0) && (arg_prec >= 63)) ||
          (!IS_TYPE_E(type)) ) {
          /* Firstly calculate the number of prefixing zeros (log2). */
        uint32_t dgt;
        dgt = ((uint32_t)(((uint64_t)(0x3FFF - exponent)
                                                    * 2585827973U) >> 32)) >> 1;
          /* With 'f', if arg_prec less than prefixing, return is a string
           * of zeroes. Must set up for here, so we can enter into the
           * allocation section */
        if ( (IS_TYPE_F(type)) && ((unsigned)arg_prec < dgt) ) {
          exponent = 0;
          *(uint64_t*)&w160[2] = (*(uint64_t*)&w160[0] = 0);
        } else {
            /* Calculate significant digits. */
          dgt = mbit - 1 + (0x3FFF - exponent) - dgt;
          if (dgt > (unsigned)arg_prec)  dgt = arg_prec;
            /* adjust default ulls by dividing digits by 18 */
          if (dgt > 38)
            pw2 += (uint32_t)((((uint64_t)(uint32_t)(dgt - 38))
                                                 * (uint32_t)238609295U) >> 32);
    } } }
  } else {
      /* Positive exponents. Up tp 2^128 can have fractional ull needs */
    if (exponent >= (0x3FFF + 128))
      pw2 = 2;
#ifdef LOW_PRECISION
      /* Type 'f' precision only applies to < 2^128, greater is just zeroes */
    if ( ( ((exponent >= POS_CUTIN) && (exponent <= POS_CUTOUT)) &&
          (arg_prec < POS_FULL_IN) ) && (!IS_TYPE_F(type)) )
        math_func = __positive_exponent_lp;
    else
#endif
    {
      math_func = __positive_exponent_fp;
        /* Type 'f' requires maximum ulls to cover all significant digits */
      if ( ((exponent >= 0x40c2) && (arg_prec >= 27)) || (IS_TYPE_F(type)) ) {
        uint32_t dgt;
        dgt = ((uint32_t)(((uint64_t)(exponent - 0x3FFF)
                                                    * 2585827973U) >> 32)) >> 1;
          /* 'e' doesn't need full precision */
        if ((IS_TYPE_E(type)) && ((unsigned)arg_prec < dgt))  dgt = arg_prec;
          /* divide by 18 for number ulls needed */
        pw2 = 1 + (uint32_t)(((uint64_t)((uint32_t)dgt) * 252645135U) >> 32);
      }
    }
  }
                        /*** allocation ***/
    /* allocate reg here based on exponent/precision, see above notes */
    /* group allocation, fprintf() to free, returning we allocated thru 's' */
  strsz = arg_prec + 9;
    /* sets loop limits for requested arg_prec */
  type |= pw2 << 16;
    /* type F has special requirements, if positive exponent */
  if ((type << 31) & ~(exponent - 0x3FFF)) {
      /* grouping assumption of thousands: 1,000,000 */
      /* add in exponent: [±][0](exponent)[.](precision)[e±000[0]] */
    uint32_t triplets = (exponent - 0x3FFF);
    strsz += 1
          + (((uint32_t)(((uint64_t)((uint32_t)triplets)
                                                   * 2585827973U) >> 32)) >> 1);
    if ((arg_flags & GRP_PREFIX) != 0)
      strsz += ((uint16_t)21845 * (uint32_t)triplets) >> 16;
  }
  regs = reg;
  if ((pw2 > 44) || (strsz > BUFSTRSIZE)) {
      /* if either static exceeds limit, allocate both */
    strsz = (strsz + ((1 << 6) - 1)) & ~((1 << 6) - 1);
      /* test for non-static string buffer */
    if (arg_flags & ALLOC_BUF)  free(*s);
      /* assignment to sPtr, sPtr is one tested and free'd in fprintf() */
      /* request 1 more than needed to overwrite pass limit.
       * if 7 ulls needed [0-7] actually needed (8) + 1 for excess write */
    if ((sPtr = malloc((size_t)(strsz + ((pw2 + 2) * sizeof(_ull_t))))) == NULL)
      return sPtr;
    *s = sPtr;
    regs = (_ull_t*)(sPtr + strsz);
  }
    /* load sPtr and sign, now that *s is known */
  *(sPtr = *s) = dblt_sign, sPtr += (dblt_sign != 0);
    /* zero regs, no longer part of math units */
  do regs[pw2].uls.hi = 0, regs[pw2].uls.lo = 0; while ((int32_t)(--pw2) >= 0);
    /* zero test now that allocation occured. Possible extreme '0' precision. */
  if ((exponent == 0) && ((*(uint64_t*)&w160[2] | *(uint64_t*)&w160[0]) == 0)) {
      /* Bypass math/rounding, but add correct signals */
    if (IS_TYPE_G(type))  type |= TYPE_F;
    type |= TYPE_ZERO;
    goto skip_round;
  }
                        /*** math ***/
  packed_return = (*math_func)(regs, w160, type);
    /* transfer info returned into addresses, exponent */
  exponent = (d0 = _first_digit(regs->ull));
  exponent += (int32_t)packed_return >> 16;
  ubPtr = regs + ((packed_return >> 4) & 0x3FF);
  packed_return &= 0x0F;
  ufPtr = ((packed_return == 0) ? ubPtr :
          ((packed_return == 0x08) ? regs : ubPtr - (packed_return - 1)));

                        /*** rounding ***/
    /* assign position 1 pass display precision */
  rpos = arg_prec + 1;
  if (IS_TYPE_F(type))  {
      /* this excludes positive exponents, they will not jump to skip */
    if (arg_prec < ~exponent)  goto skip_round;
      /* positive exponents must count pre-radix as precision */
    if (~exponent >> 31)
      arg_prec += exponent;
      /* when negative, remove pre-zero count, positive add in whole portion */
    rpos += exponent;
  }
    /* rounding position <= first digit position, has front end zeroes */
  if ((rpos -= d0) > 0) {
    _ull_t *aPtr = regs;
      /* test rounding for second ull or higher, assume not large arg_prec */
    while (((++aPtr) < ubPtr) && (rpos > 18))  rpos -= 18;
      /* verify position has digits to round */
    if (aPtr < ubPtr) {
        /* set last ull, if rpos == 1 then exclude current aPtr */
      ubPtr = aPtr + (rpos != 1);
      if (ufPtr > ubPtr)  ufPtr = ubPtr;
      const uint64_t *fc = _fcarry;
      if ((aPtr->ull += fc[18 - rpos]) >= _CARRY) {
        uint64_t t = aPtr[-1].ull + 1ULL;
          /* carry forced propagation, makes ull == 0 */
        (ubPtr = aPtr)->ull = 0;
        (--aPtr)->ull = t;
        if ((aPtr == regs) && (t >= fc[19 + d0])) {
          exponent++;
            /* type 'f' has increase in precision if positive exponent */
            /* condition of == 18 never occurs */
          arg_prec += (type & ((uint32_t)~exponent >> 31));
          ++d0;
        }
      }
    }
  } else {
      /* first ull rounding */
    const uint64_t *fc = _fcarry;
      /* limit reads of ulls to next register */
    ubPtr = regs + 1;
    if (ufPtr > ubPtr)  ufPtr = ubPtr;
      /* add '5' to rounding location, propagation test for first digit */
    if ((regs->ull += fc[-rpos]) >= fc[19 + d0]) {
      exponent++;
      if ((++d0) == 18) {
          /* rare case. inserted here to avoid alter of ulltobuffer for odd case
           * and testing all cases for this condition. */
          /* occurs @ 1e18, 1e-18
           9.9999950000000026e+17 first precision 6
           9.9999999999999987e+17 last
           9.9999950000000012e-19 first precision 6
           9.9999999999999988e-19 last
           */
          /* type f and negative exponent */
        decimalPtr = (unsigned char*)&decimal;
        if (((uint32_t)exponent >> 31) & type) {
          unsigned j, k;
          *sPtr++ = '0';
          *(uint16_t*)sPtr = *(uint16_t*)decimalPtr;
          j = 1 + (decimalPtr[1] != 0);
          sPtr += j, decimalPtr += j;
          if ((j = -exponent - 1)) {
            if (j >= (unsigned)arg_prec) goto L24;
            arg_prec -= j;
            k = j & 3;
            if ((j = (int)((unsigned)j >> 2)))
              do  *(uint32_t*)sPtr = 0x30303030U, sPtr += 4;  while ((--j));
            *(uint32_t*)sPtr = 0x30303030U;
            sPtr += k;
          }
          *sPtr++ = '1';
          if ((arg_prec -= 1) > 0)  goto L245;
          return sPtr;
        }
        *sPtr++ = '1';
        if ( (IS_TYPE_G(type)) && (((unsigned)exponent) <= (unsigned)arg_prec) )
          type |= TYPE_F;
        if ( (arg_prec) && (!(IS_TYPE_G(type)) || (arg_flags & ALT_PREFIX)) ) {
          unsigned dflag = (decimalPtr[1] != 0);
          *(uint16_t*)sPtr = *(uint16_t*)decimalPtr;
          sPtr += dflag + 1, decimalPtr += dflag + 1;
          goto L245;
        }
        goto L25;
      }
    }
  }
                    /*** adjust for entered type... g ***/
    /* rounding can adjust exponent, so now can test if conditions met */
  if (IS_TYPE_G(type)) {
      /* this should exclude negatives */
    if (((unsigned)exponent) <= (unsigned)arg_prec)  goto L23;
    if (((unsigned)(exponent + 4)) <= 4) {
      arg_prec -= exponent;
L23:  type |= TYPE_F;
    }
  }
                        /*** output section ***/
skip_round:
  decimalPtr = (unsigned char*)&decimal;
    /* type f and negative exponent, <zero> */
  if ((((uint32_t)exponent >> 31) & type) | (IS_TYPE_ZERO(type))) {
    unsigned j, k;
    *sPtr++ = '0';
    *(uint16_t*)sPtr = *(uint16_t*)decimalPtr;
    j = 1 + (decimalPtr[1] != 0);
    if (!arg_prec) {
      if (IS_TYPE_E(type))  goto L11;
      if (arg_flags & ALT_PREFIX)  return (sPtr + j);
      return sPtr;
    }
    sPtr += j, decimalPtr += j;
    if ((j = -exponent - 1)) {
      if (j >= (unsigned)arg_prec) goto L24;
      arg_prec -= j;
      k = j & 3;
      if ((j = (int)((unsigned)j >> 2)))
        do  *(uint32_t*)sPtr = 0x30303030U, sPtr += 4;  while ((--j));
      *(uint32_t*)sPtr = 0x30303030U;
      sPtr += k;
    }
  }
  {
    /*      first ull
     if regs == ufPtr then all digits are part of precision. d0 does not
     count digits but returns log10... log10(1-9) = 0
     if 'f', data starts at sPtr. Otherwise starts sPtr + size of decimal.
     will write on last char of decimal, which then that char copies to sPtr
     then overwritten by decimal.
     (!IS_TYPE_F(type)) stringPtr = sPtr + decimalsz
     To determine if first digit is used as precision use
     (decimalPtr == (char*)&decimal)
     Two-byte decimal determined by (((char*)&decimal)[1] != 0)
     */

      /* deal with d0 */
      /* _fcarry multiplier based on d0, then can adjust d0 */
    const uint64_t *mConst = &_fcarry[35 - d0];
    if ((d0 += ((regs == ufPtr) & IS_TYPE_F(type))) > arg_prec)  d0 = arg_prec;
    unsigned char *stringPtr = sPtr + 1 + !!(((char*)&decimal)[1]);
    if (IS_TYPE_F(type))  stringPtr = sPtr;
    _ulltobuffer_nlr((regs->ull * *mConst), stringPtr,
                          (int)(d0 + (decimalPtr == (unsigned char*)&decimal)));

      /* type 'e' requires radix after first digit */
    if (!IS_TYPE_F(type)) {
        /* copy first digit and decimal point */
      *(uint16_t*)sPtr = cconst16_t((*stringPtr), (*decimalPtr));
      sPtr += 2;
        /* update and check for 2 byte decimal */
      if (*++decimalPtr != 0)  *sPtr = *decimalPtr, sPtr++, decimalPtr++;
      if (!arg_prec) {
        if (arg_flags & ALT_PREFIX)
              sPtr += (((char*)&decimal)[1] != 0);
        else  sPtr -= 1 + (((char*)&decimal)[1] != 0);
        goto L11;
      }
    }
      /* increment by number of digits and significant when TYPE_F */
    sPtr += d0 + (decimalPtr == (unsigned char*)&decimal);
    if ((arg_prec -= d0) == 0)  goto L25;
  }

  do {
      /* case where has whole/fraction */
    if ((++regs) >= ufPtr) {
      if (decimalPtr == (unsigned char*)&decimal) {
          /* this also used as delimiter for whole part, stop point for
           * trailing zero removal */
        unsigned dflag = (decimalPtr[1] != 0);
        *(uint16_t*)sPtr = *(uint16_t*)decimalPtr;
        sPtr += dflag + 1, decimalPtr += dflag + 1;
      }
        /* set to last ull, if not already at */
      if (ufPtr == ubPtr)  break;
      ufPtr = ubPtr;
    }
    d0 = (arg_prec < 18) ? arg_prec : 18;
    _ulltobuffer_nlr(regs->ull, sPtr, d0);
    sPtr += d0;
    if ((arg_prec -= d0) == 0)  goto L25;
  } while (1);
L24:
  if ( (arg_prec) && (!(IS_TYPE_G(type)) || (arg_flags & ALT_PREFIX)) ) {
      /* safe because of added room for exponent in allocation */
    unsigned k;
  L245:
    k = arg_prec & 3;
    arg_prec = (int)((unsigned)arg_prec >> 2);
    *(uint32_t*)sPtr = 0x30303030U;
    if (arg_prec)
      do  sPtr += 4, *(uint32_t*)sPtr = 0x30303030U;  while ((--arg_prec));
    sPtr += k;
  }
L25:
    /* case 'g', remove any trailing <zero>s */
  if (IS_TYPE_E(type))  goto L11;
  if (!(arg_flags & ALT_PREFIX)) {
      /* test only 'last' byte of decimal point.
       * '== 0' only occurs if written. decimal is at max 2 bytes */
    if (*decimalPtr == 0) {
      unsigned char ch;
      ch = *--sPtr;
      if (IS_TYPE_G(type))
        while (ch == '0')  ch = *--sPtr;
        /* decimal point is at max 2 bytes */
      if (ch != (unsigned char)decimalPtr[-1])  ++sPtr;
      else if (&decimalPtr[-1] != (unsigned char*)&decimal) --sPtr;
    }
  } else if (*decimalPtr != 0) {
    unsigned dflag = (decimalPtr[1] != 0);
    *(uint16_t*)sPtr = *(uint16_t*)decimalPtr;
    sPtr += dflag + 1, decimalPtr += dflag + 1;
  }
                        /*** exponent output ***/
  if (IS_TYPE_F(type))  return sPtr;
L11:
    /* converts g,G to e,E and adds sign (portable character set) */
  *(uint16_t*)sPtr = cconst16_t(('e' ^ ((type & 0x20) ^ UPPER_TYPE)),
                                ('+' - ((exponent >> 31) << 1)));
    /* absolute value */
  exponent = (exponent ^ (exponent >> 31)) - (exponent >> 31);
  if (exponent < 10) {
      /* exponent output reqires 2 digit display */
    *(uint16_t*)(&sPtr[2]) = cconst16_t('0',('0' + exponent));
    return (sPtr + 4);
  }
    /* quadruple, long doubles range [10,4966] */
  uint32_t ecd = (uint32_t)((((uint32_t)exponent << 19) * 2199023989ULL) >> 32);
  ++sPtr;
  if (exponent >= 1000)  *++sPtr = (ecd >> 28) + '0';
  ecd = ((ecd << 4) >> 4) * 10;
  if (exponent >= 100)   *++sPtr = (ecd >> 28) + '0';
  sPtr[1] = ((ecd = (((ecd << 4) >> 4) * 10)) >> 28) + '0';
  sPtr[2] = ((((ecd << 4) >> 4) * 10) >> 28) + '0';
  return (sPtr + 3);
}

/* "[±]0xh.hhhhp±d"
 * normalized: h. went with '1.x'
 * denornalize: .h went with '0.x'
 * output precision based on 'g' style
 */
unsigned char *
realtohex(uint32_t w160[5], unsigned char **s, int type,
         int arg_prec, int arg_flags, unsigned decimal) {

  unsigned char *sPtr = *s;
  int exponent;
  octle result;
  uint32_t pcnt;
  int32_t rounding = __mbits[(type >> 11)] >> 2;

                      /*** input defaults ***/
  char *decimalPtr = (char*)&decimal;
  uint32_t dflag = (decimalPtr[1] != 0);
  if (arg_prec < 0) {
    arg_prec = rounding;
    type |= TYPE_G;
  }
  rounding = (arg_prec < rounding);

    /* determine upper of lower case output */
  const char    *_outvalues = _const_outStr;
  if (IS_UPPER_TYPE(type)) _outvalues += 32;

                      /*** sign && exponent ***/
  exponent = w160[4] & 0x7FFF;
  if ((w160[4] & 0x8000) != 0)  *sPtr++ = '-';
  else {
    if ((arg_flags & (SIGN_PREFIX | SPC_PREFIX)) != 0)
      *sPtr++ =  (arg_flags & SPC_PREFIX) ? ' ' : '+';
  }
  if (exponent == 0x7FFF)
    return __n_char_sequence(w160, sPtr,
                                  (type | ((arg_flags & ALT_PREFIX) << 1)));

                      /*** prefix  0x or 0X ***/
  *((uint16_t *)sPtr) = ((uint16_t *)_outvalues)[12];
  sPtr += 2;
    /* pre-output hidden 'whole' bit */
  *sPtr++ = '1';

                      /*** fractional load ***/
  result = *(octle*)w160;
    /* zero/denormal check */
  if ((exponent -= 16383) == -16383) {
    sPtr[-1] = '0';
    if ((result.ulls.ull1 == 0) && (result.ulls.ull0 == 0)) {
      arg_prec = (exponent = 0);
      if (!(arg_flags & ALT_PREFIX))  goto out_exp;
    }
  }
    /* decimal point */
  *(uint16_t*)sPtr = *(uint16_t*)decimalPtr;
  sPtr += dflag + 1, decimalPtr += dflag + 1;
  if (arg_prec == 0) {
    if (!(arg_flags & ALT_PREFIX))
      sPtr -= dflag + 1, decimalPtr -= dflag + 1;
    goto out_exp;
  }

                        /*** rounding ***/
  if (rounding) {
      /* when arg_prec is less than 'type's' nibble count */
    uint32_t rbit = (arg_prec << 2);
    if (rbit >= 64) {
      if (rbit == 64) {
        result.ulls.ull1 += (result.ulls.ull0 > 0x8000000000000000ULL);
        goto r1_check;
      }
      rbit -= 64;
      result.ulls.ull0 +=
          (uint64_t)((result.ulls.ull0 & (0xffffffffffffffffULL >> rbit))
                     > (0x8000000000000000ULL >> rbit)) << (63 - rbit);
      if (result.ulls.ull0 < *(uint64_t*)w160) {
        result.ulls.ull1 += 1ULL;
        goto r1_check;
      }
    } else {
      result.ulls.ull1 +=
          (uint64_t)((result.ulls.ull1 & (0xffffffffffffffffULL >> rbit))
                     > (0x8000000000000000ULL >> rbit)) << (63 - rbit);
    r1_check:
      if (result.ulls.ull1 < *(uint64_t*)&w160[2]) {
        result.ulls.ull1 = 0x8000000000000000ULL;
        exponent++;
      }
    }
  }

                        /*** output ***/
    /* work as 2-64bits */
  pcnt = (arg_prec < 16) ? arg_prec : 16;
  arg_prec -= pcnt;
  do {
      /* rotate into position */
    result.ulls.ull1 = (result.ulls.ull1 >> 60) | (result.ulls.ull1 << 4);
    *sPtr++ = _outvalues[(result.uls.ul2 & 0x0000000F)];
  } while ((--pcnt));
  if ((arg_prec != 0) && (result.ulls.ull0 != 0)) {
    pcnt = (arg_prec < 16) ? arg_prec : 16;
    arg_prec -= pcnt;
    do {
        /* rotate into position */
      result.ulls.ull0 = (result.ulls.ull0 >> 60) | (result.ulls.ull0 << 4);
      *sPtr++ = _outvalues[(result.uls.ul0 & 0x0000000F)];
    } while ((--pcnt));
  }

  if (IS_TYPE_G(type)) {
    unsigned char ch = *--sPtr;
    while (ch == '0')  ch = *--sPtr;
    if (ch != (unsigned char)decimalPtr[-1])  ++sPtr;
    else if (&decimalPtr[-1] != (char*)&decimal) --sPtr;
  } else if (arg_prec) {
    pcnt = arg_prec & 3;
    arg_prec = (int)((unsigned)arg_prec >> 2);
    *(uint32_t*)sPtr = 0x30303030U;
    if (arg_prec)
      do  sPtr += 4, *(uint32_t*)sPtr = 0x30303030U;  while ((--arg_prec));
    sPtr += pcnt;
  }

            /*** exponent output (p±d p[-16494,+16383]) ***/
out_exp:
  *sPtr++ = _outvalues[19];
    /* based on portable character set */
  *sPtr++ = '+' - ((exponent >> 31) << 1);
    /* absolute value */
  exponent = (exponent ^ (exponent >> 31)) - (exponent >> 31);

  if (exponent < 10) {
    *sPtr = exponent + '0';
    return (sPtr + 1);
  }
    /* divide exponent by 10000   3518437209 */
  uint32_t ecd = (uint32_t)(((uint64_t)(uint32_t)exponent * 3518437209U) >> 17);
  ecd += 1 << 14;
  if (exponent >= 10000)  *sPtr++ = (ecd >> 28) + '0';
  ecd = ((ecd << 4) >> 4) * 10;
  if (exponent >= 1000)   *sPtr++ = (ecd >> 28) + '0';
  ecd = ((ecd << 4) >> 4) * 10;
  if (exponent >= 100)    *sPtr++ = (ecd >> 28) + '0';
  sPtr[0] = ((ecd = (((ecd << 4) >> 4) * 10)) >> 28) + '0';
  sPtr[1] = ((((ecd << 4) >> 4) * 10) >> 28) + '0';

  return (sPtr + 2);
}

#pragma mark *** Utilities ***

#include <errno.h>

double
wtod(uint32_t w160[5]) {

  octle   result = *(octle *)w160;
  unsigned char *cw = (unsigned char*)&result.ulls.ull0;

    /* possiblity of rounding forcing ff */
  if ((w160[4] & 0x7fff) <= 0x3C00) {
#ifdef LEGACY_DENORMAL
    uint16_t shift = 0x3C00 - (w160[4] & 0x7fff);
    if (shift <= 52) {
        /* when shift == 52 0xfffffffffffff fff >> 0 > 0x8000000000000 000 >> 0
           when shift == 0  0x0000000000000 fff      > 0x0000000000000 800 */
      uint32_t round =
        (((result.ulls.ull1 & (0xffffffffffffffffULL >> (52 - shift)))
         | (result.ulls.ull0 != 0))
                            > (0x8000000000000000ULL >> (52 - shift)));
        /* 52nd bit '1' hidden */
      result.ulls.ull0 = (result.ulls.ull1 >> 1) | 0x8000000000000000ULL;
      if (shift == 52)
        result.ulls.ull0 = (uint64_t)round;
      else
        result.ulls.ull0 = (result.ulls.ull0 >> (shift + 12)) + (uint64_t)round;
    } else {
      if (shift != 0x3C00)
        //errno = ERANGE;
        errno = 34;
      result.ulls.ull0 = 0;
    }
    result.uls.ul1 |= (w160[4] & 0x8000) << 16;
#else
    if ((w160[4] & 0x7fff) != 0x3C00)
      //errno = ERANGE;
      errno = 34;
    result.uls.ul0 = 0;
    result.uls.ul1 = (w160[4] & 0x8000) << 16;
#endif
    return *(double*)cw;
  }
  if ((w160[4] & 0x7fff) > 0x43FE) {
    if ((w160[4] & 0x7fff) >= 0x7FFF) {
        /* nan outputs lowest, drops highest */
      result.uss.us3 = (w160[4] & 0xFFF0) | (result.uss.us3 & 0x000F);
      return *(double*)cw;
    }
  dinf:
    //errno = ERANGE;
    errno = 34;
    result.uls.ul0 = 0;
    result.uls.ul1 = ((w160[4] & 0x8000) << 16) | 0x7ff00000U;
    return *(double*)cw;
  }
  result.ulls.ull0 = (result.ulls.ull1 >> 12)
                      + (((result.uss.us4 & 0x0FFF) | (result.ulls.ull0 != 0)) > 0x800);
  result.uss.us3 += (((w160[4] & 0x7fff) - 16383 + 1023) << 4) | (w160[4] & 0x8000);
  if ((result.uss.us3 & 0x7ff0) == 0x7FF0)  goto dinf;
  return *(double*)cw;
}

#pragma mark ***** real to w160

/* quadruple is IEEE-754 binary128 */
void
qtow(quadruple qdbl, uint32_t w160[5]) {

    /* required strict aliasing conversion */
  octle *iqdbl;
  unsigned char *cqdbl = (unsigned char*)&qdbl;
  iqdbl = (octle*)cqdbl;

  w160[4] = iqdbl->uss.us7;
  *(uint64_t*)&w160[2] = iqdbl->ulls.ull1 << 16;
  *(uint16_t*)&w160[2] = iqdbl->uss.us3;
  *(uint64_t*)&w160[0] = iqdbl->ulls.ull0 << 16;
}

/* abstract long double */
void
ldtow(LD_SUBST ldbl, uint32_t w160[5]) {

    /* required strict aliasing conversion */
  octle *ildbl;
  unsigned char *cldbl = (unsigned char*)&ldbl;
  ildbl = (octle*)cldbl;

  *(uint64_t*)w160 = 0;
#if (__LDBL_MANT_DIG__ == 53)
  dtow((double)ldbl, w160);
#elif (__LDBL_MANT_DIG__ == 64)
  w160[4] = ildbl->uss.us4;
    /* nan/infinty require explicit '1' */
  if ((ildbl->uss.us4 & 0x7fff) != 0x7fff)
    *(uint64_t*)&w160[2] = ildbl->ulls.ull0 << 1;
  else
    *(uint64_t*)&w160[2] = ildbl->ulls.ull0;
#elif (__LDBL_MANT_DIG__ == 113)
  qtow((quadruple)ldbl, w160);
#elif (__LDBL_MANT_DIG__ == 106)
  octle result;
  int16_t e16, e16_2;
  w160[4] = (ildbl->uss.us7 & 0x8000);
  e16 = ((ildbl->uss.us7 & 0x7ff0) >> 4) - 1023 + 16383;
  w160[4] |= e16;
  e16_2 = ((ildbl->uss.us3 & 0x7ff0) >> 4) - 1023 + 16383;
    /* zero, do nothing */
  if (ildbl->ulls.ull1 == 0) {
    *(uint64_t*)&w160[2] = 0;
    return;
  }
  result = *ildbl;
  if (e16 == 0x43ff) {
    if (e16 != e16_2) {
        /* inf */
      result.uss.us7 = 0x8000;
    } else {
        /* nan */
      result.ulls.ull1 = (result.ulls.ull1 << 12)
                          | ((result.uls.ul1 & 0x000fffff) >> 8);
      result.ulls.ull0 <<= 24;
    }
    w160[4] |= 0x7fff;
    *(uint64_t*)&w160[2] = result.ulls.ull1;
    *(uint64_t*)&w160[0] = result.ulls.ull0;
    return;
  }
 #ifdef LEGACY_DENORMAL
  if (e16_2 == 0x3C00) {
    /* denormal, cases:
     * normal/denormal  merge
     * denormal/zero    do nothing
     */
    if (e16 == 0x3C00) {
      if (((result.uss.us7 & 0xf) == 0) && (result.uls.ul2 == 0)) {
        w160[4] &= 0x8000;
        *(uint64_t*)&w160[2] = 0;
        *(uint64_t*)&w160[0] = 0;
        return;
      }
      *(uint64_t*)&w160[2] = result.ulls.ull1 << 12;
      *(uint64_t*)&w160[0] = 0;
      return;
    }
    result.uss.us3 &= 0xf;
    result.ulls.ull0 <<= (53 - (e16 - 0x3C00));
      /* |xxxxxxxxxxxx 0aaaaaaaaaaa aaaaaaaaa|
       *  a's are shifted 1 because of 0 exponent */
    result.uss.us7 = (result.uss.us7 & 0xf) | ((e16 != 0x3C00) << 4);
      /* 12 bits from ull0 all 0s from exponent/sign/bit53 */
    result.ulls.ull1 = (result.ulls.ull1 << 12) | (result.uls.ul1 >> 8);
    result.ulls.ull0 <<= 24;
    *(uint64_t*)&w160[2] = result.ulls.ull1;
    *(uint64_t*)&w160[0] = result.ulls.ull0;
    return;
  }
 #endif
  /* Both doubles are normals */
  result.ulls.ull1 <<= 12;
  result.ulls.ull0 <<= 12;
  /* First double can be less than 52 bit mantissa if second double
   * was forced to use bits to normalize second double.
   * Second double more than likely greater than the normal continuous 52
   * bit mantissa calculation due to need of implicit '1'. */
  if ((e16 - 52) <= e16_2) {
      /* pulled bits from first double, add extra 11 bits to fill 1+63 */
    int16_t shift = e16_2 - (e16 - 52);
    result.ulls.ull0 >>= 1;
    result.uss.us3 |= 0x8000;
    result.ulls.ull1 |= (result.ulls.ull0 >> (51 - shift));
      /* clear ull1 bits */
    result.ulls.ull0 = result.ulls.ull0 << (shift + 13);
  } else {
      /* Second double >= 52 bits after first double. */
    int16_t shift = (e16 - 52) - e16_2;
    result.ulls.ull0 >>= 1;
    result.uss.us3 |= 0x8000;
    result.ulls.ull0 >>= shift - 1;
     /* pull top 11/12 bits into ull1 */
    result.ulls.ull1 |= result.ulls.ull0 >> 52;
    result.ulls.ull0 = result.ulls.ull0 << 12;
  }
  *(uint64_t*)&w160[2] = result.ulls.ull1;
  *(uint64_t*)&w160[0] = result.ulls.ull0;
#else
  #error: undefined mantissa digits
#endif
}

/* double is IEEE-754 binary64 */
void
dtow(double dbl, uint32_t w160[5]) {

    /* required strict aliasing conversion */
  uint64_t *idbl;
  unsigned char *cdbl = (unsigned char*)&dbl;
  idbl = (uint64_t*)cdbl;

  *(uint64_t*)w160 = 0;
  w160[4] = (uint32_t)(*idbl >> 52);
  *(uint64_t*)&w160[2] = *idbl << 12;
  if ((w160[4] & 0x7FF) == 0x7FF)
    w160[4] = (w160[4] << 4) | 0x000F;
  else
    w160[4] = ((w160[4] & 0x7FF) + 16383 - 1023) | ((w160[4] & 0x800) << 4);
  if ((w160[4] & 0x7FFF) == 0x3c00) {
      /* conversion of denormals to normals */
    if (*(uint64_t*)&w160[2] != 0) {
      uint32_t shift;
      if (w160[3] == 0) {
        CNTLZW(shift, w160[2]);
        w160[3] = w160[2] << (shift + 1);
        w160[4] -= 32 + shift;
        w160[2] = 0;
      } else {
        CNTLZW(shift, w160[3]);
        if (shift != 31) {
          uint32_t hi = w160[3], lo = w160[2];
          SHLDU32(hi, lo, (shift + 1));
          w160[3] = hi, w160[2] = lo;
        } else
          w160[3] = w160[2], w160[2] = 0;
        w160[4] -= shift;
      }
    } else {
        /* zero */
      w160[4] &= 0x8000;
    }
  }
}

/* float is IEEE-754 binary32 */
/* force float denornal to double, and zero to as float zero */
void
ftow(float flt, uint32_t w160[5]) {

    /* required strict aliasing conversion */
  unsigned char *cf = (unsigned char*)&flt;

  *(uint64_t*)w160 = 0;
  *(uint64_t*)&w160[2] = 0;
  w160[4] = (*(uint32_t*)cf) >> 23;

  w160[3] = (*(uint32_t*)cf) << 9;
  if ((w160[4] & 0x0FF) == 0x0FF)
    w160[4] = (w160[4] << 7) | 0x00FF;
  else
    w160[4] = ((w160[4] & 0xFF) + 16383 - 127) | ((w160[4] & 0x100) << 7);
  if ((w160[4] & 0x7FFF) == 0x3f80) {
      /* conversion of denormals to normals */
    if (w160[3] != 0) {
      uint32_t shift;
      CNTLZW(shift, w160[3]);
      w160[3] <<= (shift + 1);
      w160[4] -= shift;
    } else {
        /* zero */
      w160[4] &= 0x8000;
    }
  }
}

#pragma mark ***** real to real

/* convert binary128 to non-exact long double (113,106,64,53,etc) */
LD_SUBST
qtold(quadruple qdbl) {

#if (__LDBL_MANT_DIG__ == 113)
    /* C type 'long double' defined same as quadruple, just cast */
  return (LD_SUBST)qdbl;
#elif (__LDBL_MANT_DIG__ == 53)
    /* binary64 reduces exponent size, and mantissa */
  return (long double)qtod(qdbl);
#elif (__LDBL_MANT_DIG__ == 64)
    /* e80 adds implicit '1' between exponent and mantissa, along with
     * reducing mantissa bits */
  octle result = (octle)qdbl;
  unsigned char *cld = (unsigned char*)&result;
    /* NaN uses lowest bits, bit 0 start, for n-char-sequence */
  if ((result.uss.us7 & 0x7fff) != 0x7fff) {
    uint32_t round = ((result.ulls.ull0 & 0x0001ffffffffffff)
                      > 0x0001000000000000);
      /* << 16 >> 1 used to clear 63rd bit to watch for overflow */
    result.ulls.ull0 = (((result.ulls.ull1 << 16) >> 1)
                        | (result.uss.us3 >> 1)) + (uint64_t)round;
      /* add possible 'overflow', could use ull1>>48 if want clean pad bits */
    result.uss.us4 = result.uss.us7 + (result.uss.us3 >> 15);
      /* make sure didn't cause NaN */
    if ((result.uss.us4 & 0x7fff) == 0x7fff)
      //errno = ERANGE;
      errno = 34;
 #ifdef LEGACY_DENORMAL
    result.uss.us3 |= ((result.uss.us4 & 0x7fff) != 0) << 15;
 #else
    result.uss.us3 |= 0x8000;
 #endif
  } else {
    result.uss.us4 = result.uss.us7;
      /* e80s require forced 63rd bit */
    result.uss.us3 |= 0x8000;
  }
  return *(long double*)cld;
#elif (__LDBL_MANT_DIG__ == 106)
  octle result;
  unsigned char *cld = (unsigned char*)&result;
  result = qdbl;
  uint32_t shift;
  int16_t sign = result.uss.us7 & 0x8000;
  int16_t e16 = result.uss.us7 & 0x7FFF;
  if (e16 == 0x7FFF) {
    result.ulls.ull1 = (result.ulls.ull1 << 12) | (result.uss.us3 >> 4);
    result.uss.us3 = sign | (0x7ff0) | (result.uss.us3 & 0xf);
    result.uss.us7 = sign | (0x7ff0) | (result.uss.us7 & 0xf);
  } else if (e16 > 0x43FE) {
    errno = ERANGE;
    result.ulls.ull1 = result.ulls.ull0 = 0;
    result.uss.us3 = (result.uss.us7 = sign | (0x7ff0));
  } else if (e16 > 0x3C00) {
      /* force 106 bits */
    result.ulls.ull0 += (uint64_t)(((result.uls.ul0 & 0x7f) > 0x40) << 7);
    if (result.uls.ul1 < qdbl.uls.ul1)  result.ulls.ull1 += 1ULL;
    result.uss.us0 &= ~0x7f;
      /* set ull1 */
    result.ulls.ull1 = (result.ulls.ull1 << 4) | (result.ulls.ull0 >> 60);
    result.uss.us7 = sign
                   | ((e16 - 0x3FFF + 0x3FF) << 4) | (result.uss.us7 & 0xf);
      /* adjust flush left bits used to create ull0 */
    if ((result.ulls.ull0 <<= 4) == 0) {
      result.uss.us3 = sign;
      return *(quadruple*)cld;
    }
      /* determine ull0 possiblities
       * first doubles shift plus seconds is:
       * above 0 or <= 0. Seconds considers shift needed to
       * create above 0's implicit '1' */
    if ((e16 - 52) <= 0x3C00) {
        /* denormalize second double, 13 'cause 0 uses >>1 */
      shift = 0x3C00 - (e16 - 52) + 13;
      if (shift >= 64) {
        result.ulls.ull0 = 0;
        result.uss.us3 = sign;
      } else {
        result.ulls.ull0 >>= shift;
        result.uss.us3 = sign | (result.uss.us3 & 0xf);
      }
      return *(quadruple*)cld;
    }
    if (result.uls.ul1 != 0) {
      CNTLZW(shift, result.uls.ul1);
      shift++;
    } else {
      CNTLZW(shift, result.uls.ul0);
      shift += 33;
    }
    if ((e16 - (52 + shift)) > 0x3C00) {
        /* use shift for drop of implicit '1' and determining exponent */
        /* don't count implicit '1' drop into exponent */
      sign |= ((e16 - 0x3FFF + 0x3FF) - (52 + shift)) << 4;
      result.ulls.ull0 <<= shift;
      result.ulls.ull0 >>= 12;
      result.uss.us3 = sign | (result.uss.us3 & 0xf);
      return *(quadruple*)cld;
    } else {
        /* recalculate shift, must find implicit '1' from ull1 */
      int16_t right_shift;
        /* ffs returns bit index + 1, so bit 0 == 1 */
      if ((right_shift = ffs((int)result.uls.ul2)) == 0) {
        right_shift = ffs((int)result.uls.ul3) + 32;
      }
        /* drop 1 bit from ull1 */
      result.ulls.ull1 &= (0xffffffffffffffffULL << right_shift);
        /* adds 0's prior to right_shift */
      uint32_t round;
      round = ((result.ulls.ull0
                & (0xffffffffffffffffULL >> (64 - (right_shift + 12))))
               > (0x8000000000000000ULL >> (64 - (right_shift + 12))));
      result.ulls.ull0 >>= (right_shift - 1);
      result.ulls.ull0 >>= 12;
      result.ulls.ull0 += (uint64_t)round;
      sign |= ((e16 - (52 - (right_shift - 1))) - 0x3C00) << 4;
      result.uss.us3 = sign | (result.uss.us3 & 0xf);
      return *(quadruple*)cld;
    }
  } else {
    shift = 0x3C00 - e16;
    if (shift == 0) {
      result.ulls.ull1 = (result.ulls.ull1 << 3) | (result.uss.us3 >> 13);
      result.ulls.ull0 <<= 3;
    } else if (shift <= 52) {
        /* 52nd bit '1' hidden */
      result.ulls.ull1 = (result.ulls.ull1 << 15) | 0x8000000000000000ULL
                          | (result.uls.ul1 >> 17);
      uint32_t round =
        (((result.ulls.ull1 & (0x7fffffffffffffffULL >> (64 - (shift + 12))))
         | (result.ulls.ull0 != 0))
                            > (0x4000000000000000ULL >> (64 - (shift + 12))));
      if (shift == 52)
        result.ulls.ull1 = (uint64_t)round;
      else
        result.ulls.ull1 = (result.ulls.ull1 >> (shift + 12)) + (uint64_t)round;
    } else {
      if (shift != 0x3C00)  errno = ERANGE;
      result.ulls.ull1 = 0;
    }
    result.uss.us7 = sign | (result.uss.us7 & 0xf);
    result.ulls.ull0 = 0;
    result.uss.us3 = sign;
  }
  return *(quadruple*)cld;
#else
  #error: undefined mantissa digits
#endif
}

/* convert binary128 to binary64 */
double
qtod(quadruple qdbl) {

  uint32_t w160[5];
  unsigned char *wc = (unsigned char *)w160;
  octle iqdbl = qdbl;
  w160[4] = iqdbl.uss.us7;
  if ((iqdbl.uss.us7 & 0x7fff) != 0x7fff) {
    *(uint64_t*)&wc[8] = (iqdbl.ulls.ull1 << 16) | iqdbl.uss.us3;
    *(uint64_t*)wc = (iqdbl.ulls.ull0 << 16);
  } else {
    *(uint64_t*)&wc[8] = iqdbl.ulls.ull1;
    *(uint64_t*)wc = iqdbl.ulls.ull0;
  }
  return wtod(w160);
}

/* convert abstract long double to binary64 */
double
ldtod(LD_SUBST ldbl) {

#if (__LDBL_MANT_DIG__ == 53)
  unsigned char *wc = (unsigned char*)&ldbl;
  return *(double*)wc;
#elif (__LDBL_MANT_DIG__ == 106)
  unsigned char *wc = (unsigned char*)&ldbl.ulls.ull1;
  return *(double*)wc;
#elif (__LDBL_MANT_DIG__ == 64)
  unsigned char *wc = (unsigned char*)&ldbl;
  octle result = *(octle*)wc;
  if ((result.uss.us4 & 0x7fff) == 0x7fff) {
    result.uss.us3 = (result.uss.us3 & 0x000f) | (result.uss.us4 & 0xfff0);
  } else {
    int16_t sign, e16;
    sign = result.uss.us4 & 0x8000;
    e16  = result.uss.us4 & 0x7fff;
    if (e16 > 0x43FE) {
      //errno = ERANGE;
      errno = 34;
      result.ulls.ull0 = 0;
      result.uss.us3 = sign | (0x7ff0);
    } else if (e16 > 0x3C00) {
        /* reminder: hidden not hidden 63-11 = 52 */
      result.ulls.ull0 = ((result.ulls.ull0 >> 11)
                          + ((result.uss.us0 & 0x07ff) > 0x0400));
      result.uss.us3 = (result.uss.us3 & 0x000f)
                        | sign | ((e16 - 0x3FFF + 0x3FF) << 4);
 #ifdef LEGACY_DENORMAL
    } else if (e16 > 0x3BCC) {
      int16_t shift = 0x3C00 - e16;
      uint32_t round;
      round = ((result.ulls.ull0
                & (0xffffffffffffffffULL >> (64 - (shift + 12))))
               > (0x8000000000000000ULL >> (64 - (shift + 12))));
      result.ulls.ull0 = (result.ulls.ull0 >> (shift + 12)) + (uint64_t)round;
      result.uss.us3 = (result.uss.us3 & 0x000f) | sign;
    } else {
      //errno = ERANGE;
      errno = 34;
      result.ulls.ull0 = 0;
      result.uss.us3 = sign;
 #else
    } else {
      if (e16 != 0x3C00)
        errno = ERANGE;
      result.ulls.ull0 = 0;
      result.uss.us3 = sign;
 #endif
    }
  }
  return *(double*)(wc = (unsigned char*)&result);
#elif (__LDBL_MANT_DIG__ == 113)
  uint32_t w160[5];
  ldtow(ldbl, w160);
  return wtod(w160);
#else
  #error: undefined mantissa digits
#endif
}



int
main(void) {
  phx_printf("%.43f\n", 0x1.52f8a8e32e982p-140);
  phx_printf("%g\n", 355.0/113.0);
  return 0;
}




^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed value is incorrectly rounded
  2021-11-05  2:54             ` Keith Packard
  2021-11-05 16:00               ` Steven Abner
@ 2021-11-08  9:57               ` Corinna Vinschen
  1 sibling, 0 replies; 25+ messages in thread
From: Corinna Vinschen @ 2021-11-08  9:57 UTC (permalink / raw)
  To: newlib

On Nov  4 19:54, Keith Packard wrote:
> Brian Inglis <Brian.Inglis@SystematicSw.ab.ca> writes:
> 
> > Keith,
> >
> > I believe the implementation uses tables: that could be an issue in the 
> > embedded world; can you comment on the table space required for 32, 64, 
> > 128 bits?
> 
> I don't have a long double implementation of the ryu code; 128 bit
> doubles would require 256 bit arithmetic (add/mul, fortunately no
> divide), and a bunch of analysis to generate the table values. The
> sample code on github only provides 32- and 64- bit
> implementations. Picolibc currently has an imprecise printf
> implementation for long double that works for Intel (80 bit) Risc-V
> (IEEE 128 bit) and Power PC ('double double' 128-bit).

We certainly need long double as well.  Are the aforementioned
implementations sufficient?  The current ldtoa is somewhat imprecise as
well for Intel, so maybe we're not worse off.

gdtoa might still be an option.


Corinna



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed value is incorrectly rounded
  2021-11-04 12:24   ` Corinna Vinschen
  2021-11-04 16:48     ` Keith Packard
@ 2021-11-28  7:43     ` Takashi Yano
  2021-11-28 12:38       ` Takashi Yano
  1 sibling, 1 reply; 25+ messages in thread
From: Takashi Yano @ 2021-11-28  7:43 UTC (permalink / raw)
  To: newlib

[-- Attachment #1: Type: text/plain, Size: 1289 bytes --]

On Thu, 4 Nov 2021 13:24:42 +0100
Corinna Vinschen wrote:
> However, a much better fix would be to switch to gdtoa, as the BSDs and
> Mingw64 do.

I have tried to import gdtoa into newlib from OpenBSD.

gdtoa seems to use malloc much, so it may not work in some of
platforms due to insufficient heap. Therefore, new ldtoa.c tries
gdtoa first and fallbacks to legacy ldtoa if gdtoa fails.

To import gdtoa to newlib, I did:
1) Create "machine/ieee.h" which conditionally defines ieee_ext
   structure and EXT_TO_ARRAY32() macro depend on architecture.
2) Create arith.h which reflects endian of architecture.
3) Merge gdtoa.h with OpenBSD's gdtoa.h. __BEGIN_HIDDEN_DECLS,
   __END_HIDDEN_DECLS, PROTO_NORMAL() and DEF_STRONG() are
   defined as dummy in this header.
4) Replace malloc()/free() with _malloc_r()/_free_r().
5) Implement ACQUIRE_DTOA_LOCK() and FREE_DTOA_LOCK() macros
   using "sys/lock.h" for multi-threading environment.
6) Remove inclusion of "gd_qnan.h" which is not used.

Please see attached patch for more details.

I confirmed this works nicely with cygwin. Moreover, it is much
faster than legacy ldtoa (more than 4 times faster).

However, this may break some other supported platforms.

Could anyone please check this?

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: 0001-ldtoa-Import-gdtoa-from-OpenBSD.patch --]
[-- Type: application/octet-stream, Size: 108421 bytes --]

From 374db2d68d2a768f792ac81ac0d231c477e96f89 Mon Sep 17 00:00:00 2001
From: Takashi Yano <takashi.yano@nifty.ne.jp>
Date: Sun, 28 Nov 2021 11:04:52 +0900
Subject: [PATCH] ldtoa: Import gdtoa from OpenBSD.

---
 newlib/libc/include/machine/ieee.h | 104 ++++
 newlib/libc/stdlib/Makefile.am     |  14 +-
 newlib/libc/stdlib/Makefile.in     |  82 ++-
 newlib/libc/stdlib/arith.h         |   9 +
 newlib/libc/stdlib/gdtoa-dmisc.c   | 225 +++++++
 newlib/libc/stdlib/gdtoa-dtoa.c    | 839 ++++++++++++++++++++++++++
 newlib/libc/stdlib/gdtoa-gdtoa.c   | 830 ++++++++++++++++++++++++++
 newlib/libc/stdlib/gdtoa-gmisc.c   |  86 +++
 newlib/libc/stdlib/gdtoa-ldtoa.c   | 124 ++++
 newlib/libc/stdlib/gdtoa-misc.c    | 912 +++++++++++++++++++++++++++++
 newlib/libc/stdlib/gdtoa.h         | 132 ++++-
 newlib/libc/stdlib/gdtoaimp.h      | 672 +++++++++++++++++++++
 newlib/libc/stdlib/ldtoa.c         |   7 +
 13 files changed, 4002 insertions(+), 34 deletions(-)
 create mode 100644 newlib/libc/include/machine/ieee.h
 create mode 100644 newlib/libc/stdlib/arith.h
 create mode 100644 newlib/libc/stdlib/gdtoa-dmisc.c
 create mode 100644 newlib/libc/stdlib/gdtoa-dtoa.c
 create mode 100644 newlib/libc/stdlib/gdtoa-gdtoa.c
 create mode 100644 newlib/libc/stdlib/gdtoa-gmisc.c
 create mode 100644 newlib/libc/stdlib/gdtoa-ldtoa.c
 create mode 100644 newlib/libc/stdlib/gdtoa-misc.c
 create mode 100644 newlib/libc/stdlib/gdtoaimp.h

diff --git a/newlib/libc/include/machine/ieee.h b/newlib/libc/include/machine/ieee.h
new file mode 100644
index 000000000..bba627a3b
--- /dev/null
+++ b/newlib/libc/include/machine/ieee.h
@@ -0,0 +1,104 @@
+#ifndef _MACHINE_IEEE_H_
+#define _MACHINE_IEEE_H_
+#include <sys/types.h>
+#include <sys/cdefs.h>
+#include <machine/ieeefp.h>
+#include <float.h>
+
+#if LDBL_MANT_DIG == 24
+#define EXT_IMPLICIT_NBIT
+#define EXT_TO_ARRAY32(p, a) do {      \
+    (a)[0] = (p)->ext_frac;  \
+} while (0)
+#ifdef __IEEE_LITTLE_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_frac:23;
+    uint32_t   ext_exp:8;
+    uint32_t   ext_sign:1;
+};
+#endif
+#ifdef __IEEE_BIG_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_sign:1;
+    uint32_t   ext_exp:8;
+    uint32_t   ext_frac:23;
+};
+#endif
+#elif LDBL_MANT_DIG == 53
+#define EXT_IMPLICIT_NBIT
+#define EXT_TO_ARRAY32(p, a) do {       \
+    (a)[0] = (p)->ext_fracl;  \
+    (a)[1] = (p)->ext_frach;  \
+} while (0)
+#ifdef __IEEE_LITTLE_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_fracl;
+    uint32_t   ext_frach:20;
+    uint32_t   ext_exp:11;
+    uint32_t   ext_sign:1;
+};
+#endif
+#ifdef __IEEE_BIG_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_sign:1;
+    uint32_t   ext_exp:11;
+    uint32_t   ext_frach:20;
+    uint32_t   ext_fracl;
+};
+#endif
+#elif LDBL_MANT_DIG == 64
+#define EXT_TO_ARRAY32(p, a) do {       \
+    (a)[0] = (p)->ext_fracl;  \
+    (a)[1] = (p)->ext_frach;  \
+} while (0)
+#ifdef __IEEE_LITTLE_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_fracl;
+    uint32_t   ext_frach;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_sign:1;
+    uint32_t   ext_padl:16;
+    uint32_t   ext_padh;
+};
+#endif
+#ifdef __IEEE_BIG_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_padh;
+    uint32_t   ext_padl:16;
+    uint32_t   ext_sign:1;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_frach;
+    uint32_t   ext_fracl;
+};
+#endif
+#elif LDBL_MANT_DIG == 113
+#define EXT_IMPLICIT_NBIT
+#define EXT_TO_ARRAY32(p, a) do {        \
+    (a)[0] = (p)->ext_fracl;   \
+    (a)[1] = (p)->ext_fraclm;  \
+    (a)[2] = (p)->ext_frachm;  \
+    (a)[3] = (p)->ext_frach;   \
+} while (0)
+#ifdef __IEEE_LITTLE_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_fracl;
+    uint32_t   ext_fraclm;
+    uint32_t   ext_frachm;
+    uint32_t   ext_frach:16;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_sign:1;
+};
+#endif
+#ifdef __IEEE_BIG_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_sign:1;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_frach:16;
+    uint32_t   ext_frachm;
+    uint32_t   ext_fraclm;
+    uint32_t   ext_fracl;
+};
+#endif
+#endif
+
+#endif /* _MACHINE_IEEE_H_ */
diff --git a/newlib/libc/stdlib/Makefile.am b/newlib/libc/stdlib/Makefile.am
index 357e37beb..04b22d477 100644
--- a/newlib/libc/stdlib/Makefile.am
+++ b/newlib/libc/stdlib/Makefile.am
@@ -38,6 +38,12 @@ GENERAL_SOURCES = \
 	labs.c 		\
 	ldiv.c  	\
 	ldtoa.c		\
+	gdtoa-ldtoa.c	\
+	gdtoa-gdtoa.c	\
+	gdtoa-dtoa.c	\
+	gdtoa-misc.c	\
+	gdtoa-dmisc.c	\
+	gdtoa-gmisc.c	\
 	malloc.c  	\
 	mblen.c		\
 	mblen_r.c	\
@@ -311,7 +317,13 @@ CHEWOUT_FILES= \
 CHAPTERS = stdlib.tex
 
 $(lpfx)dtoa.$(oext): dtoa.c mprec.h
-$(lpfx)ldtoa.$(oext): ldtoa.c mprec.h
+$(lpfx)ldtoa.$(oext): ldtoa.c mprec.h gdtoa.h
+$(lpfx)gdtoa-ldtoa.$(oext): gdtoa-ldtoa.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-gdtoa.$(oext): gdtoa-gdtoa.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-dtoa.$(oext): gdtoa-dtoa.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-misc.$(oext): gdtoa-misc.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-dmisc.$(oext): gdtoa-dmisc.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-gmisc.$(oext): gdtoa-gmisc.c gdtoaimp.h gdtoa.h arith.h
 $(lpfx)ecvtbuf.$(oext): ecvtbuf.c mprec.h
 $(lpfx)mbtowc_r.$(oext): mbtowc_r.c mbctype.h
 $(lpfx)mprec.$(oext): mprec.c mprec.h
diff --git a/newlib/libc/stdlib/Makefile.in b/newlib/libc/stdlib/Makefile.in
index a812b6a95..4e891ced9 100644
--- a/newlib/libc/stdlib/Makefile.in
+++ b/newlib/libc/stdlib/Makefile.in
@@ -101,7 +101,10 @@ am__objects_2 = lib_a-__adjust.$(OBJEXT) lib_a-__atexit.$(OBJEXT) \
 	lib_a-getenv_r.$(OBJEXT) lib_a-imaxabs.$(OBJEXT) \
 	lib_a-imaxdiv.$(OBJEXT) lib_a-itoa.$(OBJEXT) \
 	lib_a-labs.$(OBJEXT) lib_a-ldiv.$(OBJEXT) \
-	lib_a-ldtoa.$(OBJEXT) lib_a-malloc.$(OBJEXT) \
+	lib_a-ldtoa.$(OBJEXT) lib_a-gdtoa-ldtoa.$(OBJEXT) \
+	lib_a-gdtoa-gdtoa.$(OBJEXT) lib_a-gdtoa-dtoa.$(OBJEXT) \
+	lib_a-gdtoa-misc.$(OBJEXT) lib_a-gdtoa-dmisc.$(OBJEXT) \
+	lib_a-gdtoa-gmisc.$(OBJEXT) lib_a-malloc.$(OBJEXT) \
 	lib_a-mblen.$(OBJEXT) lib_a-mblen_r.$(OBJEXT) \
 	lib_a-mbstowcs.$(OBJEXT) lib_a-mbstowcs_r.$(OBJEXT) \
 	lib_a-mbtowc.$(OBJEXT) lib_a-mbtowc_r.$(OBJEXT) \
@@ -165,14 +168,15 @@ am__objects_9 = __adjust.lo __atexit.lo __call_atexit.lo __exp10.lo \
 	div.lo dtoa.lo dtoastub.lo environ.lo envlock.lo eprintf.lo \
 	exit.lo gdtoa-gethex.lo gdtoa-hexnan.lo getenv.lo getenv_r.lo \
 	imaxabs.lo imaxdiv.lo itoa.lo labs.lo ldiv.lo ldtoa.lo \
-	malloc.lo mblen.lo mblen_r.lo mbstowcs.lo mbstowcs_r.lo \
-	mbtowc.lo mbtowc_r.lo mlock.lo mprec.lo mstats.lo \
-	on_exit_args.lo quick_exit.lo rand.lo rand_r.lo random.lo \
-	realloc.lo reallocarray.lo reallocf.lo sb_charsets.lo \
-	strtod.lo strtoimax.lo strtol.lo strtoul.lo strtoumax.lo \
-	utoa.lo wcstod.lo wcstoimax.lo wcstol.lo wcstoul.lo \
-	wcstoumax.lo wcstombs.lo wcstombs_r.lo wctomb.lo wctomb_r.lo \
-	$(am__objects_8)
+	gdtoa-ldtoa.lo gdtoa-gdtoa.lo gdtoa-dtoa.lo gdtoa-misc.lo \
+	gdtoa-dmisc.lo gdtoa-gmisc.lo malloc.lo mblen.lo mblen_r.lo \
+	mbstowcs.lo mbstowcs_r.lo mbtowc.lo mbtowc_r.lo mlock.lo \
+	mprec.lo mstats.lo on_exit_args.lo quick_exit.lo rand.lo \
+	rand_r.lo random.lo realloc.lo reallocarray.lo reallocf.lo \
+	sb_charsets.lo strtod.lo strtoimax.lo strtol.lo strtoul.lo \
+	strtoumax.lo utoa.lo wcstod.lo wcstoimax.lo wcstol.lo \
+	wcstoul.lo wcstoumax.lo wcstombs.lo wcstombs_r.lo wctomb.lo \
+	wctomb_r.lo $(am__objects_8)
 am__objects_10 = arc4random.lo arc4random_uniform.lo cxa_atexit.lo \
 	cxa_finalize.lo drand48.lo ecvtbuf.lo efgcvt.lo erand48.lo \
 	jrand48.lo lcong48.lo lrand48.lo mrand48.lo msize.lo mtrim.lo \
@@ -354,6 +358,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 shared_machine_dir = @shared_machine_dir@
 sharedstatedir = @sharedstatedir@
@@ -372,13 +377,14 @@ GENERAL_SOURCES = __adjust.c __atexit.c __call_atexit.c __exp10.c \
 	atexit.c atof.c atoff.c atoi.c atol.c calloc.c div.c dtoa.c \
 	dtoastub.c environ.c envlock.c eprintf.c exit.c gdtoa-gethex.c \
 	gdtoa-hexnan.c getenv.c getenv_r.c imaxabs.c imaxdiv.c itoa.c \
-	labs.c ldiv.c ldtoa.c malloc.c mblen.c mblen_r.c mbstowcs.c \
-	mbstowcs_r.c mbtowc.c mbtowc_r.c mlock.c mprec.c mstats.c \
-	on_exit_args.c quick_exit.c rand.c rand_r.c random.c realloc.c \
-	reallocarray.c reallocf.c sb_charsets.c strtod.c strtoimax.c \
-	strtol.c strtoul.c strtoumax.c utoa.c wcstod.c wcstoimax.c \
-	wcstol.c wcstoul.c wcstoumax.c wcstombs.c wcstombs_r.c \
-	wctomb.c wctomb_r.c $(am__append_1)
+	labs.c ldiv.c ldtoa.c gdtoa-ldtoa.c gdtoa-gdtoa.c gdtoa-dtoa.c \
+	gdtoa-misc.c gdtoa-dmisc.c gdtoa-gmisc.c malloc.c mblen.c \
+	mblen_r.c mbstowcs.c mbstowcs_r.c mbtowc.c mbtowc_r.c mlock.c \
+	mprec.c mstats.c on_exit_args.c quick_exit.c rand.c rand_r.c \
+	random.c realloc.c reallocarray.c reallocf.c sb_charsets.c \
+	strtod.c strtoimax.c strtol.c strtoul.c strtoumax.c utoa.c \
+	wcstod.c wcstoimax.c wcstol.c wcstoul.c wcstoumax.c wcstombs.c \
+	wcstombs_r.c wctomb.c wctomb_r.c $(am__append_1)
 @NEWLIB_NANO_MALLOC_FALSE@MALIGNR = malignr
 @NEWLIB_NANO_MALLOC_TRUE@MALIGNR = nano-malignr
 @NEWLIB_NANO_MALLOC_FALSE@MALLOPTR = malloptr
@@ -827,6 +833,42 @@ lib_a-ldtoa.o: ldtoa.c
 lib_a-ldtoa.obj: ldtoa.c
 	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-ldtoa.obj `if test -f 'ldtoa.c'; then $(CYGPATH_W) 'ldtoa.c'; else $(CYGPATH_W) '$(srcdir)/ldtoa.c'; fi`
 
+lib_a-gdtoa-ldtoa.o: gdtoa-ldtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-ldtoa.o `test -f 'gdtoa-ldtoa.c' || echo '$(srcdir)/'`gdtoa-ldtoa.c
+
+lib_a-gdtoa-ldtoa.obj: gdtoa-ldtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-ldtoa.obj `if test -f 'gdtoa-ldtoa.c'; then $(CYGPATH_W) 'gdtoa-ldtoa.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-ldtoa.c'; fi`
+
+lib_a-gdtoa-gdtoa.o: gdtoa-gdtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-gdtoa.o `test -f 'gdtoa-gdtoa.c' || echo '$(srcdir)/'`gdtoa-gdtoa.c
+
+lib_a-gdtoa-gdtoa.obj: gdtoa-gdtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-gdtoa.obj `if test -f 'gdtoa-gdtoa.c'; then $(CYGPATH_W) 'gdtoa-gdtoa.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-gdtoa.c'; fi`
+
+lib_a-gdtoa-dtoa.o: gdtoa-dtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-dtoa.o `test -f 'gdtoa-dtoa.c' || echo '$(srcdir)/'`gdtoa-dtoa.c
+
+lib_a-gdtoa-dtoa.obj: gdtoa-dtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-dtoa.obj `if test -f 'gdtoa-dtoa.c'; then $(CYGPATH_W) 'gdtoa-dtoa.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-dtoa.c'; fi`
+
+lib_a-gdtoa-misc.o: gdtoa-misc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-misc.o `test -f 'gdtoa-misc.c' || echo '$(srcdir)/'`gdtoa-misc.c
+
+lib_a-gdtoa-misc.obj: gdtoa-misc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-misc.obj `if test -f 'gdtoa-misc.c'; then $(CYGPATH_W) 'gdtoa-misc.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-misc.c'; fi`
+
+lib_a-gdtoa-dmisc.o: gdtoa-dmisc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-dmisc.o `test -f 'gdtoa-dmisc.c' || echo '$(srcdir)/'`gdtoa-dmisc.c
+
+lib_a-gdtoa-dmisc.obj: gdtoa-dmisc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-dmisc.obj `if test -f 'gdtoa-dmisc.c'; then $(CYGPATH_W) 'gdtoa-dmisc.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-dmisc.c'; fi`
+
+lib_a-gdtoa-gmisc.o: gdtoa-gmisc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-gmisc.o `test -f 'gdtoa-gmisc.c' || echo '$(srcdir)/'`gdtoa-gmisc.c
+
+lib_a-gdtoa-gmisc.obj: gdtoa-gmisc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-gmisc.obj `if test -f 'gdtoa-gmisc.c'; then $(CYGPATH_W) 'gdtoa-gmisc.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-gmisc.c'; fi`
+
 lib_a-malloc.o: malloc.c
 	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-malloc.o `test -f 'malloc.c' || echo '$(srcdir)/'`malloc.c
 
@@ -1610,7 +1652,13 @@ $(lpfx)$(MALLOPTR).$(oext): $(MALLOCR).c
 	$(MALLOC_COMPILE) -DDEFINE_MALLOPT -c $(srcdir)/$(MALLOCR).c -o $@
 
 $(lpfx)dtoa.$(oext): dtoa.c mprec.h
-$(lpfx)ldtoa.$(oext): ldtoa.c mprec.h
+$(lpfx)ldtoa.$(oext): ldtoa.c mprec.h gdtoa.h
+$(lpfx)gdtoa-ldtoa.$(oext): gdtoa-ldtoa.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-gdtoa.$(oext): gdtoa-gdtoa.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-dtoa.$(oext): gdtoa-dtoa.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-misc.$(oext): gdtoa-misc.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-dmisc.$(oext): gdtoa-dmisc.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-gmisc.$(oext): gdtoa-gmisc.c gdtoaimp.h gdtoa.h arith.h
 $(lpfx)ecvtbuf.$(oext): ecvtbuf.c mprec.h
 $(lpfx)mbtowc_r.$(oext): mbtowc_r.c mbctype.h
 $(lpfx)mprec.$(oext): mprec.c mprec.h
diff --git a/newlib/libc/stdlib/arith.h b/newlib/libc/stdlib/arith.h
new file mode 100644
index 000000000..d3b84d867
--- /dev/null
+++ b/newlib/libc/stdlib/arith.h
@@ -0,0 +1,9 @@
+#include <machine/ieeefp.h>
+
+#ifdef __IEEE_LITTLE_ENDIAN
+#define IEEE_8087
+#endif
+
+#ifdef __IEEE_BIG_ENDIAN
+#define IEEE_MC68k
+#endif
diff --git a/newlib/libc/stdlib/gdtoa-dmisc.c b/newlib/libc/stdlib/gdtoa-dmisc.c
new file mode 100644
index 000000000..f3d8ea71a
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-dmisc.c
@@ -0,0 +1,225 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include "gdtoaimp.h"
+
+#ifndef MULTIPLE_THREADS
+ char *dtoa_result;
+#endif
+
+ char *
+#ifdef KR_headers
+rv_alloc(i) int i;
+#else
+rv_alloc(int i)
+#endif
+{
+	int j, k, *r;
+
+	j = sizeof(ULong);
+	for(k = 0;
+		sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i;
+		j <<= 1)
+			k++;
+	r = (int*)Balloc(k);
+	if (r == NULL)
+		return (
+#ifndef MULTIPLE_THREADS
+		dtoa_result =
+#endif
+			NULL);
+	*r = k;
+	return
+#ifndef MULTIPLE_THREADS
+	dtoa_result =
+#endif
+		(char *)(r+1);
+	}
+
+ char *
+#ifdef KR_headers
+nrv_alloc(s, rve, n) char *s, **rve; int n;
+#else
+nrv_alloc(char *s, char **rve, int n)
+#endif
+{
+	char *rv, *t;
+
+	t = rv = rv_alloc(n);
+	if (t == NULL)
+		return (NULL);
+	while((*t = *s++) !=0)
+		t++;
+	if (rve)
+		*rve = t;
+	return rv;
+	}
+
+/* freedtoa(s) must be used to free values s returned by dtoa
+ * when MULTIPLE_THREADS is #defined.  It should be used in all cases,
+ * but for consistency with earlier versions of dtoa, it is optional
+ * when MULTIPLE_THREADS is not defined.
+ */
+
+ void
+#ifdef KR_headers
+freedtoa(s) char *s;
+#else
+freedtoa(char *s)
+#endif
+{
+	Bigint *b = (Bigint *)((int *)s - 1);
+	b->maxwds = 1 << (b->k = *(int*)b);
+	Bfree(b);
+#ifndef MULTIPLE_THREADS
+	if (s == dtoa_result)
+		dtoa_result = 0;
+#endif
+	}
+DEF_STRONG(freedtoa);
+
+ int
+quorem
+#ifdef KR_headers
+	(b, S) Bigint *b, *S;
+#else
+	(Bigint *b, Bigint *S)
+#endif
+{
+	int n;
+	ULong *bx, *bxe, q, *sx, *sxe;
+#ifdef ULLong
+	ULLong borrow, carry, y, ys;
+#else
+	ULong borrow, carry, y, ys;
+#ifdef Pack_32
+	ULong si, z, zs;
+#endif
+#endif
+
+	n = S->wds;
+#ifdef DEBUG
+	/*debug*/ if (b->wds > n)
+	/*debug*/	Bug("oversize b in quorem");
+#endif
+	if (b->wds < n)
+		return 0;
+	sx = S->x;
+	sxe = sx + --n;
+	bx = b->x;
+	bxe = bx + n;
+	q = *bxe / (*sxe + 1);	/* ensure q <= true quotient */
+#ifdef DEBUG
+	/*debug*/ if (q > 9)
+	/*debug*/	Bug("oversized quotient in quorem");
+#endif
+	if (q) {
+		borrow = 0;
+		carry = 0;
+		do {
+#ifdef ULLong
+			ys = *sx++ * (ULLong)q + carry;
+			carry = ys >> 32;
+			y = *bx - (ys & 0xffffffffUL) - borrow;
+			borrow = y >> 32 & 1UL;
+			*bx++ = y & 0xffffffffUL;
+#else
+#ifdef Pack_32
+			si = *sx++;
+			ys = (si & 0xffff) * q + carry;
+			zs = (si >> 16) * q + (ys >> 16);
+			carry = zs >> 16;
+			y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			z = (*bx >> 16) - (zs & 0xffff) - borrow;
+			borrow = (z & 0x10000) >> 16;
+			Storeinc(bx, z, y);
+#else
+			ys = *sx++ * q + carry;
+			carry = ys >> 16;
+			y = *bx - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			*bx++ = y & 0xffff;
+#endif
+#endif
+			}
+			while(sx <= sxe);
+		if (!*bxe) {
+			bx = b->x;
+			while(--bxe > bx && !*bxe)
+				--n;
+			b->wds = n;
+			}
+		}
+	if (cmp(b, S) >= 0) {
+		q++;
+		borrow = 0;
+		carry = 0;
+		bx = b->x;
+		sx = S->x;
+		do {
+#ifdef ULLong
+			ys = *sx++ + carry;
+			carry = ys >> 32;
+			y = *bx - (ys & 0xffffffffUL) - borrow;
+			borrow = y >> 32 & 1UL;
+			*bx++ = y & 0xffffffffUL;
+#else
+#ifdef Pack_32
+			si = *sx++;
+			ys = (si & 0xffff) + carry;
+			zs = (si >> 16) + (ys >> 16);
+			carry = zs >> 16;
+			y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			z = (*bx >> 16) - (zs & 0xffff) - borrow;
+			borrow = (z & 0x10000) >> 16;
+			Storeinc(bx, z, y);
+#else
+			ys = *sx++ + carry;
+			carry = ys >> 16;
+			y = *bx - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			*bx++ = y & 0xffff;
+#endif
+#endif
+			}
+			while(sx <= sxe);
+		bx = b->x;
+		bxe = bx + n;
+		if (!*bxe) {
+			while(--bxe > bx && !*bxe)
+				--n;
+			b->wds = n;
+			}
+		}
+	return q;
+	}
diff --git a/newlib/libc/stdlib/gdtoa-dtoa.c b/newlib/libc/stdlib/gdtoa-dtoa.c
new file mode 100644
index 000000000..998192764
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-dtoa.c
@@ -0,0 +1,839 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998, 1999 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include "gdtoaimp.h"
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ *	1. Rather than iterating, we use a simple numeric overestimate
+ *	   to determine k = floor(log10(d)).  We scale relevant
+ *	   quantities using O(log2(k)) rather than O(k) multiplications.
+ *	2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ *	   try to generate digits strictly left to right.  Instead, we
+ *	   compute with fewer bits and propagate the carry if necessary
+ *	   when rounding the final digit up.  This is often faster.
+ *	3. Under the assumption that input will be rounded nearest,
+ *	   mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ *	   That is, we allow equality in stopping tests when the
+ *	   round-nearest rule will give the same floating-point value
+ *	   as would satisfaction of the stopping test with strict
+ *	   inequality.
+ *	4. We remove common factors of powers of 2 from relevant
+ *	   quantities.
+ *	5. When converting floating-point integers less than 1e16,
+ *	   we use floating-point arithmetic rather than resorting
+ *	   to multiple-precision integers.
+ *	6. When asked to produce fewer than 15 digits, we first try
+ *	   to get by with floating-point arithmetic; we resort to
+ *	   multiple-precision integer arithmetic only if we cannot
+ *	   guarantee that the floating-point calculation has given
+ *	   the correctly rounded result.  For k requested digits and
+ *	   "uniformly" distributed input, the probability is
+ *	   something like 10^(k-15) that we must resort to the Long
+ *	   calculation.
+ */
+
+#ifdef Honor_FLT_ROUNDS
+#undef Check_FLT_ROUNDS
+#define Check_FLT_ROUNDS
+#else
+#define Rounding Flt_Rounds
+#endif
+
+ char *
+dtoa
+#ifdef KR_headers
+	(d0, mode, ndigits, decpt, sign, rve)
+	double d0; int mode, ndigits, *decpt, *sign; char **rve;
+#else
+	(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
+#endif
+{
+ /*	Arguments ndigits, decpt, sign are similar to those
+	of ecvt and fcvt; trailing zeros are suppressed from
+	the returned string.  If not null, *rve is set to point
+	to the end of the return value.  If d is +-Infinity or NaN,
+	then *decpt is set to 9999.
+
+	mode:
+		0 ==> shortest string that yields d when read in
+			and rounded to nearest.
+		1 ==> like 0, but with Steele & White stopping rule;
+			e.g. with IEEE P754 arithmetic , mode 0 gives
+			1e23 whereas mode 1 gives 9.999999999999999e22.
+		2 ==> max(1,ndigits) significant digits.  This gives a
+			return value similar to that of ecvt, except
+			that trailing zeros are suppressed.
+		3 ==> through ndigits past the decimal point.  This
+			gives a return value similar to that from fcvt,
+			except that trailing zeros are suppressed, and
+			ndigits can be negative.
+		4,5 ==> similar to 2 and 3, respectively, but (in
+			round-nearest mode) with the tests of mode 0 to
+			possibly return a shorter string that rounds to d.
+			With IEEE arithmetic and compilation with
+			-DHonor_FLT_ROUNDS, modes 4 and 5 behave the same
+			as modes 2 and 3 when FLT_ROUNDS != 1.
+		6-9 ==> Debugging modes similar to mode - 4:  don't try
+			fast floating-point estimate (if applicable).
+
+		Values of mode other than 0-9 are treated as mode 0.
+
+		Sufficient space is allocated to the return value
+		to hold the suppressed trailing zeros.
+	*/
+
+	int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,
+		j, j1, k, k0, k_check, leftright, m2, m5, s2, s5,
+		spec_case, try_quick;
+	Long L;
+#ifndef Sudden_Underflow
+	int denorm;
+	ULong x;
+#endif
+	Bigint *b, *b1, *delta, *mlo, *mhi, *S;
+	U d, d2, eps;
+	double ds;
+	char *s, *s0;
+#ifdef SET_INEXACT
+	int inexact, oldinexact;
+#endif
+#ifdef Honor_FLT_ROUNDS /*{*/
+	int Rounding;
+#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */
+	Rounding = Flt_Rounds;
+#else /*}{*/
+	Rounding = 1;
+	switch(fegetround()) {
+	  case FE_TOWARDZERO:	Rounding = 0; break;
+	  case FE_UPWARD:	Rounding = 2; break;
+	  case FE_DOWNWARD:	Rounding = 3;
+	  }
+#endif /*}}*/
+#endif /*}*/
+
+#ifndef MULTIPLE_THREADS
+	if (dtoa_result) {
+		freedtoa(dtoa_result);
+		dtoa_result = 0;
+		}
+#endif
+	d.d = d0;
+	if (word0(&d) & Sign_bit) {
+		/* set sign for everything, including 0's and NaNs */
+		*sign = 1;
+		word0(&d) &= ~Sign_bit;	/* clear sign bit */
+		}
+	else
+		*sign = 0;
+
+#if defined(IEEE_Arith) + defined(VAX)
+#ifdef IEEE_Arith
+	if ((word0(&d) & Exp_mask) == Exp_mask)
+#else
+	if (word0(&d)  == 0x8000)
+#endif
+		{
+		/* Infinity or NaN */
+		*decpt = 9999;
+#ifdef IEEE_Arith
+		if (!word1(&d) && !(word0(&d) & 0xfffff))
+			return nrv_alloc("Infinity", rve, 8);
+#endif
+		return nrv_alloc("NaN", rve, 3);
+		}
+#endif
+#ifdef IBM
+	dval(&d) += 0; /* normalize */
+#endif
+	if (!dval(&d)) {
+		*decpt = 1;
+		return nrv_alloc("0", rve, 1);
+		}
+
+#ifdef SET_INEXACT
+	try_quick = oldinexact = get_inexact();
+	inexact = 1;
+#endif
+#ifdef Honor_FLT_ROUNDS
+	if (Rounding >= 2) {
+		if (*sign)
+			Rounding = Rounding == 2 ? 0 : 2;
+		else
+			if (Rounding != 2)
+				Rounding = 0;
+		}
+#endif
+
+	b = d2b(dval(&d), &be, &bbits);
+	if (b == NULL)
+		return (NULL);
+#ifdef Sudden_Underflow
+	i = (int)(word0(&d) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
+#else
+	if (( i = (int)(word0(&d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)) )!=0) {
+#endif
+		dval(&d2) = dval(&d);
+		word0(&d2) &= Frac_mask1;
+		word0(&d2) |= Exp_11;
+#ifdef IBM
+		if (( j = 11 - hi0bits(word0(&d2) & Frac_mask) )!=0)
+			dval(&d2) /= 1 << j;
+#endif
+
+		/* log(x)	~=~ log(1.5) + (x-1.5)/1.5
+		 * log10(x)	 =  log(x) / log(10)
+		 *		~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+		 * log10(&d) = (i-Bias)*log(2)/log(10) + log10(&d2)
+		 *
+		 * This suggests computing an approximation k to log10(&d) by
+		 *
+		 * k = (i - Bias)*0.301029995663981
+		 *	+ ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+		 *
+		 * We want k to be too large rather than too small.
+		 * The error in the first-order Taylor series approximation
+		 * is in our favor, so we just round up the constant enough
+		 * to compensate for any error in the multiplication of
+		 * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+		 * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+		 * adding 1e-13 to the constant term more than suffices.
+		 * Hence we adjust the constant term to 0.1760912590558.
+		 * (We could get a more accurate k by invoking log10,
+		 *  but this is probably not worthwhile.)
+		 */
+
+		i -= Bias;
+#ifdef IBM
+		i <<= 2;
+		i += j;
+#endif
+#ifndef Sudden_Underflow
+		denorm = 0;
+		}
+	else {
+		/* d is denormalized */
+
+		i = bbits + be + (Bias + (P-1) - 1);
+		x = i > 32  ? word0(&d) << (64 - i) | word1(&d) >> (i - 32)
+			    : word1(&d) << (32 - i);
+		dval(&d2) = x;
+		word0(&d2) -= 31*Exp_msk1; /* adjust exponent */
+		i -= (Bias + (P-1) - 1) + 1;
+		denorm = 1;
+		}
+#endif
+	ds = (dval(&d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
+	k = (int)ds;
+	if (ds < 0. && ds != k)
+		k--;	/* want k = floor(ds) */
+	k_check = 1;
+	if (k >= 0 && k <= Ten_pmax) {
+		if (dval(&d) < tens[k])
+			k--;
+		k_check = 0;
+		}
+	j = bbits - i - 1;
+	if (j >= 0) {
+		b2 = 0;
+		s2 = j;
+		}
+	else {
+		b2 = -j;
+		s2 = 0;
+		}
+	if (k >= 0) {
+		b5 = 0;
+		s5 = k;
+		s2 += k;
+		}
+	else {
+		b2 -= k;
+		b5 = -k;
+		s5 = 0;
+		}
+	if (mode < 0 || mode > 9)
+		mode = 0;
+
+#ifndef SET_INEXACT
+#ifdef Check_FLT_ROUNDS
+	try_quick = Rounding == 1;
+#else
+	try_quick = 1;
+#endif
+#endif /*SET_INEXACT*/
+
+	if (mode > 5) {
+		mode -= 4;
+		try_quick = 0;
+		}
+	leftright = 1;
+	ilim = ilim1 = -1;	/* Values for cases 0 and 1; done here to */
+				/* silence erroneous "gcc -Wall" warning. */
+	switch(mode) {
+		case 0:
+		case 1:
+			i = 18;
+			ndigits = 0;
+			break;
+		case 2:
+			leftright = 0;
+			/* no break */
+		case 4:
+			if (ndigits <= 0)
+				ndigits = 1;
+			ilim = ilim1 = i = ndigits;
+			break;
+		case 3:
+			leftright = 0;
+			/* no break */
+		case 5:
+			i = ndigits + k + 1;
+			ilim = i;
+			ilim1 = i - 1;
+			if (i <= 0)
+				i = 1;
+		}
+	s = s0 = rv_alloc(i);
+	if (s == NULL)
+		return (NULL);
+
+#ifdef Honor_FLT_ROUNDS
+	if (mode > 1 && Rounding != 1)
+		leftright = 0;
+#endif
+
+	if (ilim >= 0 && ilim <= Quick_max && try_quick) {
+
+		/* Try to get by with floating-point arithmetic. */
+
+		i = 0;
+		dval(&d2) = dval(&d);
+		k0 = k;
+		ilim0 = ilim;
+		ieps = 2; /* conservative */
+		if (k > 0) {
+			ds = tens[k&0xf];
+			j = k >> 4;
+			if (j & Bletch) {
+				/* prevent overflows */
+				j &= Bletch - 1;
+				dval(&d) /= bigtens[n_bigtens-1];
+				ieps++;
+				}
+			for(; j; j >>= 1, i++)
+				if (j & 1) {
+					ieps++;
+					ds *= bigtens[i];
+					}
+			dval(&d) /= ds;
+			}
+		else if (( j1 = -k )!=0) {
+			dval(&d) *= tens[j1 & 0xf];
+			for(j = j1 >> 4; j; j >>= 1, i++)
+				if (j & 1) {
+					ieps++;
+					dval(&d) *= bigtens[i];
+					}
+			}
+		if (k_check && dval(&d) < 1. && ilim > 0) {
+			if (ilim1 <= 0)
+				goto fast_failed;
+			ilim = ilim1;
+			k--;
+			dval(&d) *= 10.;
+			ieps++;
+			}
+		dval(&eps) = ieps*dval(&d) + 7.;
+		word0(&eps) -= (P-1)*Exp_msk1;
+		if (ilim == 0) {
+			S = mhi = 0;
+			dval(&d) -= 5.;
+			if (dval(&d) > dval(&eps))
+				goto one_digit;
+			if (dval(&d) < -dval(&eps))
+				goto no_digits;
+			goto fast_failed;
+			}
+#ifndef No_leftright
+		if (leftright) {
+			/* Use Steele & White method of only
+			 * generating digits needed.
+			 */
+			dval(&eps) = 0.5/tens[ilim-1] - dval(&eps);
+			for(i = 0;;) {
+				L = dval(&d);
+				dval(&d) -= L;
+				*s++ = '0' + (int)L;
+				if (dval(&d) < dval(&eps))
+					goto ret1;
+				if (1. - dval(&d) < dval(&eps))
+					goto bump_up;
+				if (++i >= ilim)
+					break;
+				dval(&eps) *= 10.;
+				dval(&d) *= 10.;
+				}
+			}
+		else {
+#endif
+			/* Generate ilim digits, then fix them up. */
+			dval(&eps) *= tens[ilim-1];
+			for(i = 1;; i++, dval(&d) *= 10.) {
+				L = (Long)(dval(&d));
+				if (!(dval(&d) -= L))
+					ilim = i;
+				*s++ = '0' + (int)L;
+				if (i == ilim) {
+					if (dval(&d) > 0.5 + dval(&eps))
+						goto bump_up;
+					else if (dval(&d) < 0.5 - dval(&eps)) {
+						while(*--s == '0');
+						s++;
+						goto ret1;
+						}
+					break;
+					}
+				}
+#ifndef No_leftright
+			}
+#endif
+ fast_failed:
+		s = s0;
+		dval(&d) = dval(&d2);
+		k = k0;
+		ilim = ilim0;
+		}
+
+	/* Do we have a "small" integer? */
+
+	if (be >= 0 && k <= Int_max) {
+		/* Yes. */
+		ds = tens[k];
+		if (ndigits < 0 && ilim <= 0) {
+			S = mhi = 0;
+			if (ilim < 0 || dval(&d) <= 5*ds)
+				goto no_digits;
+			goto one_digit;
+			}
+		for(i = 1;; i++, dval(&d) *= 10.) {
+			L = (Long)(dval(&d) / ds);
+			dval(&d) -= L*ds;
+#ifdef Check_FLT_ROUNDS
+			/* If FLT_ROUNDS == 2, L will usually be high by 1 */
+			if (dval(&d) < 0) {
+				L--;
+				dval(&d) += ds;
+				}
+#endif
+			*s++ = '0' + (int)L;
+			if (!dval(&d)) {
+#ifdef SET_INEXACT
+				inexact = 0;
+#endif
+				break;
+				}
+			if (i == ilim) {
+#ifdef Honor_FLT_ROUNDS
+				if (mode > 1)
+				switch(Rounding) {
+				  case 0: goto ret1;
+				  case 2: goto bump_up;
+				  }
+#endif
+				dval(&d) += dval(&d);
+#ifdef ROUND_BIASED
+				if (dval(&d) >= ds)
+#else
+				if (dval(&d) > ds || (dval(&d) == ds && L & 1))
+#endif
+					{
+ bump_up:
+					while(*--s == '9')
+						if (s == s0) {
+							k++;
+							*s = '0';
+							break;
+							}
+					++*s++;
+					}
+				break;
+				}
+			}
+		goto ret1;
+		}
+
+	m2 = b2;
+	m5 = b5;
+	mhi = mlo = 0;
+	if (leftright) {
+		i =
+#ifndef Sudden_Underflow
+			denorm ? be + (Bias + (P-1) - 1 + 1) :
+#endif
+#ifdef IBM
+			1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3);
+#else
+			1 + P - bbits;
+#endif
+		b2 += i;
+		s2 += i;
+		mhi = i2b(1);
+		if (mhi == NULL)
+			return (NULL);
+		}
+	if (m2 > 0 && s2 > 0) {
+		i = m2 < s2 ? m2 : s2;
+		b2 -= i;
+		m2 -= i;
+		s2 -= i;
+		}
+	if (b5 > 0) {
+		if (leftright) {
+			if (m5 > 0) {
+				mhi = pow5mult(mhi, m5);
+				if (mhi == NULL)
+					return (NULL);
+				b1 = mult(mhi, b);
+				if (b1 == NULL)
+					return (NULL);
+				Bfree(b);
+				b = b1;
+				}
+			if (( j = b5 - m5 )!=0) {
+				b = pow5mult(b, j);
+				if (b == NULL)
+					return (NULL);
+				}
+			}
+		else {
+			b = pow5mult(b, b5);
+			if (b == NULL)
+				return (NULL);
+			}
+		}
+	S = i2b(1);
+	if (S == NULL)
+		return (NULL);
+	if (s5 > 0) {
+		S = pow5mult(S, s5);
+		if (S == NULL)
+			return (NULL);
+		}
+
+	/* Check for special case that d is a normalized power of 2. */
+
+	spec_case = 0;
+	if ((mode < 2 || leftright)
+#ifdef Honor_FLT_ROUNDS
+			&& Rounding == 1
+#endif
+				) {
+		if (!word1(&d) && !(word0(&d) & Bndry_mask)
+#ifndef Sudden_Underflow
+		 && word0(&d) & (Exp_mask & ~Exp_msk1)
+#endif
+				) {
+			/* The special case */
+			b2 += Log2P;
+			s2 += Log2P;
+			spec_case = 1;
+			}
+		}
+
+	/* Arrange for convenient computation of quotients:
+	 * shift left if necessary so divisor has 4 leading 0 bits.
+	 *
+	 * Perhaps we should just compute leading 28 bits of S once
+	 * and for all and pass them and a shift to quorem, so it
+	 * can do shifts and ors to compute the numerator for q.
+	 */
+#ifdef Pack_32
+	if (( i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f )!=0)
+		i = 32 - i;
+#else
+	if (( i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf )!=0)
+		i = 16 - i;
+#endif
+	if (i > 4) {
+		i -= 4;
+		b2 += i;
+		m2 += i;
+		s2 += i;
+		}
+	else if (i < 4) {
+		i += 28;
+		b2 += i;
+		m2 += i;
+		s2 += i;
+		}
+	if (b2 > 0) {
+		b = lshift(b, b2);
+		if (b == NULL)
+			return (NULL);
+		}
+	if (s2 > 0) {
+		S = lshift(S, s2);
+		if (S == NULL)
+			return (NULL);
+		}
+	if (k_check) {
+		if (cmp(b,S) < 0) {
+			k--;
+			b = multadd(b, 10, 0);	/* we botched the k estimate */
+			if (b == NULL)
+				return (NULL);
+			if (leftright) {
+				mhi = multadd(mhi, 10, 0);
+				if (mhi == NULL)
+					return (NULL);
+				}
+			ilim = ilim1;
+			}
+		}
+	if (ilim <= 0 && (mode == 3 || mode == 5)) {
+		S = multadd(S,5,0);
+		if (S == NULL)
+			return (NULL);
+		if (ilim < 0 || cmp(b,S) <= 0) {
+			/* no digits, fcvt style */
+ no_digits:
+			k = -1 - ndigits;
+			goto ret;
+			}
+ one_digit:
+		*s++ = '1';
+		k++;
+		goto ret;
+		}
+	if (leftright) {
+		if (m2 > 0) {
+			mhi = lshift(mhi, m2);
+			if (mhi == NULL)
+				return (NULL);
+			}
+
+		/* Compute mlo -- check for special case
+		 * that d is a normalized power of 2.
+		 */
+
+		mlo = mhi;
+		if (spec_case) {
+			mhi = Balloc(mhi->k);
+			if (mhi == NULL)
+				return (NULL);
+			Bcopy(mhi, mlo);
+			mhi = lshift(mhi, Log2P);
+			if (mhi == NULL)
+				return (NULL);
+			}
+
+		for(i = 1;;i++) {
+			dig = quorem(b,S) + '0';
+			/* Do we yet have the shortest decimal string
+			 * that will round to d?
+			 */
+			j = cmp(b, mlo);
+			delta = diff(S, mhi);
+			if (delta == NULL)
+				return (NULL);
+			j1 = delta->sign ? 1 : cmp(b, delta);
+			Bfree(delta);
+#ifndef ROUND_BIASED
+			if (j1 == 0 && mode != 1 && !(word1(&d) & 1)
+#ifdef Honor_FLT_ROUNDS
+				&& Rounding >= 1
+#endif
+								   ) {
+				if (dig == '9')
+					goto round_9_up;
+				if (j > 0)
+					dig++;
+#ifdef SET_INEXACT
+				else if (!b->x[0] && b->wds <= 1)
+					inexact = 0;
+#endif
+				*s++ = dig;
+				goto ret;
+				}
+#endif
+			if (j < 0 || (j == 0 && mode != 1
+#ifndef ROUND_BIASED
+							&& !(word1(&d) & 1)
+#endif
+					)) {
+				if (!b->x[0] && b->wds <= 1) {
+#ifdef SET_INEXACT
+					inexact = 0;
+#endif
+					goto accept_dig;
+					}
+#ifdef Honor_FLT_ROUNDS
+				if (mode > 1)
+				 switch(Rounding) {
+				  case 0: goto accept_dig;
+				  case 2: goto keep_dig;
+				  }
+#endif /*Honor_FLT_ROUNDS*/
+				if (j1 > 0) {
+					b = lshift(b, 1);
+					if (b == NULL)
+						return (NULL);
+					j1 = cmp(b, S);
+#ifdef ROUND_BIASED
+					if (j1 >= 0 /*)*/
+#else
+					if ((j1 > 0 || (j1 == 0 && dig & 1))
+#endif
+					&& dig++ == '9')
+						goto round_9_up;
+					}
+ accept_dig:
+				*s++ = dig;
+				goto ret;
+				}
+			if (j1 > 0) {
+#ifdef Honor_FLT_ROUNDS
+				if (!Rounding)
+					goto accept_dig;
+#endif
+				if (dig == '9') { /* possible if i == 1 */
+ round_9_up:
+					*s++ = '9';
+					goto roundoff;
+					}
+				*s++ = dig + 1;
+				goto ret;
+				}
+#ifdef Honor_FLT_ROUNDS
+ keep_dig:
+#endif
+			*s++ = dig;
+			if (i == ilim)
+				break;
+			b = multadd(b, 10, 0);
+			if (b == NULL)
+				return (NULL);
+			if (mlo == mhi) {
+				mlo = mhi = multadd(mhi, 10, 0);
+				if (mlo == NULL)
+					return (NULL);
+				}
+			else {
+				mlo = multadd(mlo, 10, 0);
+				if (mlo == NULL)
+					return (NULL);
+				mhi = multadd(mhi, 10, 0);
+				if (mhi == NULL)
+					return (NULL);
+				}
+			}
+		}
+	else
+		for(i = 1;; i++) {
+			*s++ = dig = quorem(b,S) + '0';
+			if (!b->x[0] && b->wds <= 1) {
+#ifdef SET_INEXACT
+				inexact = 0;
+#endif
+				goto ret;
+				}
+			if (i >= ilim)
+				break;
+			b = multadd(b, 10, 0);
+			if (b == NULL)
+				return (NULL);
+			}
+
+	/* Round off last digit */
+
+#ifdef Honor_FLT_ROUNDS
+	switch(Rounding) {
+	  case 0: goto trimzeros;
+	  case 2: goto roundoff;
+	  }
+#endif
+	b = lshift(b, 1);
+	if (b == NULL)
+		return (NULL);
+	j = cmp(b, S);
+#ifdef ROUND_BIASED
+	if (j >= 0)
+#else
+	if (j > 0 || (j == 0 && dig & 1))
+#endif
+		{
+ roundoff:
+		while(*--s == '9')
+			if (s == s0) {
+				k++;
+				*s++ = '1';
+				goto ret;
+				}
+		++*s++;
+		}
+	else {
+#ifdef Honor_FLT_ROUNDS
+ trimzeros:
+#endif
+		while(*--s == '0');
+		s++;
+		}
+ ret:
+	Bfree(S);
+	if (mhi) {
+		if (mlo && mlo != mhi)
+			Bfree(mlo);
+		Bfree(mhi);
+		}
+ ret1:
+#ifdef SET_INEXACT
+	if (inexact) {
+		if (!oldinexact) {
+			word0(&d) = Exp_1 + (70 << Exp_shift);
+			word1(&d) = 0;
+			dval(&d) += 1.;
+			}
+		}
+	else if (!oldinexact)
+		clear_inexact();
+#endif
+	Bfree(b);
+	*s = 0;
+	*decpt = k + 1;
+	if (rve)
+		*rve = s;
+	return s0;
+}
diff --git a/newlib/libc/stdlib/gdtoa-gdtoa.c b/newlib/libc/stdlib/gdtoa-gdtoa.c
new file mode 100644
index 000000000..feae5afa3
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-gdtoa.c
@@ -0,0 +1,830 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998, 1999 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include "gdtoaimp.h"
+
+ static Bigint *
+#ifdef KR_headers
+bitstob(bits, nbits, bbits) ULong *bits; int nbits; int *bbits;
+#else
+bitstob(ULong *bits, int nbits, int *bbits)
+#endif
+{
+	int i, k;
+	Bigint *b;
+	ULong *be, *x, *x0;
+
+	i = ULbits;
+	k = 0;
+	while(i < nbits) {
+		i <<= 1;
+		k++;
+		}
+#ifndef Pack_32
+	if (!k)
+		k = 1;
+#endif
+	b = Balloc(k);
+	if (b == NULL)
+		return (NULL);
+	be = bits + ((nbits - 1) >> kshift);
+	x = x0 = b->x;
+	do {
+		*x++ = *bits & ALL_ON;
+#ifdef Pack_16
+		*x++ = (*bits >> 16) & ALL_ON;
+#endif
+		} while(++bits <= be);
+	i = x - x0;
+	while(!x0[--i])
+		if (!i) {
+			b->wds = 0;
+			*bbits = 0;
+			goto ret;
+			}
+	b->wds = i + 1;
+	*bbits = i*ULbits + 32 - hi0bits(b->x[i]);
+ ret:
+	return b;
+	}
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ *	1. Rather than iterating, we use a simple numeric overestimate
+ *	   to determine k = floor(log10(d)).  We scale relevant
+ *	   quantities using O(log2(k)) rather than O(k) multiplications.
+ *	2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ *	   try to generate digits strictly left to right.  Instead, we
+ *	   compute with fewer bits and propagate the carry if necessary
+ *	   when rounding the final digit up.  This is often faster.
+ *	3. Under the assumption that input will be rounded nearest,
+ *	   mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ *	   That is, we allow equality in stopping tests when the
+ *	   round-nearest rule will give the same floating-point value
+ *	   as would satisfaction of the stopping test with strict
+ *	   inequality.
+ *	4. We remove common factors of powers of 2 from relevant
+ *	   quantities.
+ *	5. When converting floating-point integers less than 1e16,
+ *	   we use floating-point arithmetic rather than resorting
+ *	   to multiple-precision integers.
+ *	6. When asked to produce fewer than 15 digits, we first try
+ *	   to get by with floating-point arithmetic; we resort to
+ *	   multiple-precision integer arithmetic only if we cannot
+ *	   guarantee that the floating-point calculation has given
+ *	   the correctly rounded result.  For k requested digits and
+ *	   "uniformly" distributed input, the probability is
+ *	   something like 10^(k-15) that we must resort to the Long
+ *	   calculation.
+ */
+
+ char *
+gdtoa
+#ifdef KR_headers
+	(fpi, be, bits, kindp, mode, ndigits, decpt, rve)
+	FPI *fpi; int be; ULong *bits;
+	int *kindp, mode, ndigits, *decpt; char **rve;
+#else
+	(FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, int *decpt, char **rve)
+#endif
+{
+ /*	Arguments ndigits and decpt are similar to the second and third
+	arguments of ecvt and fcvt; trailing zeros are suppressed from
+	the returned string.  If not null, *rve is set to point
+	to the end of the return value.  If d is +-Infinity or NaN,
+	then *decpt is set to 9999.
+	be = exponent: value = (integer represented by bits) * (2 to the power of be).
+
+	mode:
+		0 ==> shortest string that yields d when read in
+			and rounded to nearest.
+		1 ==> like 0, but with Steele & White stopping rule;
+			e.g. with IEEE P754 arithmetic , mode 0 gives
+			1e23 whereas mode 1 gives 9.999999999999999e22.
+		2 ==> max(1,ndigits) significant digits.  This gives a
+			return value similar to that of ecvt, except
+			that trailing zeros are suppressed.
+		3 ==> through ndigits past the decimal point.  This
+			gives a return value similar to that from fcvt,
+			except that trailing zeros are suppressed, and
+			ndigits can be negative.
+		4-9 should give the same return values as 2-3, i.e.,
+			4 <= mode <= 9 ==> same return as mode
+			2 + (mode & 1).  These modes are mainly for
+			debugging; often they run slower but sometimes
+			faster than modes 2-3.
+		4,5,8,9 ==> left-to-right digit generation.
+		6-9 ==> don't try fast floating-point estimate
+			(if applicable).
+
+		Values of mode other than 0-9 are treated as mode 0.
+
+		Sufficient space is allocated to the return value
+		to hold the suppressed trailing zeros.
+	*/
+
+	int bbits, b2, b5, be0, dig, i, ieps, ilim, ilim0, ilim1, inex;
+	int j, j1, k, k0, k_check, kind, leftright, m2, m5, nbits;
+	int rdir, s2, s5, spec_case, try_quick;
+	Long L;
+	Bigint *b, *b1, *delta, *mlo, *mhi, *mhi1, *S;
+	double d2, ds;
+	char *s, *s0;
+	U d, eps;
+
+#ifndef MULTIPLE_THREADS
+	if (dtoa_result) {
+		freedtoa(dtoa_result);
+		dtoa_result = 0;
+		}
+#endif
+	inex = 0;
+	kind = *kindp &= ~STRTOG_Inexact;
+	switch(kind & STRTOG_Retmask) {
+	  case STRTOG_Zero:
+		goto ret_zero;
+	  case STRTOG_Normal:
+	  case STRTOG_Denormal:
+		break;
+	  case STRTOG_Infinite:
+		*decpt = -32768;
+		return nrv_alloc("Infinity", rve, 8);
+	  case STRTOG_NaN:
+		*decpt = -32768;
+		return nrv_alloc("NaN", rve, 3);
+	  default:
+		return 0;
+	  }
+	b = bitstob(bits, nbits = fpi->nbits, &bbits);
+	if (b == NULL)
+		return (NULL);
+	be0 = be;
+	if ( (i = trailz(b)) !=0) {
+		rshift(b, i);
+		be += i;
+		bbits -= i;
+		}
+	if (!b->wds) {
+		Bfree(b);
+ ret_zero:
+		*decpt = 1;
+		return nrv_alloc("0", rve, 1);
+		}
+
+	dval(&d) = b2d(b, &i);
+	i = be + bbits - 1;
+	word0(&d) &= Frac_mask1;
+	word0(&d) |= Exp_11;
+#ifdef IBM
+	if ( (j = 11 - hi0bits(word0(&d) & Frac_mask)) !=0)
+		dval(&d) /= 1 << j;
+#endif
+
+	/* log(x)	~=~ log(1.5) + (x-1.5)/1.5
+	 * log10(x)	 =  log(x) / log(10)
+	 *		~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+	 * log10(&d) = (i-Bias)*log(2)/log(10) + log10(d2)
+	 *
+	 * This suggests computing an approximation k to log10(&d) by
+	 *
+	 * k = (i - Bias)*0.301029995663981
+	 *	+ ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+	 *
+	 * We want k to be too large rather than too small.
+	 * The error in the first-order Taylor series approximation
+	 * is in our favor, so we just round up the constant enough
+	 * to compensate for any error in the multiplication of
+	 * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+	 * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+	 * adding 1e-13 to the constant term more than suffices.
+	 * Hence we adjust the constant term to 0.1760912590558.
+	 * (We could get a more accurate k by invoking log10,
+	 *  but this is probably not worthwhile.)
+	 */
+#ifdef IBM
+	i <<= 2;
+	i += j;
+#endif
+	ds = (dval(&d)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
+
+	/* correct assumption about exponent range */
+	if ((j = i) < 0)
+		j = -j;
+	if ((j -= 1077) > 0)
+		ds += j * 7e-17;
+
+	k = (int)ds;
+	if (ds < 0. && ds != k)
+		k--;	/* want k = floor(ds) */
+	k_check = 1;
+#ifdef IBM
+	j = be + bbits - 1;
+	if ( (j1 = j & 3) !=0)
+		dval(&d) *= 1 << j1;
+	word0(&d) += j << Exp_shift - 2 & Exp_mask;
+#else
+	word0(&d) += (be + bbits - 1) << Exp_shift;
+#endif
+	if (k >= 0 && k <= Ten_pmax) {
+		if (dval(&d) < tens[k])
+			k--;
+		k_check = 0;
+		}
+	j = bbits - i - 1;
+	if (j >= 0) {
+		b2 = 0;
+		s2 = j;
+		}
+	else {
+		b2 = -j;
+		s2 = 0;
+		}
+	if (k >= 0) {
+		b5 = 0;
+		s5 = k;
+		s2 += k;
+		}
+	else {
+		b2 -= k;
+		b5 = -k;
+		s5 = 0;
+		}
+	if (mode < 0 || mode > 9)
+		mode = 0;
+	try_quick = 1;
+	if (mode > 5) {
+		mode -= 4;
+		try_quick = 0;
+		}
+	else if (i >= -4 - Emin || i < Emin)
+		try_quick = 0;
+	leftright = 1;
+	ilim = ilim1 = -1;	/* Values for cases 0 and 1; done here to */
+				/* silence erroneous "gcc -Wall" warning. */
+	switch(mode) {
+		case 0:
+		case 1:
+			i = (int)(nbits * .30103) + 3;
+			ndigits = 0;
+			break;
+		case 2:
+			leftright = 0;
+			/* no break */
+		case 4:
+			if (ndigits <= 0)
+				ndigits = 1;
+			ilim = ilim1 = i = ndigits;
+			break;
+		case 3:
+			leftright = 0;
+			/* no break */
+		case 5:
+			i = ndigits + k + 1;
+			ilim = i;
+			ilim1 = i - 1;
+			if (i <= 0)
+				i = 1;
+		}
+	s = s0 = rv_alloc(i);
+	if (s == NULL)
+		return (NULL);
+
+	if ( (rdir = fpi->rounding - 1) !=0) {
+		if (rdir < 0)
+			rdir = 2;
+		if (kind & STRTOG_Neg)
+			rdir = 3 - rdir;
+		}
+
+	/* Now rdir = 0 ==> round near, 1 ==> round up, 2 ==> round down. */
+
+	if (ilim >= 0 && ilim <= Quick_max && try_quick && !rdir
+#ifndef IMPRECISE_INEXACT
+		&& k == 0
+#endif
+								) {
+
+		/* Try to get by with floating-point arithmetic. */
+
+		i = 0;
+		d2 = dval(&d);
+#ifdef IBM
+		if ( (j = 11 - hi0bits(word0(&d) & Frac_mask)) !=0)
+			dval(&d) /= 1 << j;
+#endif
+		k0 = k;
+		ilim0 = ilim;
+		ieps = 2; /* conservative */
+		if (k > 0) {
+			ds = tens[k&0xf];
+			j = k >> 4;
+			if (j & Bletch) {
+				/* prevent overflows */
+				j &= Bletch - 1;
+				dval(&d) /= bigtens[n_bigtens-1];
+				ieps++;
+				}
+			for(; j; j >>= 1, i++)
+				if (j & 1) {
+					ieps++;
+					ds *= bigtens[i];
+					}
+			}
+		else  {
+			ds = 1.;
+			if ( (j1 = -k) !=0) {
+				dval(&d) *= tens[j1 & 0xf];
+				for(j = j1 >> 4; j; j >>= 1, i++)
+					if (j & 1) {
+						ieps++;
+						dval(&d) *= bigtens[i];
+						}
+				}
+			}
+		if (k_check && dval(&d) < 1. && ilim > 0) {
+			if (ilim1 <= 0)
+				goto fast_failed;
+			ilim = ilim1;
+			k--;
+			dval(&d) *= 10.;
+			ieps++;
+			}
+		dval(&eps) = ieps*dval(&d) + 7.;
+		word0(&eps) -= (P-1)*Exp_msk1;
+		if (ilim == 0) {
+			S = mhi = 0;
+			dval(&d) -= 5.;
+			if (dval(&d) > dval(&eps))
+				goto one_digit;
+			if (dval(&d) < -dval(&eps))
+				goto no_digits;
+			goto fast_failed;
+			}
+#ifndef No_leftright
+		if (leftright) {
+			/* Use Steele & White method of only
+			 * generating digits needed.
+			 */
+			dval(&eps) = ds*0.5/tens[ilim-1] - dval(&eps);
+			for(i = 0;;) {
+				L = (Long)(dval(&d)/ds);
+				dval(&d) -= L*ds;
+				*s++ = '0' + (int)L;
+				if (dval(&d) < dval(&eps)) {
+					if (dval(&d))
+						inex = STRTOG_Inexlo;
+					goto ret1;
+					}
+				if (ds - dval(&d) < dval(&eps))
+					goto bump_up;
+				if (++i >= ilim)
+					break;
+				dval(&eps) *= 10.;
+				dval(&d) *= 10.;
+				}
+			}
+		else {
+#endif
+			/* Generate ilim digits, then fix them up. */
+			dval(&eps) *= tens[ilim-1];
+			for(i = 1;; i++, dval(&d) *= 10.) {
+				if ( (L = (Long)(dval(&d)/ds)) !=0)
+					dval(&d) -= L*ds;
+				*s++ = '0' + (int)L;
+				if (i == ilim) {
+					ds *= 0.5;
+					if (dval(&d) > ds + dval(&eps))
+						goto bump_up;
+					else if (dval(&d) < ds - dval(&eps)) {
+						if (dval(&d))
+							inex = STRTOG_Inexlo;
+						goto clear_trailing0;
+						}
+					break;
+					}
+				}
+#ifndef No_leftright
+			}
+#endif
+ fast_failed:
+		s = s0;
+		dval(&d) = d2;
+		k = k0;
+		ilim = ilim0;
+		}
+
+	/* Do we have a "small" integer? */
+
+	if (be >= 0 && k <= Int_max) {
+		/* Yes. */
+		ds = tens[k];
+		if (ndigits < 0 && ilim <= 0) {
+			S = mhi = 0;
+			if (ilim < 0 || dval(&d) <= 5*ds)
+				goto no_digits;
+			goto one_digit;
+			}
+		for(i = 1;; i++, dval(&d) *= 10.) {
+			L = dval(&d) / ds;
+			dval(&d) -= L*ds;
+#ifdef Check_FLT_ROUNDS
+			/* If FLT_ROUNDS == 2, L will usually be high by 1 */
+			if (dval(&d) < 0) {
+				L--;
+				dval(&d) += ds;
+				}
+#endif
+			*s++ = '0' + (int)L;
+			if (dval(&d) == 0.)
+				break;
+			if (i == ilim) {
+				if (rdir) {
+					if (rdir == 1)
+						goto bump_up;
+					inex = STRTOG_Inexlo;
+					goto ret1;
+					}
+				dval(&d) += dval(&d);
+#ifdef ROUND_BIASED
+				if (dval(&d) >= ds)
+#else
+				if (dval(&d) > ds || (dval(&d) == ds && L & 1))
+#endif
+					{
+ bump_up:
+					inex = STRTOG_Inexhi;
+					while(*--s == '9')
+						if (s == s0) {
+							k++;
+							*s = '0';
+							break;
+							}
+					++*s++;
+					}
+				else {
+					inex = STRTOG_Inexlo;
+ clear_trailing0:
+					while(*--s == '0'){}
+					++s;
+					}
+				break;
+				}
+			}
+		goto ret1;
+		}
+
+	m2 = b2;
+	m5 = b5;
+	mhi = mlo = 0;
+	if (leftright) {
+		i = nbits - bbits;
+		if (be - i++ < fpi->emin && mode != 3 && mode != 5) {
+			/* denormal */
+			i = be - fpi->emin + 1;
+			if (mode >= 2 && ilim > 0 && ilim < i)
+				goto small_ilim;
+			}
+		else if (mode >= 2) {
+ small_ilim:
+			j = ilim - 1;
+			if (m5 >= j)
+				m5 -= j;
+			else {
+				s5 += j -= m5;
+				b5 += j;
+				m5 = 0;
+				}
+			if ((i = ilim) < 0) {
+				m2 -= i;
+				i = 0;
+				}
+			}
+		b2 += i;
+		s2 += i;
+		mhi = i2b(1);
+		if (mhi == NULL)
+			return (NULL);
+		}
+	if (m2 > 0 && s2 > 0) {
+		i = m2 < s2 ? m2 : s2;
+		b2 -= i;
+		m2 -= i;
+		s2 -= i;
+		}
+	if (b5 > 0) {
+		if (leftright) {
+			if (m5 > 0) {
+				mhi = pow5mult(mhi, m5);
+				if (mhi == NULL)
+					return (NULL);
+				b1 = mult(mhi, b);
+				if (b1 == NULL)
+					return (NULL);
+				Bfree(b);
+				b = b1;
+				}
+			if ( (j = b5 - m5) !=0) {
+				b = pow5mult(b, j);
+				if (b == NULL)
+					return (NULL);
+				}
+			}
+		else {
+			b = pow5mult(b, b5);
+			if (b == NULL)
+				return (NULL);
+			}
+		}
+	S = i2b(1);
+	if (S == NULL)
+		return (NULL);
+	if (s5 > 0) {
+		S = pow5mult(S, s5);
+		if (S == NULL)
+			return (NULL);
+		}
+
+	/* Check for special case that d is a normalized power of 2. */
+
+	spec_case = 0;
+	if (mode < 2) {
+		if (bbits == 1 && be0 > fpi->emin + 1) {
+			/* The special case */
+			b2++;
+			s2++;
+			spec_case = 1;
+			}
+		}
+
+	/* Arrange for convenient computation of quotients:
+	 * shift left if necessary so divisor has 4 leading 0 bits.
+	 *
+	 * Perhaps we should just compute leading 28 bits of S once
+	 * and for all and pass them and a shift to quorem, so it
+	 * can do shifts and ors to compute the numerator for q.
+	 */
+	i = ((s5 ? hi0bits(S->x[S->wds-1]) : ULbits - 1) - s2 - 4) & kmask;
+	m2 += i;
+	if ((b2 += i) > 0) {
+		b = lshift(b, b2);
+		if (b == NULL)
+			return (NULL);
+		}
+	if ((s2 += i) > 0) {
+		S = lshift(S, s2);
+		if (S == NULL)
+			return (NULL);
+		}
+	if (k_check) {
+		if (cmp(b,S) < 0) {
+			k--;
+			b = multadd(b, 10, 0);	/* we botched the k estimate */
+			if (b == NULL)
+				return (NULL);
+			if (leftright) {
+				mhi = multadd(mhi, 10, 0);
+				if (mhi == NULL)
+					return (NULL);
+				}
+			ilim = ilim1;
+			}
+		}
+	if (ilim <= 0 && mode > 2) {
+		S = multadd(S,5,0);
+		if (S == NULL)
+			return (NULL);
+		if (ilim < 0 || cmp(b,S) <= 0) {
+			/* no digits, fcvt style */
+ no_digits:
+			k = -1 - ndigits;
+			inex = STRTOG_Inexlo;
+			goto ret;
+			}
+ one_digit:
+		inex = STRTOG_Inexhi;
+		*s++ = '1';
+		k++;
+		goto ret;
+		}
+	if (leftright) {
+		if (m2 > 0) {
+			mhi = lshift(mhi, m2);
+			if (mhi == NULL)
+				return (NULL);
+			}
+
+		/* Compute mlo -- check for special case
+		 * that d is a normalized power of 2.
+		 */
+
+		mlo = mhi;
+		if (spec_case) {
+			mhi = Balloc(mhi->k);
+			if (mhi == NULL)
+				return (NULL);
+			Bcopy(mhi, mlo);
+			mhi = lshift(mhi, 1);
+			if (mhi == NULL)
+				return (NULL);
+			}
+
+		for(i = 1;;i++) {
+			dig = quorem(b,S) + '0';
+			/* Do we yet have the shortest decimal string
+			 * that will round to d?
+			 */
+			j = cmp(b, mlo);
+			delta = diff(S, mhi);
+			if (delta == NULL)
+				return (NULL);
+			j1 = delta->sign ? 1 : cmp(b, delta);
+			Bfree(delta);
+#ifndef ROUND_BIASED
+			if (j1 == 0 && !mode && !(bits[0] & 1) && !rdir) {
+				if (dig == '9')
+					goto round_9_up;
+				if (j <= 0) {
+					if (b->wds > 1 || b->x[0])
+						inex = STRTOG_Inexlo;
+					}
+				else {
+					dig++;
+					inex = STRTOG_Inexhi;
+					}
+				*s++ = dig;
+				goto ret;
+				}
+#endif
+			if (j < 0 || (j == 0 && !mode
+#ifndef ROUND_BIASED
+							&& !(bits[0] & 1)
+#endif
+					)) {
+				if (rdir && (b->wds > 1 || b->x[0])) {
+					if (rdir == 2) {
+						inex = STRTOG_Inexlo;
+						goto accept;
+						}
+					while (cmp(S,mhi) > 0) {
+						*s++ = dig;
+						mhi1 = multadd(mhi, 10, 0);
+						if (mhi1 == NULL)
+							return (NULL);
+						if (mlo == mhi)
+							mlo = mhi1;
+						mhi = mhi1;
+						b = multadd(b, 10, 0);
+						if (b == NULL)
+							return (NULL);
+						dig = quorem(b,S) + '0';
+						}
+					if (dig++ == '9')
+						goto round_9_up;
+					inex = STRTOG_Inexhi;
+					goto accept;
+					}
+				if (j1 > 0) {
+					b = lshift(b, 1);
+					if (b == NULL)
+						return (NULL);
+					j1 = cmp(b, S);
+#ifdef ROUND_BIASED
+					if (j1 >= 0 /*)*/
+#else
+					if ((j1 > 0 || (j1 == 0 && dig & 1))
+#endif
+					&& dig++ == '9')
+						goto round_9_up;
+					inex = STRTOG_Inexhi;
+					}
+				if (b->wds > 1 || b->x[0])
+					inex = STRTOG_Inexlo;
+ accept:
+				*s++ = dig;
+				goto ret;
+				}
+			if (j1 > 0 && rdir != 2) {
+				if (dig == '9') { /* possible if i == 1 */
+ round_9_up:
+					*s++ = '9';
+					inex = STRTOG_Inexhi;
+					goto roundoff;
+					}
+				inex = STRTOG_Inexhi;
+				*s++ = dig + 1;
+				goto ret;
+				}
+			*s++ = dig;
+			if (i == ilim)
+				break;
+			b = multadd(b, 10, 0);
+			if (b == NULL)
+				return (NULL);
+			if (mlo == mhi) {
+				mlo = mhi = multadd(mhi, 10, 0);
+				if (mlo == NULL)
+					return (NULL);
+				}
+			else {
+				mlo = multadd(mlo, 10, 0);
+				if (mlo == NULL)
+					return (NULL);
+				mhi = multadd(mhi, 10, 0);
+				if (mhi == NULL)
+					return (NULL);
+				}
+			}
+		}
+	else
+		for(i = 1;; i++) {
+			*s++ = dig = quorem(b,S) + '0';
+			if (i >= ilim)
+				break;
+			b = multadd(b, 10, 0);
+			if (b == NULL)
+				return (NULL);
+			}
+
+	/* Round off last digit */
+
+	if (rdir) {
+		if (rdir == 2 || (b->wds <= 1 && !b->x[0]))
+			goto chopzeros;
+		goto roundoff;
+		}
+	b = lshift(b, 1);
+	if (b == NULL)
+		return (NULL);
+	j = cmp(b, S);
+#ifdef ROUND_BIASED
+	if (j >= 0)
+#else
+	if (j > 0 || (j == 0 && dig & 1))
+#endif
+		{
+ roundoff:
+		inex = STRTOG_Inexhi;
+		while(*--s == '9')
+			if (s == s0) {
+				k++;
+				*s++ = '1';
+				goto ret;
+				}
+		++*s++;
+		}
+	else {
+ chopzeros:
+		if (b->wds > 1 || b->x[0])
+			inex = STRTOG_Inexlo;
+		while(*--s == '0'){}
+		++s;
+		}
+ ret:
+	Bfree(S);
+	if (mhi) {
+		if (mlo && mlo != mhi)
+			Bfree(mlo);
+		Bfree(mhi);
+		}
+ ret1:
+	Bfree(b);
+	*s = 0;
+	*decpt = k + 1;
+	if (rve)
+		*rve = s;
+	*kindp |= inex;
+	return s0;
+	}
+DEF_STRONG(gdtoa);
diff --git a/newlib/libc/stdlib/gdtoa-gmisc.c b/newlib/libc/stdlib/gdtoa-gmisc.c
new file mode 100644
index 000000000..8270ef944
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-gmisc.c
@@ -0,0 +1,86 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include "gdtoaimp.h"
+
+ void
+#ifdef KR_headers
+rshift(b, k) Bigint *b; int k;
+#else
+rshift(Bigint *b, int k)
+#endif
+{
+	ULong *x, *x1, *xe, y;
+	int n;
+
+	x = x1 = b->x;
+	n = k >> kshift;
+	if (n < b->wds) {
+		xe = x + b->wds;
+		x += n;
+		if (k &= kmask) {
+			n = ULbits - k;
+			y = *x++ >> k;
+			while(x < xe) {
+				*x1++ = (y | (*x << n)) & ALL_ON;
+				y = *x++ >> k;
+				}
+			if ((*x1 = y) !=0)
+				x1++;
+			}
+		else
+			while(x < xe)
+				*x1++ = *x++;
+		}
+	if ((b->wds = x1 - b->x) == 0)
+		b->x[0] = 0;
+	}
+
+ int
+#ifdef KR_headers
+trailz(b) Bigint *b;
+#else
+trailz(Bigint *b)
+#endif
+{
+	ULong L, *x, *xe;
+	int n = 0;
+
+	x = b->x;
+	xe = x + b->wds;
+	for(n = 0; x < xe && !*x; x++)
+		n += ULbits;
+	if (x < xe) {
+		L = *x;
+		n += lo0bits(&L);
+		}
+	return n;
+	}
diff --git a/newlib/libc/stdlib/gdtoa-ldtoa.c b/newlib/libc/stdlib/gdtoa-ldtoa.c
new file mode 100644
index 000000000..7282e7a39
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-ldtoa.c
@@ -0,0 +1,124 @@
+/*	$OpenBSD: ldtoa.c,v 1.4 2016/03/09 16:28:47 deraadt Exp $	*/
+/*-
+ * Copyright (c) 2003 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <machine/ieee.h>
+#include <float.h>
+#include <stdint.h>
+#include <limits.h>
+#include <math.h>
+#include <stdlib.h>
+#include "gdtoaimp.h"
+
+#if (LDBL_MANT_DIG > DBL_MANT_DIG)
+
+/*
+ * ldtoa() is a wrapper for gdtoa() that makes it smell like dtoa(),
+ * except that the floating point argument is passed by reference.
+ * When dtoa() is passed a NaN or infinity, it sets expt to 9999.
+ * However, a long double could have a valid exponent of 9999, so we
+ * use INT_MAX in ldtoa() instead.
+ */
+char *
+__ldtoa(long double *ld, int mode, int ndigits, int *decpt, int *sign,
+    char **rve)
+{
+	FPI fpi = {
+		LDBL_MANT_DIG,			/* nbits */
+		LDBL_MIN_EXP - LDBL_MANT_DIG,	/* emin */
+		LDBL_MAX_EXP - LDBL_MANT_DIG,	/* emax */
+		FLT_ROUNDS,	       		/* rounding */
+#ifdef Sudden_Underflow	/* unused, but correct anyway */
+		1
+#else
+		0
+#endif
+	};
+	int be, kind;
+	char *ret;
+	struct ieee_ext *p = (struct ieee_ext *)ld;
+	uint32_t bits[(LDBL_MANT_DIG + 31) / 32];
+	void *vbits = bits;
+
+	/*
+	 * gdtoa doesn't know anything about the sign of the number, so
+	 * if the number is negative, we need to swap rounding modes of
+	 * 2 (upwards) and 3 (downwards).
+	 */
+	*sign = p->ext_sign;
+	fpi.rounding ^= (fpi.rounding >> 1) & p->ext_sign;
+
+	be = p->ext_exp - (LDBL_MAX_EXP - 1) - (LDBL_MANT_DIG - 1);
+	EXT_TO_ARRAY32(p, bits);
+
+	switch (fpclassify(*ld)) {
+	case FP_NORMAL:
+		kind = STRTOG_Normal;
+#ifdef EXT_IMPLICIT_NBIT
+		bits[LDBL_MANT_DIG / 32] |= 1 << ((LDBL_MANT_DIG - 1) % 32);
+#endif /* EXT_IMPLICIT_NBIT */
+		break;
+	case FP_ZERO:
+		kind = STRTOG_Zero;
+		break;
+	case FP_SUBNORMAL:
+		kind = STRTOG_Denormal;
+		be++;
+		break;
+	case FP_INFINITE:
+		kind = STRTOG_Infinite;
+		break;
+	case FP_NAN:
+		kind = STRTOG_NaN;
+		break;
+	default:
+		abort();
+	}
+
+	ret = gdtoa(&fpi, be, vbits, &kind, mode, ndigits, decpt, rve);
+	if (*decpt == -32768)
+		*decpt = INT_MAX;
+	return ret;
+}
+DEF_STRONG(__ldtoa);
+
+#else   /* (LDBL_MANT_DIG == DBL_MANT_DIG) */
+
+char *
+__ldtoa(long double *ld, int mode, int ndigits, int *decpt, int *sign,
+    char **rve)
+{
+	char *ret;
+
+	ret = dtoa((double)*ld, mode, ndigits, decpt, sign, rve);
+	if (*decpt == 9999)
+		*decpt = INT_MAX;
+	return ret;
+}
+DEF_STRONG(__ldtoa);
+
+#endif  /* (LDBL_MANT_DIG == DBL_MANT_DIG) */
diff --git a/newlib/libc/stdlib/gdtoa-misc.c b/newlib/libc/stdlib/gdtoa-misc.c
new file mode 100644
index 000000000..5d1e0ad69
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-misc.c
@@ -0,0 +1,912 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998, 1999 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include "gdtoaimp.h"
+
+ static Bigint *freelist[Kmax+1];
+#ifndef Omit_Private_Memory
+#ifndef PRIVATE_MEM
+#define PRIVATE_MEM 2304
+#endif
+#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double))
+static double private_mem[PRIVATE_mem], *pmem_next = private_mem;
+#endif
+
+#ifdef MULTIPLE_THREADS
+__LOCK_INIT(static, __dtoa_lock0);
+__LOCK_INIT(static, __dtoa_lock1);
+#endif
+
+ Bigint *
+Balloc
+#ifdef KR_headers
+	(k) int k;
+#else
+	(int k)
+#endif
+{
+	int x;
+	Bigint *rv;
+#ifndef Omit_Private_Memory
+	unsigned int len;
+#endif
+
+	ACQUIRE_DTOA_LOCK(0);
+	/* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */
+	/* but this case seems very unlikely. */
+	if (k <= Kmax && (rv = freelist[k]) !=0) {
+		freelist[k] = rv->next;
+		}
+	else {
+		x = 1 << k;
+#ifdef Omit_Private_Memory
+		rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong));
+		if (rv == NULL)
+			return (NULL);
+#else
+		len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1)
+			/sizeof(double);
+		if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem) {
+			rv = (Bigint*)pmem_next;
+			pmem_next += len;
+			}
+		else {
+			rv = (Bigint*)MALLOC(len*sizeof(double));
+			if (rv == NULL)
+				return (NULL);
+		}
+#endif
+		rv->k = k;
+		rv->maxwds = x;
+		}
+	FREE_DTOA_LOCK(0);
+	rv->sign = rv->wds = 0;
+	return rv;
+	}
+
+ void
+Bfree
+#ifdef KR_headers
+	(v) Bigint *v;
+#else
+	(Bigint *v)
+#endif
+{
+	if (v) {
+		if (v->k > Kmax)
+#ifdef FREE
+			FREE(v);
+#else
+			free(v);
+#endif
+		else {
+			ACQUIRE_DTOA_LOCK(0);
+			v->next = freelist[v->k];
+			freelist[v->k] = v;
+			FREE_DTOA_LOCK(0);
+			}
+		}
+	}
+
+ int
+lo0bits
+#ifdef KR_headers
+	(y) ULong *y;
+#else
+	(ULong *y)
+#endif
+{
+	int k;
+	ULong x = *y;
+
+	if (x & 7) {
+		if (x & 1)
+			return 0;
+		if (x & 2) {
+			*y = x >> 1;
+			return 1;
+			}
+		*y = x >> 2;
+		return 2;
+		}
+	k = 0;
+	if (!(x & 0xffff)) {
+		k = 16;
+		x >>= 16;
+		}
+	if (!(x & 0xff)) {
+		k += 8;
+		x >>= 8;
+		}
+	if (!(x & 0xf)) {
+		k += 4;
+		x >>= 4;
+		}
+	if (!(x & 0x3)) {
+		k += 2;
+		x >>= 2;
+		}
+	if (!(x & 1)) {
+		k++;
+		x >>= 1;
+		if (!x)
+			return 32;
+		}
+	*y = x;
+	return k;
+	}
+
+ Bigint *
+multadd
+#ifdef KR_headers
+	(b, m, a) Bigint *b; int m, a;
+#else
+	(Bigint *b, int m, int a)	/* multiply by m and add a */
+#endif
+{
+	int i, wds;
+#ifdef ULLong
+	ULong *x;
+	ULLong carry, y;
+#else
+	ULong carry, *x, y;
+#ifdef Pack_32
+	ULong xi, z;
+#endif
+#endif
+	Bigint *b1;
+
+	wds = b->wds;
+	x = b->x;
+	i = 0;
+	carry = a;
+	do {
+#ifdef ULLong
+		y = *x * (ULLong)m + carry;
+		carry = y >> 32;
+		*x++ = y & 0xffffffffUL;
+#else
+#ifdef Pack_32
+		xi = *x;
+		y = (xi & 0xffff) * m + carry;
+		z = (xi >> 16) * m + (y >> 16);
+		carry = z >> 16;
+		*x++ = (z << 16) + (y & 0xffff);
+#else
+		y = *x * m + carry;
+		carry = y >> 16;
+		*x++ = y & 0xffff;
+#endif
+#endif
+		}
+		while(++i < wds);
+	if (carry) {
+		if (wds >= b->maxwds) {
+			b1 = Balloc(b->k+1);
+			if (b1 == NULL)
+				return (NULL);
+			Bcopy(b1, b);
+			Bfree(b);
+			b = b1;
+			}
+		b->x[wds++] = carry;
+		b->wds = wds;
+		}
+	return b;
+	}
+
+ int
+hi0bits_D2A
+#ifdef KR_headers
+	(x) ULong x;
+#else
+	(ULong x)
+#endif
+{
+	int k = 0;
+
+	if (!(x & 0xffff0000)) {
+		k = 16;
+		x <<= 16;
+		}
+	if (!(x & 0xff000000)) {
+		k += 8;
+		x <<= 8;
+		}
+	if (!(x & 0xf0000000)) {
+		k += 4;
+		x <<= 4;
+		}
+	if (!(x & 0xc0000000)) {
+		k += 2;
+		x <<= 2;
+		}
+	if (!(x & 0x80000000)) {
+		k++;
+		if (!(x & 0x40000000))
+			return 32;
+		}
+	return k;
+	}
+
+ Bigint *
+i2b
+#ifdef KR_headers
+	(i) int i;
+#else
+	(int i)
+#endif
+{
+	Bigint *b;
+
+	b = Balloc(1);
+	if (b == NULL)
+		return (NULL);
+	b->x[0] = i;
+	b->wds = 1;
+	return b;
+	}
+
+ Bigint *
+mult
+#ifdef KR_headers
+	(a, b) Bigint *a, *b;
+#else
+	(Bigint *a, Bigint *b)
+#endif
+{
+	Bigint *c;
+	int k, wa, wb, wc;
+	ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0;
+	ULong y;
+#ifdef ULLong
+	ULLong carry, z;
+#else
+	ULong carry, z;
+#ifdef Pack_32
+	ULong z2;
+#endif
+#endif
+
+	if (a->wds < b->wds) {
+		c = a;
+		a = b;
+		b = c;
+		}
+	k = a->k;
+	wa = a->wds;
+	wb = b->wds;
+	wc = wa + wb;
+	if (wc > a->maxwds)
+		k++;
+	c = Balloc(k);
+	if (c == NULL)
+		return (NULL);
+	for(x = c->x, xa = x + wc; x < xa; x++)
+		*x = 0;
+	xa = a->x;
+	xae = xa + wa;
+	xb = b->x;
+	xbe = xb + wb;
+	xc0 = c->x;
+#ifdef ULLong
+	for(; xb < xbe; xc0++) {
+		if ( (y = *xb++) !=0) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			do {
+				z = *x++ * (ULLong)y + *xc + carry;
+				carry = z >> 32;
+				*xc++ = z & 0xffffffffUL;
+				}
+				while(x < xae);
+			*xc = carry;
+			}
+		}
+#else
+#ifdef Pack_32
+	for(; xb < xbe; xb++, xc0++) {
+		if ( (y = *xb & 0xffff) !=0) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			do {
+				z = (*x & 0xffff) * y + (*xc & 0xffff) + carry;
+				carry = z >> 16;
+				z2 = (*x++ >> 16) * y + (*xc >> 16) + carry;
+				carry = z2 >> 16;
+				Storeinc(xc, z2, z);
+				}
+				while(x < xae);
+			*xc = carry;
+			}
+		if ( (y = *xb >> 16) !=0) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			z2 = *xc;
+			do {
+				z = (*x & 0xffff) * y + (*xc >> 16) + carry;
+				carry = z >> 16;
+				Storeinc(xc, z, z2);
+				z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry;
+				carry = z2 >> 16;
+				}
+				while(x < xae);
+			*xc = z2;
+			}
+		}
+#else
+	for(; xb < xbe; xc0++) {
+		if ( (y = *xb++) !=0) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			do {
+				z = *x++ * y + *xc + carry;
+				carry = z >> 16;
+				*xc++ = z & 0xffff;
+				}
+				while(x < xae);
+			*xc = carry;
+			}
+		}
+#endif
+#endif
+	for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ;
+	c->wds = wc;
+	return c;
+	}
+
+ static Bigint *p5s;
+
+ Bigint *
+pow5mult
+#ifdef KR_headers
+	(b, k) Bigint *b; int k;
+#else
+	(Bigint *b, int k)
+#endif
+{
+	Bigint *b1, *p5, *p51;
+	int i;
+	static int p05[3] = { 5, 25, 125 };
+
+	if ( (i = k & 3) !=0) {
+		b = multadd(b, p05[i-1], 0);
+		if (b == NULL)
+			return (NULL);
+		}
+
+	if (!(k >>= 2))
+		return b;
+	if ((p5 = p5s) == 0) {
+		/* first time */
+#ifdef MULTIPLE_THREADS
+		ACQUIRE_DTOA_LOCK(1);
+		if (!(p5 = p5s)) {
+			p5 = p5s = i2b(625);
+			if (p5 == NULL)
+				return (NULL);
+			p5->next = 0;
+			}
+		FREE_DTOA_LOCK(1);
+#else
+		p5 = p5s = i2b(625);
+		if (p5 == NULL)
+			return (NULL);
+		p5->next = 0;
+#endif
+		}
+	for(;;) {
+		if (k & 1) {
+			b1 = mult(b, p5);
+			if (b1 == NULL)
+				return (NULL);
+			Bfree(b);
+			b = b1;
+			}
+		if (!(k >>= 1))
+			break;
+		if ((p51 = p5->next) == 0) {
+#ifdef MULTIPLE_THREADS
+			ACQUIRE_DTOA_LOCK(1);
+			if (!(p51 = p5->next)) {
+				p51 = p5->next = mult(p5,p5);
+				if (p51 == NULL)
+					return (NULL);
+				p51->next = 0;
+				}
+			FREE_DTOA_LOCK(1);
+#else
+			p51 = p5->next = mult(p5,p5);
+			if (p51 == NULL)
+				return (NULL);
+			p51->next = 0;
+#endif
+			}
+		p5 = p51;
+		}
+	return b;
+	}
+
+ Bigint *
+lshift
+#ifdef KR_headers
+	(b, k) Bigint *b; int k;
+#else
+	(Bigint *b, int k)
+#endif
+{
+	int i, k1, n, n1;
+	Bigint *b1;
+	ULong *x, *x1, *xe, z;
+
+	n = k >> kshift;
+	k1 = b->k;
+	n1 = n + b->wds + 1;
+	for(i = b->maxwds; n1 > i; i <<= 1)
+		k1++;
+	b1 = Balloc(k1);
+	if (b1 == NULL)
+		return (NULL);
+	x1 = b1->x;
+	for(i = 0; i < n; i++)
+		*x1++ = 0;
+	x = b->x;
+	xe = x + b->wds;
+	if (k &= kmask) {
+#ifdef Pack_32
+		k1 = 32 - k;
+		z = 0;
+		do {
+			*x1++ = *x << k | z;
+			z = *x++ >> k1;
+			}
+			while(x < xe);
+		if ((*x1 = z) !=0)
+			++n1;
+#else
+		k1 = 16 - k;
+		z = 0;
+		do {
+			*x1++ = *x << k  & 0xffff | z;
+			z = *x++ >> k1;
+			}
+			while(x < xe);
+		if (*x1 = z)
+			++n1;
+#endif
+		}
+	else do
+		*x1++ = *x++;
+		while(x < xe);
+	b1->wds = n1 - 1;
+	Bfree(b);
+	return b1;
+	}
+
+ int
+cmp
+#ifdef KR_headers
+	(a, b) Bigint *a, *b;
+#else
+	(Bigint *a, Bigint *b)
+#endif
+{
+	ULong *xa, *xa0, *xb, *xb0;
+	int i, j;
+
+	i = a->wds;
+	j = b->wds;
+#ifdef DEBUG
+	if (i > 1 && !a->x[i-1])
+		Bug("cmp called with a->x[a->wds-1] == 0");
+	if (j > 1 && !b->x[j-1])
+		Bug("cmp called with b->x[b->wds-1] == 0");
+#endif
+	if (i -= j)
+		return i;
+	xa0 = a->x;
+	xa = xa0 + j;
+	xb0 = b->x;
+	xb = xb0 + j;
+	for(;;) {
+		if (*--xa != *--xb)
+			return *xa < *xb ? -1 : 1;
+		if (xa <= xa0)
+			break;
+		}
+	return 0;
+	}
+
+ Bigint *
+diff
+#ifdef KR_headers
+	(a, b) Bigint *a, *b;
+#else
+	(Bigint *a, Bigint *b)
+#endif
+{
+	Bigint *c;
+	int i, wa, wb;
+	ULong *xa, *xae, *xb, *xbe, *xc;
+#ifdef ULLong
+	ULLong borrow, y;
+#else
+	ULong borrow, y;
+#ifdef Pack_32
+	ULong z;
+#endif
+#endif
+
+	i = cmp(a,b);
+	if (!i) {
+		c = Balloc(0);
+		if (c == NULL)
+			return (NULL);
+		c->wds = 1;
+		c->x[0] = 0;
+		return c;
+		}
+	if (i < 0) {
+		c = a;
+		a = b;
+		b = c;
+		i = 1;
+		}
+	else
+		i = 0;
+	c = Balloc(a->k);
+	if (c == NULL)
+		return (NULL);
+	c->sign = i;
+	wa = a->wds;
+	xa = a->x;
+	xae = xa + wa;
+	wb = b->wds;
+	xb = b->x;
+	xbe = xb + wb;
+	xc = c->x;
+	borrow = 0;
+#ifdef ULLong
+	do {
+		y = (ULLong)*xa++ - *xb++ - borrow;
+		borrow = y >> 32 & 1UL;
+		*xc++ = y & 0xffffffffUL;
+		}
+		while(xb < xbe);
+	while(xa < xae) {
+		y = *xa++ - borrow;
+		borrow = y >> 32 & 1UL;
+		*xc++ = y & 0xffffffffUL;
+		}
+#else
+#ifdef Pack_32
+	do {
+		y = (*xa & 0xffff) - (*xb & 0xffff) - borrow;
+		borrow = (y & 0x10000) >> 16;
+		z = (*xa++ >> 16) - (*xb++ >> 16) - borrow;
+		borrow = (z & 0x10000) >> 16;
+		Storeinc(xc, z, y);
+		}
+		while(xb < xbe);
+	while(xa < xae) {
+		y = (*xa & 0xffff) - borrow;
+		borrow = (y & 0x10000) >> 16;
+		z = (*xa++ >> 16) - borrow;
+		borrow = (z & 0x10000) >> 16;
+		Storeinc(xc, z, y);
+		}
+#else
+	do {
+		y = *xa++ - *xb++ - borrow;
+		borrow = (y & 0x10000) >> 16;
+		*xc++ = y & 0xffff;
+		}
+		while(xb < xbe);
+	while(xa < xae) {
+		y = *xa++ - borrow;
+		borrow = (y & 0x10000) >> 16;
+		*xc++ = y & 0xffff;
+		}
+#endif
+#endif
+	while(!*--xc)
+		wa--;
+	c->wds = wa;
+	return c;
+	}
+
+ double
+b2d
+#ifdef KR_headers
+	(a, e) Bigint *a; int *e;
+#else
+	(Bigint *a, int *e)
+#endif
+{
+	ULong *xa, *xa0, w, y, z;
+	int k;
+	U d;
+#ifdef VAX
+	ULong d0, d1;
+#else
+#define d0 word0(&d)
+#define d1 word1(&d)
+#endif
+
+	xa0 = a->x;
+	xa = xa0 + a->wds;
+	y = *--xa;
+#ifdef DEBUG
+	if (!y) Bug("zero y in b2d");
+#endif
+	k = hi0bits(y);
+	*e = 32 - k;
+#ifdef Pack_32
+	if (k < Ebits) {
+		d0 = Exp_1 | y >> (Ebits - k);
+		w = xa > xa0 ? *--xa : 0;
+		d1 = y << ((32-Ebits) + k) | w >> (Ebits - k);
+		goto ret_d;
+		}
+	z = xa > xa0 ? *--xa : 0;
+	if (k -= Ebits) {
+		d0 = Exp_1 | y << k | z >> (32 - k);
+		y = xa > xa0 ? *--xa : 0;
+		d1 = z << k | y >> (32 - k);
+		}
+	else {
+		d0 = Exp_1 | y;
+		d1 = z;
+		}
+#else
+	if (k < Ebits + 16) {
+		z = xa > xa0 ? *--xa : 0;
+		d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k;
+		w = xa > xa0 ? *--xa : 0;
+		y = xa > xa0 ? *--xa : 0;
+		d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k;
+		goto ret_d;
+		}
+	z = xa > xa0 ? *--xa : 0;
+	w = xa > xa0 ? *--xa : 0;
+	k -= Ebits + 16;
+	d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k;
+	y = xa > xa0 ? *--xa : 0;
+	d1 = w << k + 16 | y << k;
+#endif
+ ret_d:
+#ifdef VAX
+	word0(&d) = d0 >> 16 | d0 << 16;
+	word1(&d) = d1 >> 16 | d1 << 16;
+#endif
+	return dval(&d);
+	}
+#undef d0
+#undef d1
+
+ Bigint *
+d2b
+#ifdef KR_headers
+	(dd, e, bits) double dd; int *e, *bits;
+#else
+	(double dd, int *e, int *bits)
+#endif
+{
+	Bigint *b;
+	U d;
+#ifndef Sudden_Underflow
+	int i;
+#endif
+	int de, k;
+	ULong *x, y, z;
+#ifdef VAX
+	ULong d0, d1;
+#else
+#define d0 word0(&d)
+#define d1 word1(&d)
+#endif
+	d.d = dd;
+#ifdef VAX
+	d0 = word0(&d) >> 16 | word0(&d) << 16;
+	d1 = word1(&d) >> 16 | word1(&d) << 16;
+#endif
+
+#ifdef Pack_32
+	b = Balloc(1);
+#else
+	b = Balloc(2);
+#endif
+	if (b == NULL)
+		return (NULL);
+	x = b->x;
+
+	z = d0 & Frac_mask;
+	d0 &= 0x7fffffff;	/* clear sign bit, which we ignore */
+#ifdef Sudden_Underflow
+	de = (int)(d0 >> Exp_shift);
+#ifndef IBM
+	z |= Exp_msk11;
+#endif
+#else
+	if ( (de = (int)(d0 >> Exp_shift)) !=0)
+		z |= Exp_msk1;
+#endif
+#ifdef Pack_32
+	if ( (y = d1) !=0) {
+		if ( (k = lo0bits(&y)) !=0) {
+			x[0] = y | z << (32 - k);
+			z >>= k;
+			}
+		else
+			x[0] = y;
+#ifndef Sudden_Underflow
+		i =
+#endif
+		     b->wds = (x[1] = z) !=0 ? 2 : 1;
+		}
+	else {
+		k = lo0bits(&z);
+		x[0] = z;
+#ifndef Sudden_Underflow
+		i =
+#endif
+		    b->wds = 1;
+		k += 32;
+		}
+#else
+	if ( (y = d1) !=0) {
+		if ( (k = lo0bits(&y)) !=0)
+			if (k >= 16) {
+				x[0] = y | z << 32 - k & 0xffff;
+				x[1] = z >> k - 16 & 0xffff;
+				x[2] = z >> k;
+				i = 2;
+				}
+			else {
+				x[0] = y & 0xffff;
+				x[1] = y >> 16 | z << 16 - k & 0xffff;
+				x[2] = z >> k & 0xffff;
+				x[3] = z >> k+16;
+				i = 3;
+				}
+		else {
+			x[0] = y & 0xffff;
+			x[1] = y >> 16;
+			x[2] = z & 0xffff;
+			x[3] = z >> 16;
+			i = 3;
+			}
+		}
+	else {
+#ifdef DEBUG
+		if (!z)
+			Bug("Zero passed to d2b");
+#endif
+		k = lo0bits(&z);
+		if (k >= 16) {
+			x[0] = z;
+			i = 0;
+			}
+		else {
+			x[0] = z & 0xffff;
+			x[1] = z >> 16;
+			i = 1;
+			}
+		k += 32;
+		}
+	while(!x[i])
+		--i;
+	b->wds = i + 1;
+#endif
+#ifndef Sudden_Underflow
+	if (de) {
+#endif
+#ifdef IBM
+		*e = (de - Bias - (P-1) << 2) + k;
+		*bits = 4*P + 8 - k - hi0bits(word0(&d) & Frac_mask);
+#else
+		*e = de - Bias - (P-1) + k;
+		*bits = P - k;
+#endif
+#ifndef Sudden_Underflow
+		}
+	else {
+		*e = de - Bias - (P-1) + 1 + k;
+#ifdef Pack_32
+		*bits = 32*i - hi0bits(x[i-1]);
+#else
+		*bits = (i+2)*16 - hi0bits(x[i]);
+#endif
+		}
+#endif
+	return b;
+	}
+#undef d0
+#undef d1
+
+ CONST double
+#ifdef IEEE_Arith
+bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };
+CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, 1e-256
+		};
+#else
+#ifdef IBM
+bigtens[] = { 1e16, 1e32, 1e64 };
+CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 };
+#else
+bigtens[] = { 1e16, 1e32 };
+CONST double tinytens[] = { 1e-16, 1e-32 };
+#endif
+#endif
+
+ CONST double
+tens[] = {
+		1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+		1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+		1e20, 1e21, 1e22
+#ifdef VAX
+		, 1e23, 1e24
+#endif
+		};
+
+#ifdef NO_STRING_H
+
+ char *
+#ifdef KR_headers
+strcp_D2A(a, b) char *a; char *b;
+#else
+strcp_D2A(char *a, CONST char *b)
+#endif
+{
+	while((*a = *b++))
+		a++;
+	return a;
+	}
+
+ Char *
+#ifdef KR_headers
+memcpy_D2A(a, b, len) Char *a; Char *b; size_t len;
+#else
+memcpy_D2A(void *a1, void *b1, size_t len)
+#endif
+{
+	char *a = (char*)a1, *ae = a + len;
+	char *b = (char*)b1, *a0 = a;
+	while(a < ae)
+		*a++ = *b++;
+	return a0;
+	}
+
+#endif /* NO_STRING_H */
diff --git a/newlib/libc/stdlib/gdtoa.h b/newlib/libc/stdlib/gdtoa.h
index 07506aac1..4f26d8857 100644
--- a/newlib/libc/stdlib/gdtoa.h
+++ b/newlib/libc/stdlib/gdtoa.h
@@ -32,25 +32,61 @@ THIS SOFTWARE.
 #ifndef GDTOA_H_INCLUDED
 #define GDTOA_H_INCLUDED
 
+#include "arith.h"
+#include <stddef.h> /* for size_t */
+
+#define PROTO_NORMAL(x)
+#define __BEGIN_HIDDEN_DECLS
+#define __END_HIDDEN_DECLS
+#define DEF_STRONG(x)
+
+#ifndef Long
+#define Long int
+#endif
+#ifndef ULong
+typedef unsigned Long ULong;
+#endif
+#ifndef UShort
+typedef unsigned short UShort;
+#endif
+
+#ifndef ANSI
+#ifdef KR_headers
+#define ANSI(x) ()
+#define Void /*nothing*/
+#else
+#define ANSI(x) x
+#define Void void
+#endif
+#endif /* ANSI */
+
+#ifndef CONST
+#ifdef KR_headers
+#define CONST /* blank */
+#else
+#define CONST const
+#endif
+#endif /* CONST */
 
  enum {	/* return values from strtodg */
-	STRTOG_Zero	= 0,
-	STRTOG_Normal	= 1,
-	STRTOG_Denormal	= 2,
-	STRTOG_Infinite	= 3,
-	STRTOG_NaN	= 4,
-	STRTOG_NaNbits	= 5,
-	STRTOG_NoNumber	= 6,
-	STRTOG_Retmask	= 7,
+	STRTOG_Zero	= 0x000,
+	STRTOG_Normal	= 0x001,
+	STRTOG_Denormal	= 0x002,
+	STRTOG_Infinite	= 0x003,
+	STRTOG_NaN	= 0x004,
+	STRTOG_NaNbits	= 0x005,
+	STRTOG_NoNumber	= 0x006,
+	STRTOG_NoMemory = 0x007,
+	STRTOG_Retmask	= 0x00f,
 
 	/* The following may be or-ed into one of the above values. */
 
-	STRTOG_Neg	= 0x08,
-	STRTOG_Inexlo	= 0x10,
-	STRTOG_Inexhi	= 0x20,
-	STRTOG_Inexact	= 0x30,
-	STRTOG_Underflow= 0x40,
-	STRTOG_Overflow	= 0x80
+	STRTOG_Inexlo	= 0x010, /* returned result rounded toward zero */
+	STRTOG_Inexhi	= 0x020, /* returned result rounded away from zero */
+	STRTOG_Inexact	= 0x030,
+	STRTOG_Underflow= 0x040,
+	STRTOG_Overflow	= 0x080,
+	STRTOG_Neg	= 0x100 /* does not affect STRTOG_Inexlo or STRTOG_Inexhi */
 	};
 
  typedef struct
@@ -69,6 +105,70 @@ enum {	/* FPI.rounding values: same as FLT_ROUNDS */
 	FPI_Round_down = 3
 	};
 
-#endif /* GDTOA_H_INCLUDED */
-
 typedef unsigned short __UShort;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char* __dtoa  ANSI((double d, int mode, int ndigits, int *decpt,
+			int *sign, char **rve));
+extern char* __gdtoa ANSI((FPI *fpi, int be, ULong *bits, int *kindp,
+			int mode, int ndigits, int *decpt, char **rve));
+extern void __freedtoa ANSI((char*));
+extern float  strtof ANSI((CONST char *, char **));
+extern double strtod ANSI((CONST char *, char **));
+extern int __strtodg ANSI((CONST char*, char**, FPI*, Long*, ULong*));
+char	*__hdtoa(double, const char *, int, int *, int *, char **);
+char	*__hldtoa(long double, const char *, int, int *, int *, char **);
+char	*__ldtoa(long double *, int, int, int *, int *, char **);
+
+PROTO_NORMAL(__dtoa);
+PROTO_NORMAL(__gdtoa);
+PROTO_NORMAL(__freedtoa);
+PROTO_NORMAL(__hdtoa);
+PROTO_NORMAL(__hldtoa);
+PROTO_NORMAL(__ldtoa);
+
+__BEGIN_HIDDEN_DECLS
+extern char*	__g_ddfmt  ANSI((char*, double*, int, size_t));
+extern char*	__g_dfmt   ANSI((char*, double*, int, size_t));
+extern char*	__g_ffmt   ANSI((char*, float*,  int, size_t));
+extern char*	__g_Qfmt   ANSI((char*, void*,   int, size_t));
+extern char*	__g_xfmt   ANSI((char*, void*,   int, size_t));
+extern char*	__g_xLfmt  ANSI((char*, void*,   int, size_t));
+
+extern int	__strtoId  ANSI((CONST char*, char**, double*, double*));
+extern int	__strtoIdd ANSI((CONST char*, char**, double*, double*));
+extern int	__strtoIf  ANSI((CONST char*, char**, float*, float*));
+extern int	__strtoIQ  ANSI((CONST char*, char**, void*, void*));
+extern int	__strtoIx  ANSI((CONST char*, char**, void*, void*));
+extern int	__strtoIxL ANSI((CONST char*, char**, void*, void*));
+extern int	__strtord  ANSI((CONST char*, char**, int, double*));
+extern int	__strtordd ANSI((CONST char*, char**, int, double*));
+extern int	__strtorf  ANSI((CONST char*, char**, int, float*));
+extern int	__strtorQ  ANSI((CONST char*, char**, int, void*));
+extern int	__strtorx  ANSI((CONST char*, char**, int, void*));
+extern int	__strtorxL ANSI((CONST char*, char**, int, void*));
+#if 1
+extern int	__strtodI  ANSI((CONST char*, char**, double*));
+extern int	__strtopd  ANSI((CONST char*, char**, double*));
+extern int	__strtopdd ANSI((CONST char*, char**, double*));
+extern int	__strtopf  ANSI((CONST char*, char**, float*));
+extern int	__strtopQ  ANSI((CONST char*, char**, void*));
+extern int	__strtopx  ANSI((CONST char*, char**, void*));
+extern int	__strtopxL ANSI((CONST char*, char**, void*));
+#else
+#define __strtopd(s,se,x) strtord(s,se,1,x)
+#define __strtopdd(s,se,x) strtordd(s,se,1,x)
+#define __strtopf(s,se,x) strtorf(s,se,1,x)
+#define __strtopQ(s,se,x) strtorQ(s,se,1,x)
+#define __strtopx(s,se,x) strtorx(s,se,1,x)
+#define __strtopxL(s,se,x) strtorxL(s,se,1,x)
+#endif
+__END_HIDDEN_DECLS
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* GDTOA_H_INCLUDED */
diff --git a/newlib/libc/stdlib/gdtoaimp.h b/newlib/libc/stdlib/gdtoaimp.h
new file mode 100644
index 000000000..bf9770955
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoaimp.h
@@ -0,0 +1,672 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998-2000 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* This is a variation on dtoa.c that converts arbitary binary
+   floating-point formats to and from decimal notation.  It uses
+   double-precision arithmetic internally, so there are still
+   various #ifdefs that adapt the calculations to the native
+   double-precision arithmetic (any of IEEE, VAX D_floating,
+   or IBM mainframe arithmetic).
+
+   Please send bug reports to David M. Gay (dmg at acm dot org,
+   with " at " changed at "@" and " dot " changed to ".").
+ */
+
+/* On a machine with IEEE extended-precision registers, it is
+ * necessary to specify double-precision (53-bit) rounding precision
+ * before invoking strtod or dtoa.  If the machine uses (the equivalent
+ * of) Intel 80x87 arithmetic, the call
+ *	_control87(PC_53, MCW_PC);
+ * does this with many compilers.  Whether this or another call is
+ * appropriate depends on the compiler; for this to work, it may be
+ * necessary to #include "float.h" or another system-dependent header
+ * file.
+ */
+
+/* strtod for IEEE-, VAX-, and IBM-arithmetic machines.
+ *
+ * This strtod returns a nearest machine number to the input decimal
+ * string (or sets errno to ERANGE).  With IEEE arithmetic, ties are
+ * broken by the IEEE round-even rule.  Otherwise ties are broken by
+ * biased rounding (add half and chop).
+ *
+ * Inspired loosely by William D. Clinger's paper "How to Read Floating
+ * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ *
+ *	1. We only require IEEE, IBM, or VAX double-precision
+ *		arithmetic (not IEEE double-extended).
+ *	2. We get by with floating-point arithmetic in a case that
+ *		Clinger missed -- when we're computing d * 10^n
+ *		for a small integer d and the integer n is not too
+ *		much larger than 22 (the maximum integer k for which
+ *		we can represent 10^k exactly), we may be able to
+ *		compute (d*10^k) * 10^(e-k) with just one roundoff.
+ *	3. Rather than a bit-at-a-time adjustment of the binary
+ *		result in the hard case, we use floating-point
+ *		arithmetic to determine the adjustment to within
+ *		one bit; only in really hard cases do we need to
+ *		compute a second residual.
+ *	4. Because of 3., we don't need a large table of powers of 10
+ *		for ten-to-e (just some small tables, e.g. of 10^k
+ *		for 0 <= k <= 22).
+ */
+
+/*
+ * #define IEEE_8087 for IEEE-arithmetic machines where the least
+ *	significant byte has the lowest address.
+ * #define IEEE_MC68k for IEEE-arithmetic machines where the most
+ *	significant byte has the lowest address.
+ * #define Long int on machines with 32-bit ints and 64-bit longs.
+ * #define Sudden_Underflow for IEEE-format machines without gradual
+ *	underflow (i.e., that flush to zero on underflow).
+ * #define IBM for IBM mainframe-style floating-point arithmetic.
+ * #define VAX for VAX-style floating-point arithmetic (D_floating).
+ * #define No_leftright to omit left-right logic in fast floating-point
+ *	computation of dtoa and gdtoa.  This will cause modes 4 and 5 to be
+ *	treated the same as modes 2 and 3 for some inputs.
+ * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3.
+ * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines
+ *	that use extended-precision instructions to compute rounded
+ *	products and quotients) with IBM.
+ * #define ROUND_BIASED for IEEE-format with biased rounding and arithmetic
+ *	that rounds toward +Infinity.
+ * #define ROUND_BIASED_without_Round_Up for IEEE-format with biased
+ *	rounding when the underlying floating-point arithmetic uses
+ *	unbiased rounding.  This prevent using ordinary floating-point
+ *	arithmetic when the result could be computed with one rounding error.
+ * #define Inaccurate_Divide for IEEE-format with correctly rounded
+ *	products but inaccurate quotients, e.g., for Intel i860.
+ * #define NO_LONG_LONG on machines that do not have a "long long"
+ *	integer type (of >= 64 bits).  On such machines, you can
+ *	#define Just_16 to store 16 bits per 32-bit Long when doing
+ *	high-precision integer arithmetic.  Whether this speeds things
+ *	up or slows things down depends on the machine and the number
+ *	being converted.  If long long is available and the name is
+ *	something other than "long long", #define Llong to be the name,
+ *	and if "unsigned Llong" does not work as an unsigned version of
+ *	Llong, #define #ULLong to be the corresponding unsigned type.
+ * #define KR_headers for old-style C function headers.
+ * #define Bad_float_h if your system lacks a float.h or if it does not
+ *	define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP,
+ *	FLT_RADIX, FLT_ROUNDS, and DBL_MAX.
+ * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n)
+ *	if memory is available and otherwise does something you deem
+ *	appropriate.  If MALLOC is undefined, malloc will be invoked
+ *	directly -- and assumed always to succeed.  Similarly, if you
+ *	want something other than the system's free() to be called to
+ *	recycle memory acquired from MALLOC, #define FREE to be the
+ *	name of the alternate routine.  (FREE or free is only called in
+ *	pathological cases, e.g., in a gdtoa call after a gdtoa return in
+ *	mode 3 with thousands of digits requested.)
+ * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making
+ *	memory allocations from a private pool of memory when possible.
+ *	When used, the private pool is PRIVATE_MEM bytes long:  2304 bytes,
+ *	unless #defined to be a different length.  This default length
+ *	suffices to get rid of MALLOC calls except for unusual cases,
+ *	such as decimal-to-binary conversion of a very long string of
+ *	digits.  When converting IEEE double precision values, the
+ *	longest string gdtoa can return is about 751 bytes long.  For
+ *	conversions by strtod of strings of 800 digits and all gdtoa
+ *	conversions of IEEE doubles in single-threaded executions with
+ *	8-byte pointers, PRIVATE_MEM >= 7400 appears to suffice; with
+ *	4-byte pointers, PRIVATE_MEM >= 7112 appears adequate.
+ * #define NO_INFNAN_CHECK if you do not wish to have INFNAN_CHECK
+ *	#defined automatically on IEEE systems.  On such systems,
+ *	when INFNAN_CHECK is #defined, strtod checks
+ *	for Infinity and NaN (case insensitively).
+ *	When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined,
+ *	strtodg also accepts (case insensitively) strings of the form
+ *	NaN(x), where x is a string of hexadecimal digits (optionally
+ *	preceded by 0x or 0X) and spaces; if there is only one string
+ *	of hexadecimal digits, it is taken for the fraction bits of the
+ *	resulting NaN; if there are two or more strings of hexadecimal
+ *	digits, each string is assigned to the next available sequence
+ *	of 32-bit words of fractions bits (starting with the most
+ *	significant), right-aligned in each sequence.
+ *	Unless GDTOA_NON_PEDANTIC_NANCHECK is #defined, input "NaN(...)"
+ *	is consumed even when ... has the wrong form (in which case the
+ *	"(...)" is consumed but ignored).
+ * #define MULTIPLE_THREADS if the system offers preemptively scheduled
+ *	multiple threads.  In this case, you must provide (or suitably
+ *	#define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed
+ *	by FREE_DTOA_LOCK(n) for n = 0 or 1.  (The second lock, accessed
+ *	in pow5mult, ensures lazy evaluation of only one copy of high
+ *	powers of 5; omitting this lock would introduce a small
+ *	probability of wasting memory, but would otherwise be harmless.)
+ *	You must also invoke freedtoa(s) to free the value s returned by
+ *	dtoa.  You may do so whether or not MULTIPLE_THREADS is #defined.
+ * #define IMPRECISE_INEXACT if you do not care about the setting of
+ *	the STRTOG_Inexact bits in the special case of doing IEEE double
+ *	precision conversions (which could also be done by the strtod in
+ *	dtoa.c).
+ * #define NO_HEX_FP to disable recognition of C9x's hexadecimal
+ *	floating-point constants.
+ * #define -DNO_ERRNO to suppress setting errno (in strtod.c and
+ *	strtodg.c).
+ * #define NO_STRING_H to use private versions of memcpy.
+ *	On some K&R systems, it may also be necessary to
+ *	#define DECLARE_SIZE_T in this case.
+ * #define USE_LOCALE to use the current locale's decimal_point value.
+ */
+
+#ifndef GDTOAIMP_H_INCLUDED
+#define GDTOAIMP_H_INCLUDED
+#include "gdtoa.h"
+#if 0
+#include "gd_qnan.h"
+#endif
+#ifdef Honor_FLT_ROUNDS
+#include <fenv.h>
+#endif
+
+#ifdef DEBUG
+#include "stdio.h"
+#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);}
+#endif
+
+#include "stdlib.h"
+#include "string.h"
+
+#ifdef KR_headers
+#define Char char
+#else
+#define Char void
+#endif
+
+#ifdef MALLOC
+extern Char *MALLOC ANSI((size_t));
+#else
+#define MALLOC(x) _malloc_r(_REENT, x)
+#endif
+#define FREE(x) _free_r(_REENT, x)
+
+#undef IEEE_Arith
+#undef Avoid_Underflow
+#ifdef IEEE_MC68k
+#define IEEE_Arith
+#endif
+#ifdef IEEE_8087
+#define IEEE_Arith
+#endif
+
+#include "errno.h"
+#ifdef Bad_float_h
+
+#ifdef IEEE_Arith
+#define DBL_DIG 15
+#define DBL_MAX_10_EXP 308
+#define DBL_MAX_EXP 1024
+#define FLT_RADIX 2
+#define DBL_MAX 1.7976931348623157e+308
+#endif
+
+#ifdef IBM
+#define DBL_DIG 16
+#define DBL_MAX_10_EXP 75
+#define DBL_MAX_EXP 63
+#define FLT_RADIX 16
+#define DBL_MAX 7.2370055773322621e+75
+#endif
+
+#ifdef VAX
+#define DBL_DIG 16
+#define DBL_MAX_10_EXP 38
+#define DBL_MAX_EXP 127
+#define FLT_RADIX 2
+#define DBL_MAX 1.7014118346046923e+38
+#define n_bigtens 2
+#endif
+
+#ifndef LONG_MAX
+#define LONG_MAX 2147483647
+#endif
+
+#else /* ifndef Bad_float_h */
+#include "float.h"
+#endif /* Bad_float_h */
+
+#ifdef IEEE_Arith
+#define Scale_Bit 0x10
+#define n_bigtens 5
+#endif
+
+#ifdef IBM
+#define n_bigtens 3
+#endif
+
+#ifdef VAX
+#define n_bigtens 2
+#endif
+
+#ifndef __MATH_H__
+#include "math.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1
+Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined.
+#endif
+
+typedef union { double d; ULong L[2]; } U;
+
+#ifdef IEEE_8087
+#define word0(x) (x)->L[1]
+#define word1(x) (x)->L[0]
+#else
+#define word0(x) (x)->L[0]
+#define word1(x) (x)->L[1]
+#endif
+#define dval(x) (x)->d
+
+/* The following definition of Storeinc is appropriate for MIPS processors.
+ * An alternative that might be better on some machines is
+ * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff)
+ */
+#if defined(IEEE_8087) + defined(VAX)
+#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \
+((unsigned short *)a)[0] = (unsigned short)c, a++)
+#else
+#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \
+((unsigned short *)a)[1] = (unsigned short)c, a++)
+#endif
+
+/* #define P DBL_MANT_DIG */
+/* Ten_pmax = floor(P*log(2)/log(5)) */
+/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */
+/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */
+/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */
+
+#ifdef IEEE_Arith
+#define Exp_shift  20
+#define Exp_shift1 20
+#define Exp_msk1    0x100000
+#define Exp_msk11   0x100000
+#define Exp_mask  0x7ff00000
+#define P 53
+#define Bias 1023
+#define Emin (-1022)
+#define Exp_1  0x3ff00000
+#define Exp_11 0x3ff00000
+#define Ebits 11
+#define Frac_mask  0xfffff
+#define Frac_mask1 0xfffff
+#define Ten_pmax 22
+#define Bletch 0x10
+#define Bndry_mask  0xfffff
+#define Bndry_mask1 0xfffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 1
+#define Tiny0 0
+#define Tiny1 1
+#define Quick_max 14
+#define Int_max 14
+
+#ifndef Flt_Rounds
+#ifdef FLT_ROUNDS
+#define Flt_Rounds FLT_ROUNDS
+#else
+#define Flt_Rounds 1
+#endif
+#endif /*Flt_Rounds*/
+
+#else /* ifndef IEEE_Arith */
+#undef  Sudden_Underflow
+#define Sudden_Underflow
+#ifdef IBM
+#undef Flt_Rounds
+#define Flt_Rounds 0
+#define Exp_shift  24
+#define Exp_shift1 24
+#define Exp_msk1   0x1000000
+#define Exp_msk11  0x1000000
+#define Exp_mask  0x7f000000
+#define P 14
+#define Bias 65
+#define Exp_1  0x41000000
+#define Exp_11 0x41000000
+#define Ebits 8	/* exponent has 7 bits, but 8 is the right value in b2d */
+#define Frac_mask  0xffffff
+#define Frac_mask1 0xffffff
+#define Bletch 4
+#define Ten_pmax 22
+#define Bndry_mask  0xefffff
+#define Bndry_mask1 0xffffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 4
+#define Tiny0 0x100000
+#define Tiny1 0
+#define Quick_max 14
+#define Int_max 15
+#else /* VAX */
+#undef Flt_Rounds
+#define Flt_Rounds 1
+#define Exp_shift  23
+#define Exp_shift1 7
+#define Exp_msk1    0x80
+#define Exp_msk11   0x800000
+#define Exp_mask  0x7f80
+#define P 56
+#define Bias 129
+#define Emin (-127)
+#define Exp_1  0x40800000
+#define Exp_11 0x4080
+#define Ebits 8
+#define Frac_mask  0x7fffff
+#define Frac_mask1 0xffff007f
+#define Ten_pmax 24
+#define Bletch 2
+#define Bndry_mask  0xffff007f
+#define Bndry_mask1 0xffff007f
+#define LSB 0x10000
+#define Sign_bit 0x8000
+#define Log2P 1
+#define Tiny0 0x80
+#define Tiny1 0
+#define Quick_max 15
+#define Int_max 15
+#endif /* IBM, VAX */
+#endif /* IEEE_Arith */
+
+#ifndef IEEE_Arith
+#define ROUND_BIASED
+#else
+#ifdef ROUND_BIASED_without_Round_Up
+#undef  ROUND_BIASED
+#define ROUND_BIASED
+#endif
+#endif
+
+#ifdef RND_PRODQUOT
+#define rounded_product(a,b) a = rnd_prod(a, b)
+#define rounded_quotient(a,b) a = rnd_quot(a, b)
+#ifdef KR_headers
+extern double rnd_prod(), rnd_quot();
+#else
+extern double rnd_prod(double, double), rnd_quot(double, double);
+#endif
+#else
+#define rounded_product(a,b) a *= b
+#define rounded_quotient(a,b) a /= b
+#endif
+
+#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1))
+#define Big1 0xffffffff
+
+#undef  Pack_16
+#ifndef Pack_32
+#define Pack_32
+#endif
+
+#ifdef NO_LONG_LONG
+#undef ULLong
+#ifdef Just_16
+#undef Pack_32
+#define Pack_16
+/* When Pack_32 is not defined, we store 16 bits per 32-bit Long.
+ * This makes some inner loops simpler and sometimes saves work
+ * during multiplications, but it often seems to make things slightly
+ * slower.  Hence the default is now to store 32 bits per Long.
+ */
+#endif
+#else	/* long long available */
+#ifndef Llong
+#define Llong long long
+#endif
+#ifndef ULLong
+#define ULLong unsigned Llong
+#endif
+#endif /* NO_LONG_LONG */
+
+#ifdef Pack_32
+#define ULbits 32
+#define kshift 5
+#define kmask 31
+#define ALL_ON 0xffffffff
+#else
+#define ULbits 16
+#define kshift 4
+#define kmask 15
+#define ALL_ON 0xffff
+#endif
+
+#ifndef __SINGLE_THREAD__
+#define MULTIPLE_THREADS
+#endif
+
+#ifndef MULTIPLE_THREADS
+#define ACQUIRE_DTOA_LOCK(n)	/*nothing*/
+#define FREE_DTOA_LOCK(n)	/*nothing*/
+#else
+#include <sys/lock.h>
+#define ACQUIRE_DTOA_LOCK(n) \
+	n ? __lock_acquire(__dtoa_lock1) : __lock_acquire(__dtoa_lock0)
+#define FREE_DTOA_LOCK(n) \
+	n ? __lock_release(__dtoa_lock1) : __lock_release(__dtoa_lock0)
+#endif
+
+#define Kmax 9
+
+ struct
+Bigint {
+	struct Bigint *next;
+	int k, maxwds, sign, wds;
+	ULong x[1];
+	};
+
+ typedef struct Bigint Bigint;
+
+#ifdef NO_STRING_H
+#ifdef DECLARE_SIZE_T
+typedef unsigned int size_t;
+#endif
+extern void memcpy_D2A ANSI((void*, const void*, size_t));
+#define Bcopy(x,y) memcpy_D2A(&x->sign,&y->sign,y->wds*sizeof(ULong) + 2*sizeof(int))
+#else /* !NO_STRING_H */
+#define Bcopy(x,y) memcpy(&x->sign,&y->sign,y->wds*sizeof(ULong) + 2*sizeof(int))
+#endif /* NO_STRING_H */
+
+#define dtoa __dtoa
+#define gdtoa __gdtoa
+#define freedtoa __freedtoa
+#define strtodg __strtodg
+#define g_ddfmt __g_ddfmt
+#define g_dfmt __g_dfmt
+#define g_ffmt __g_ffmt
+#define g_Qfmt __g_Qfmt
+#define g_xfmt __g_xfmt
+#define g_xLfmt __g_xLfmt
+#define strtoId __strtoId
+#define strtoIdd __strtoIdd
+#define strtoIf __strtoIf
+#define strtoIQ __strtoIQ
+#define strtoIx __strtoIx
+#define strtoIxL __strtoIxL
+#define strtord __strtord
+#define strtordd __strtordd
+#define strtorf __strtorf
+#define strtorQ __strtorQ
+#define strtorx __strtorx
+#define strtorxL __strtorxL
+#define strtodI __strtodI
+#define strtopd __strtopd
+#define strtopdd __strtopdd
+#define strtopf __strtopf
+#define strtopQ __strtopQ
+#define strtopx __strtopx
+#define strtopxL __strtopxL
+
+#define Balloc __Balloc_D2A
+#define Bfree __Bfree_D2A
+#define ULtoQ __ULtoQ_D2A
+#define ULtof __ULtof_D2A
+#define ULtod __ULtod_D2A
+#define ULtodd __ULtodd_D2A
+#define ULtox __ULtox_D2A
+#define ULtoxL __ULtoxL_D2A
+#define any_on __any_on_D2A
+#define b2d __b2d_D2A
+#define bigtens __bigtens_D2A
+#define cmp __cmp_D2A
+#define copybits __copybits_D2A
+#define d2b __d2b_D2A
+#define decrement __decrement_D2A
+#define diff __diff_D2A
+#define dtoa_result __dtoa_result_D2A
+#define g__fmt __g__fmt_D2A
+#define gethex __gethex_D2A
+#define hexdig __hexdig_D2A
+#define hexnan __hexnan_D2A
+#define hi0bits(x) __hi0bits_D2A((ULong)(x))
+#define hi0bits_D2A __hi0bits_D2A
+#define i2b __i2b_D2A
+#define increment __increment_D2A
+#define lo0bits __lo0bits_D2A
+#define lshift __lshift_D2A
+#define match __match_D2A
+#define mult __mult_D2A
+#define multadd __multadd_D2A
+#define nrv_alloc __nrv_alloc_D2A
+#define pow5mult __pow5mult_D2A
+#define quorem __quorem_D2A
+#define ratio __ratio_D2A
+#define rshift __rshift_D2A
+#define rv_alloc __rv_alloc_D2A
+#define s2b __s2b_D2A
+#define set_ones __set_ones_D2A
+#define strcp __strcp_D2A
+#define strtoIg __strtoIg_D2A
+#define sulp __sulp_D2A
+#define sum __sum_D2A
+#define tens __tens_D2A
+#define tinytens __tinytens_D2A
+#define tinytens __tinytens_D2A
+#define trailz __trailz_D2A
+#define ulp __ulp_D2A
+
+__BEGIN_HIDDEN_DECLS
+ extern char *dtoa_result;
+ extern CONST double bigtens[], tens[], tinytens[];
+ extern unsigned char hexdig[];
+
+ extern Bigint *Balloc ANSI((int));
+ extern void Bfree ANSI((Bigint*));
+ extern void ULtof ANSI((ULong*, ULong*, Long, int));
+ extern void ULtod ANSI((ULong*, ULong*, Long, int));
+ extern void ULtodd ANSI((ULong*, ULong*, Long, int));
+ extern void ULtoQ ANSI((ULong*, ULong*, Long, int));
+ extern void ULtox ANSI((UShort*, ULong*, Long, int));
+ extern void ULtoxL ANSI((ULong*, ULong*, Long, int));
+ extern ULong any_on ANSI((Bigint*, int));
+ extern double b2d ANSI((Bigint*, int*));
+ extern int cmp ANSI((Bigint*, Bigint*));
+ extern void copybits ANSI((ULong*, int, Bigint*));
+ extern Bigint *d2b ANSI((double, int*, int*));
+ extern void decrement ANSI((Bigint*));
+ extern Bigint *diff ANSI((Bigint*, Bigint*));
+ extern char *g__fmt ANSI((char*, char*, char*, int, ULong, size_t));
+ extern int gethex ANSI((CONST char**, FPI*, Long*, Bigint**, int));
+ extern void __hexdig_init_D2A(Void);
+ extern int hexnan ANSI((CONST char**, FPI*, ULong*));
+ extern int hi0bits_D2A ANSI((ULong));
+ extern Bigint *i2b ANSI((int));
+ extern Bigint *increment ANSI((Bigint*));
+ extern int lo0bits ANSI((ULong*));
+ extern Bigint *lshift ANSI((Bigint*, int));
+ extern int match ANSI((CONST char**, char*));
+ extern Bigint *mult ANSI((Bigint*, Bigint*));
+ extern Bigint *multadd ANSI((Bigint*, int, int));
+ extern char *nrv_alloc ANSI((char*, char **, int));
+ extern Bigint *pow5mult ANSI((Bigint*, int));
+ extern int quorem ANSI((Bigint*, Bigint*));
+ extern double ratio ANSI((Bigint*, Bigint*));
+ extern void rshift ANSI((Bigint*, int));
+ extern char *rv_alloc ANSI((int));
+ extern Bigint *s2b ANSI((CONST char*, int, int, ULong, int));
+ extern Bigint *set_ones ANSI((Bigint*, int));
+ extern char *strcp ANSI((char*, const char*));
+ extern int strtoIg ANSI((CONST char*, char**, FPI*, Long*, Bigint**, int*));
+ extern Bigint *sum ANSI((Bigint*, Bigint*));
+ extern int trailz ANSI((Bigint*));
+ extern double ulp ANSI((U*));
+__END_HIDDEN_DECLS
+
+#ifdef __cplusplus
+}
+#endif
+/*
+ * NAN_WORD0 and NAN_WORD1 are only referenced in strtod.c.  Prior to
+ * 20050115, they used to be hard-wired here (to 0x7ff80000 and 0,
+ * respectively), but now are determined by compiling and running
+ * qnan.c to generate gd_qnan.h, which specifies d_QNAN0 and d_QNAN1.
+ * Formerly gdtoaimp.h recommended supplying suitable -DNAN_WORD0=...
+ * and -DNAN_WORD1=...  values if necessary.  This should still work.
+ * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.)
+ */
+#ifdef IEEE_Arith
+#ifndef NO_INFNAN_CHECK
+#undef INFNAN_CHECK
+#define INFNAN_CHECK
+#endif
+#ifdef IEEE_MC68k
+#define _0 0
+#define _1 1
+#ifndef NAN_WORD0
+#define NAN_WORD0 d_QNAN0
+#endif
+#ifndef NAN_WORD1
+#define NAN_WORD1 d_QNAN1
+#endif
+#else
+#define _0 1
+#define _1 0
+#ifndef NAN_WORD0
+#define NAN_WORD0 d_QNAN1
+#endif
+#ifndef NAN_WORD1
+#define NAN_WORD1 d_QNAN0
+#endif
+#endif
+#else
+#undef INFNAN_CHECK
+#endif
+
+#undef SI
+#ifdef Sudden_Underflow
+#define SI 1
+#else
+#define SI 0
+#endif
+
+#endif /* GDTOAIMP_H_INCLUDED */
diff --git a/newlib/libc/stdlib/ldtoa.c b/newlib/libc/stdlib/ldtoa.c
index 26c61948b..fbbd3d0b1 100644
--- a/newlib/libc/stdlib/ldtoa.c
+++ b/newlib/libc/stdlib/ldtoa.c
@@ -7,6 +7,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include "mprec.h"
+#include "gdtoa.h"
 
 /* These are the externally visible entries. */
 /* linux name:  long double _IO_strtold (char *, char **); */
@@ -2814,6 +2815,12 @@ _ldtoa_r (struct _reent *ptr, long double d, int mode, int ndigits,
       _REENT_MP_RESULT (ptr) = 0;
     }
 
+  /* Use the result of gdtoa if successfull. */
+  outstr = __ldtoa (&d, mode, ndigits, decpt, sign, rve);
+  /* If it fails, fallback to legacy ldtoa. */
+  if (outstr)
+    return outstr;
+
 #if LDBL_MANT_DIG == 24
   e24toe (&du.pe, e, ldp);
 #elif LDBL_MANT_DIG == 53
-- 
2.33.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed value is incorrectly rounded
  2021-11-28  7:43     ` Takashi Yano
@ 2021-11-28 12:38       ` Takashi Yano
  2021-11-28 13:16         ` Takashi Yano
  0 siblings, 1 reply; 25+ messages in thread
From: Takashi Yano @ 2021-11-28 12:38 UTC (permalink / raw)
  To: newlib

On Sun, 28 Nov 2021 16:43:11 +0900
Takashi Yano wrote:
> On Thu, 4 Nov 2021 13:24:42 +0100
> Corinna Vinschen wrote:
> > However, a much better fix would be to switch to gdtoa, as the BSDs and
> > Mingw64 do.
> 
> I have tried to import gdtoa into newlib from OpenBSD.
> 
> gdtoa seems to use malloc much, so it may not work in some of
> platforms due to insufficient heap. Therefore, new ldtoa.c tries
> gdtoa first and fallbacks to legacy ldtoa if gdtoa fails.
> 
> To import gdtoa to newlib, I did:
> 1) Create "machine/ieee.h" which conditionally defines ieee_ext
>    structure and EXT_TO_ARRAY32() macro depend on architecture.
> 2) Create arith.h which reflects endian of architecture.
> 3) Merge gdtoa.h with OpenBSD's gdtoa.h. __BEGIN_HIDDEN_DECLS,
>    __END_HIDDEN_DECLS, PROTO_NORMAL() and DEF_STRONG() are
>    defined as dummy in this header.
> 4) Replace malloc()/free() with _malloc_r()/_free_r().
> 5) Implement ACQUIRE_DTOA_LOCK() and FREE_DTOA_LOCK() macros
>    using "sys/lock.h" for multi-threading environment.
> 6) Remove inclusion of "gd_qnan.h" which is not used.
> 
> Please see attached patch for more details.
> 
> I confirmed this works nicely with cygwin. Moreover, it is much
> faster than legacy ldtoa (more than 4 times faster).
> 
> However, this may break some other supported platforms.
> 
> Could anyone please check this?

Ah, in "machine/ieee.h", struct ieee_ext definition for
LDBL_MANT_DIG==64 and __IEEE_BIG_ENDIAN case, is obviously
wrong. 

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed value is incorrectly rounded
  2021-11-28 12:38       ` Takashi Yano
@ 2021-11-28 13:16         ` Takashi Yano
  2021-11-29 10:56           ` Takashi Yano
  0 siblings, 1 reply; 25+ messages in thread
From: Takashi Yano @ 2021-11-28 13:16 UTC (permalink / raw)
  To: newlib

[-- Attachment #1: Type: text/plain, Size: 1667 bytes --]

On Sun, 28 Nov 2021 21:38:39 +0900
Takashi Yano wrote:
> On Sun, 28 Nov 2021 16:43:11 +0900
> Takashi Yano wrote:
> > On Thu, 4 Nov 2021 13:24:42 +0100
> > Corinna Vinschen wrote:
> > > However, a much better fix would be to switch to gdtoa, as the BSDs and
> > > Mingw64 do.
> > 
> > I have tried to import gdtoa into newlib from OpenBSD.
> > 
> > gdtoa seems to use malloc much, so it may not work in some of
> > platforms due to insufficient heap. Therefore, new ldtoa.c tries
> > gdtoa first and fallbacks to legacy ldtoa if gdtoa fails.
> > 
> > To import gdtoa to newlib, I did:
> > 1) Create "machine/ieee.h" which conditionally defines ieee_ext
> >    structure and EXT_TO_ARRAY32() macro depend on architecture.
> > 2) Create arith.h which reflects endian of architecture.
> > 3) Merge gdtoa.h with OpenBSD's gdtoa.h. __BEGIN_HIDDEN_DECLS,
> >    __END_HIDDEN_DECLS, PROTO_NORMAL() and DEF_STRONG() are
> >    defined as dummy in this header.
> > 4) Replace malloc()/free() with _malloc_r()/_free_r().
> > 5) Implement ACQUIRE_DTOA_LOCK() and FREE_DTOA_LOCK() macros
> >    using "sys/lock.h" for multi-threading environment.
> > 6) Remove inclusion of "gd_qnan.h" which is not used.
> > 
> > Please see attached patch for more details.
> > 
> > I confirmed this works nicely with cygwin. Moreover, it is much
> > faster than legacy ldtoa (more than 4 times faster).
> > 
> > However, this may break some other supported platforms.
> > 
> > Could anyone please check this?
> 
> Ah, in "machine/ieee.h", struct ieee_ext definition for
> LDBL_MANT_DIG==64 and __IEEE_BIG_ENDIAN case, is obviously
> wrong. 

Fixed.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: 0001-ldtoa-Import-gdtoa-from-OpenBSD.patch --]
[-- Type: application/octet-stream, Size: 108429 bytes --]

From 3f94a09c8555bc5db2b26fe6f0815e2bc5659e29 Mon Sep 17 00:00:00 2001
From: Takashi Yano <takashi.yano@nifty.ne.jp>
Date: Sun, 28 Nov 2021 22:11:47 +0900
Subject: [PATCH] ldtoa: Import gdtoa from OpenBSD.

---
 newlib/libc/include/machine/ieee.h | 103 ++++
 newlib/libc/stdlib/Makefile.am     |  14 +-
 newlib/libc/stdlib/Makefile.in     |  82 ++-
 newlib/libc/stdlib/arith.h         |   9 +
 newlib/libc/stdlib/gdtoa-dmisc.c   | 225 +++++++
 newlib/libc/stdlib/gdtoa-dtoa.c    | 839 ++++++++++++++++++++++++++
 newlib/libc/stdlib/gdtoa-gdtoa.c   | 830 ++++++++++++++++++++++++++
 newlib/libc/stdlib/gdtoa-gmisc.c   |  86 +++
 newlib/libc/stdlib/gdtoa-ldtoa.c   | 124 ++++
 newlib/libc/stdlib/gdtoa-misc.c    | 912 +++++++++++++++++++++++++++++
 newlib/libc/stdlib/gdtoa.h         | 132 ++++-
 newlib/libc/stdlib/gdtoaimp.h      | 672 +++++++++++++++++++++
 newlib/libc/stdlib/ldtoa.c         |   7 +
 13 files changed, 4001 insertions(+), 34 deletions(-)
 create mode 100644 newlib/libc/include/machine/ieee.h
 create mode 100644 newlib/libc/stdlib/arith.h
 create mode 100644 newlib/libc/stdlib/gdtoa-dmisc.c
 create mode 100644 newlib/libc/stdlib/gdtoa-dtoa.c
 create mode 100644 newlib/libc/stdlib/gdtoa-gdtoa.c
 create mode 100644 newlib/libc/stdlib/gdtoa-gmisc.c
 create mode 100644 newlib/libc/stdlib/gdtoa-ldtoa.c
 create mode 100644 newlib/libc/stdlib/gdtoa-misc.c
 create mode 100644 newlib/libc/stdlib/gdtoaimp.h

diff --git a/newlib/libc/include/machine/ieee.h b/newlib/libc/include/machine/ieee.h
new file mode 100644
index 000000000..5cead1951
--- /dev/null
+++ b/newlib/libc/include/machine/ieee.h
@@ -0,0 +1,103 @@
+#ifndef _MACHINE_IEEE_H_
+#define _MACHINE_IEEE_H_
+#include <sys/types.h>
+#include <sys/cdefs.h>
+#include <machine/ieeefp.h>
+#include <float.h>
+
+#if LDBL_MANT_DIG == 24
+#define EXT_IMPLICIT_NBIT
+#define EXT_TO_ARRAY32(p, a) do {      \
+    (a)[0] = (p)->ext_frac;  \
+} while (0)
+#ifdef __IEEE_LITTLE_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_frac:23;
+    uint32_t   ext_exp:8;
+    uint32_t   ext_sign:1;
+};
+#endif
+#ifdef __IEEE_BIG_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_sign:1;
+    uint32_t   ext_exp:8;
+    uint32_t   ext_frac:23;
+};
+#endif
+#elif LDBL_MANT_DIG == 53
+#define EXT_IMPLICIT_NBIT
+#define EXT_TO_ARRAY32(p, a) do {       \
+    (a)[0] = (p)->ext_fracl;  \
+    (a)[1] = (p)->ext_frach;  \
+} while (0)
+#ifdef __IEEE_LITTLE_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_fracl;
+    uint32_t   ext_frach:20;
+    uint32_t   ext_exp:11;
+    uint32_t   ext_sign:1;
+};
+#endif
+#ifdef __IEEE_BIG_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_sign:1;
+    uint32_t   ext_exp:11;
+    uint32_t   ext_frach:20;
+    uint32_t   ext_fracl;
+};
+#endif
+#elif LDBL_MANT_DIG == 64
+#define EXT_TO_ARRAY32(p, a) do {       \
+    (a)[0] = (p)->ext_fracl;  \
+    (a)[1] = (p)->ext_frach;  \
+} while (0)
+#ifdef __IEEE_LITTLE_ENDIAN /* for Intel CPU */
+struct ieee_ext {
+    uint32_t   ext_fracl;
+    uint32_t   ext_frach;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_sign:1;
+    uint32_t   ext_padl:16;
+    uint32_t   ext_padh;
+};
+#endif
+#ifdef __IEEE_BIG_ENDIAN /* for m68k */
+struct ieee_ext {
+    uint32_t   ext_sign:1;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_pad:16;
+    uint32_t   ext_frach;
+    uint32_t   ext_fracl;
+};
+#endif
+#elif LDBL_MANT_DIG == 113
+#define EXT_IMPLICIT_NBIT
+#define EXT_TO_ARRAY32(p, a) do {        \
+    (a)[0] = (p)->ext_fracl;   \
+    (a)[1] = (p)->ext_fraclm;  \
+    (a)[2] = (p)->ext_frachm;  \
+    (a)[3] = (p)->ext_frach;   \
+} while (0)
+#ifdef __IEEE_LITTLE_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_fracl;
+    uint32_t   ext_fraclm;
+    uint32_t   ext_frachm;
+    uint32_t   ext_frach:16;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_sign:1;
+};
+#endif
+#ifdef __IEEE_BIG_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_sign:1;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_frach:16;
+    uint32_t   ext_frachm;
+    uint32_t   ext_fraclm;
+    uint32_t   ext_fracl;
+};
+#endif
+#endif
+
+#endif /* _MACHINE_IEEE_H_ */
diff --git a/newlib/libc/stdlib/Makefile.am b/newlib/libc/stdlib/Makefile.am
index 357e37beb..04b22d477 100644
--- a/newlib/libc/stdlib/Makefile.am
+++ b/newlib/libc/stdlib/Makefile.am
@@ -38,6 +38,12 @@ GENERAL_SOURCES = \
 	labs.c 		\
 	ldiv.c  	\
 	ldtoa.c		\
+	gdtoa-ldtoa.c	\
+	gdtoa-gdtoa.c	\
+	gdtoa-dtoa.c	\
+	gdtoa-misc.c	\
+	gdtoa-dmisc.c	\
+	gdtoa-gmisc.c	\
 	malloc.c  	\
 	mblen.c		\
 	mblen_r.c	\
@@ -311,7 +317,13 @@ CHEWOUT_FILES= \
 CHAPTERS = stdlib.tex
 
 $(lpfx)dtoa.$(oext): dtoa.c mprec.h
-$(lpfx)ldtoa.$(oext): ldtoa.c mprec.h
+$(lpfx)ldtoa.$(oext): ldtoa.c mprec.h gdtoa.h
+$(lpfx)gdtoa-ldtoa.$(oext): gdtoa-ldtoa.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-gdtoa.$(oext): gdtoa-gdtoa.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-dtoa.$(oext): gdtoa-dtoa.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-misc.$(oext): gdtoa-misc.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-dmisc.$(oext): gdtoa-dmisc.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-gmisc.$(oext): gdtoa-gmisc.c gdtoaimp.h gdtoa.h arith.h
 $(lpfx)ecvtbuf.$(oext): ecvtbuf.c mprec.h
 $(lpfx)mbtowc_r.$(oext): mbtowc_r.c mbctype.h
 $(lpfx)mprec.$(oext): mprec.c mprec.h
diff --git a/newlib/libc/stdlib/Makefile.in b/newlib/libc/stdlib/Makefile.in
index a812b6a95..4e891ced9 100644
--- a/newlib/libc/stdlib/Makefile.in
+++ b/newlib/libc/stdlib/Makefile.in
@@ -101,7 +101,10 @@ am__objects_2 = lib_a-__adjust.$(OBJEXT) lib_a-__atexit.$(OBJEXT) \
 	lib_a-getenv_r.$(OBJEXT) lib_a-imaxabs.$(OBJEXT) \
 	lib_a-imaxdiv.$(OBJEXT) lib_a-itoa.$(OBJEXT) \
 	lib_a-labs.$(OBJEXT) lib_a-ldiv.$(OBJEXT) \
-	lib_a-ldtoa.$(OBJEXT) lib_a-malloc.$(OBJEXT) \
+	lib_a-ldtoa.$(OBJEXT) lib_a-gdtoa-ldtoa.$(OBJEXT) \
+	lib_a-gdtoa-gdtoa.$(OBJEXT) lib_a-gdtoa-dtoa.$(OBJEXT) \
+	lib_a-gdtoa-misc.$(OBJEXT) lib_a-gdtoa-dmisc.$(OBJEXT) \
+	lib_a-gdtoa-gmisc.$(OBJEXT) lib_a-malloc.$(OBJEXT) \
 	lib_a-mblen.$(OBJEXT) lib_a-mblen_r.$(OBJEXT) \
 	lib_a-mbstowcs.$(OBJEXT) lib_a-mbstowcs_r.$(OBJEXT) \
 	lib_a-mbtowc.$(OBJEXT) lib_a-mbtowc_r.$(OBJEXT) \
@@ -165,14 +168,15 @@ am__objects_9 = __adjust.lo __atexit.lo __call_atexit.lo __exp10.lo \
 	div.lo dtoa.lo dtoastub.lo environ.lo envlock.lo eprintf.lo \
 	exit.lo gdtoa-gethex.lo gdtoa-hexnan.lo getenv.lo getenv_r.lo \
 	imaxabs.lo imaxdiv.lo itoa.lo labs.lo ldiv.lo ldtoa.lo \
-	malloc.lo mblen.lo mblen_r.lo mbstowcs.lo mbstowcs_r.lo \
-	mbtowc.lo mbtowc_r.lo mlock.lo mprec.lo mstats.lo \
-	on_exit_args.lo quick_exit.lo rand.lo rand_r.lo random.lo \
-	realloc.lo reallocarray.lo reallocf.lo sb_charsets.lo \
-	strtod.lo strtoimax.lo strtol.lo strtoul.lo strtoumax.lo \
-	utoa.lo wcstod.lo wcstoimax.lo wcstol.lo wcstoul.lo \
-	wcstoumax.lo wcstombs.lo wcstombs_r.lo wctomb.lo wctomb_r.lo \
-	$(am__objects_8)
+	gdtoa-ldtoa.lo gdtoa-gdtoa.lo gdtoa-dtoa.lo gdtoa-misc.lo \
+	gdtoa-dmisc.lo gdtoa-gmisc.lo malloc.lo mblen.lo mblen_r.lo \
+	mbstowcs.lo mbstowcs_r.lo mbtowc.lo mbtowc_r.lo mlock.lo \
+	mprec.lo mstats.lo on_exit_args.lo quick_exit.lo rand.lo \
+	rand_r.lo random.lo realloc.lo reallocarray.lo reallocf.lo \
+	sb_charsets.lo strtod.lo strtoimax.lo strtol.lo strtoul.lo \
+	strtoumax.lo utoa.lo wcstod.lo wcstoimax.lo wcstol.lo \
+	wcstoul.lo wcstoumax.lo wcstombs.lo wcstombs_r.lo wctomb.lo \
+	wctomb_r.lo $(am__objects_8)
 am__objects_10 = arc4random.lo arc4random_uniform.lo cxa_atexit.lo \
 	cxa_finalize.lo drand48.lo ecvtbuf.lo efgcvt.lo erand48.lo \
 	jrand48.lo lcong48.lo lrand48.lo mrand48.lo msize.lo mtrim.lo \
@@ -354,6 +358,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 shared_machine_dir = @shared_machine_dir@
 sharedstatedir = @sharedstatedir@
@@ -372,13 +377,14 @@ GENERAL_SOURCES = __adjust.c __atexit.c __call_atexit.c __exp10.c \
 	atexit.c atof.c atoff.c atoi.c atol.c calloc.c div.c dtoa.c \
 	dtoastub.c environ.c envlock.c eprintf.c exit.c gdtoa-gethex.c \
 	gdtoa-hexnan.c getenv.c getenv_r.c imaxabs.c imaxdiv.c itoa.c \
-	labs.c ldiv.c ldtoa.c malloc.c mblen.c mblen_r.c mbstowcs.c \
-	mbstowcs_r.c mbtowc.c mbtowc_r.c mlock.c mprec.c mstats.c \
-	on_exit_args.c quick_exit.c rand.c rand_r.c random.c realloc.c \
-	reallocarray.c reallocf.c sb_charsets.c strtod.c strtoimax.c \
-	strtol.c strtoul.c strtoumax.c utoa.c wcstod.c wcstoimax.c \
-	wcstol.c wcstoul.c wcstoumax.c wcstombs.c wcstombs_r.c \
-	wctomb.c wctomb_r.c $(am__append_1)
+	labs.c ldiv.c ldtoa.c gdtoa-ldtoa.c gdtoa-gdtoa.c gdtoa-dtoa.c \
+	gdtoa-misc.c gdtoa-dmisc.c gdtoa-gmisc.c malloc.c mblen.c \
+	mblen_r.c mbstowcs.c mbstowcs_r.c mbtowc.c mbtowc_r.c mlock.c \
+	mprec.c mstats.c on_exit_args.c quick_exit.c rand.c rand_r.c \
+	random.c realloc.c reallocarray.c reallocf.c sb_charsets.c \
+	strtod.c strtoimax.c strtol.c strtoul.c strtoumax.c utoa.c \
+	wcstod.c wcstoimax.c wcstol.c wcstoul.c wcstoumax.c wcstombs.c \
+	wcstombs_r.c wctomb.c wctomb_r.c $(am__append_1)
 @NEWLIB_NANO_MALLOC_FALSE@MALIGNR = malignr
 @NEWLIB_NANO_MALLOC_TRUE@MALIGNR = nano-malignr
 @NEWLIB_NANO_MALLOC_FALSE@MALLOPTR = malloptr
@@ -827,6 +833,42 @@ lib_a-ldtoa.o: ldtoa.c
 lib_a-ldtoa.obj: ldtoa.c
 	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-ldtoa.obj `if test -f 'ldtoa.c'; then $(CYGPATH_W) 'ldtoa.c'; else $(CYGPATH_W) '$(srcdir)/ldtoa.c'; fi`
 
+lib_a-gdtoa-ldtoa.o: gdtoa-ldtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-ldtoa.o `test -f 'gdtoa-ldtoa.c' || echo '$(srcdir)/'`gdtoa-ldtoa.c
+
+lib_a-gdtoa-ldtoa.obj: gdtoa-ldtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-ldtoa.obj `if test -f 'gdtoa-ldtoa.c'; then $(CYGPATH_W) 'gdtoa-ldtoa.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-ldtoa.c'; fi`
+
+lib_a-gdtoa-gdtoa.o: gdtoa-gdtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-gdtoa.o `test -f 'gdtoa-gdtoa.c' || echo '$(srcdir)/'`gdtoa-gdtoa.c
+
+lib_a-gdtoa-gdtoa.obj: gdtoa-gdtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-gdtoa.obj `if test -f 'gdtoa-gdtoa.c'; then $(CYGPATH_W) 'gdtoa-gdtoa.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-gdtoa.c'; fi`
+
+lib_a-gdtoa-dtoa.o: gdtoa-dtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-dtoa.o `test -f 'gdtoa-dtoa.c' || echo '$(srcdir)/'`gdtoa-dtoa.c
+
+lib_a-gdtoa-dtoa.obj: gdtoa-dtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-dtoa.obj `if test -f 'gdtoa-dtoa.c'; then $(CYGPATH_W) 'gdtoa-dtoa.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-dtoa.c'; fi`
+
+lib_a-gdtoa-misc.o: gdtoa-misc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-misc.o `test -f 'gdtoa-misc.c' || echo '$(srcdir)/'`gdtoa-misc.c
+
+lib_a-gdtoa-misc.obj: gdtoa-misc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-misc.obj `if test -f 'gdtoa-misc.c'; then $(CYGPATH_W) 'gdtoa-misc.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-misc.c'; fi`
+
+lib_a-gdtoa-dmisc.o: gdtoa-dmisc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-dmisc.o `test -f 'gdtoa-dmisc.c' || echo '$(srcdir)/'`gdtoa-dmisc.c
+
+lib_a-gdtoa-dmisc.obj: gdtoa-dmisc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-dmisc.obj `if test -f 'gdtoa-dmisc.c'; then $(CYGPATH_W) 'gdtoa-dmisc.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-dmisc.c'; fi`
+
+lib_a-gdtoa-gmisc.o: gdtoa-gmisc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-gmisc.o `test -f 'gdtoa-gmisc.c' || echo '$(srcdir)/'`gdtoa-gmisc.c
+
+lib_a-gdtoa-gmisc.obj: gdtoa-gmisc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-gmisc.obj `if test -f 'gdtoa-gmisc.c'; then $(CYGPATH_W) 'gdtoa-gmisc.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-gmisc.c'; fi`
+
 lib_a-malloc.o: malloc.c
 	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-malloc.o `test -f 'malloc.c' || echo '$(srcdir)/'`malloc.c
 
@@ -1610,7 +1652,13 @@ $(lpfx)$(MALLOPTR).$(oext): $(MALLOCR).c
 	$(MALLOC_COMPILE) -DDEFINE_MALLOPT -c $(srcdir)/$(MALLOCR).c -o $@
 
 $(lpfx)dtoa.$(oext): dtoa.c mprec.h
-$(lpfx)ldtoa.$(oext): ldtoa.c mprec.h
+$(lpfx)ldtoa.$(oext): ldtoa.c mprec.h gdtoa.h
+$(lpfx)gdtoa-ldtoa.$(oext): gdtoa-ldtoa.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-gdtoa.$(oext): gdtoa-gdtoa.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-dtoa.$(oext): gdtoa-dtoa.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-misc.$(oext): gdtoa-misc.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-dmisc.$(oext): gdtoa-dmisc.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-gmisc.$(oext): gdtoa-gmisc.c gdtoaimp.h gdtoa.h arith.h
 $(lpfx)ecvtbuf.$(oext): ecvtbuf.c mprec.h
 $(lpfx)mbtowc_r.$(oext): mbtowc_r.c mbctype.h
 $(lpfx)mprec.$(oext): mprec.c mprec.h
diff --git a/newlib/libc/stdlib/arith.h b/newlib/libc/stdlib/arith.h
new file mode 100644
index 000000000..d3b84d867
--- /dev/null
+++ b/newlib/libc/stdlib/arith.h
@@ -0,0 +1,9 @@
+#include <machine/ieeefp.h>
+
+#ifdef __IEEE_LITTLE_ENDIAN
+#define IEEE_8087
+#endif
+
+#ifdef __IEEE_BIG_ENDIAN
+#define IEEE_MC68k
+#endif
diff --git a/newlib/libc/stdlib/gdtoa-dmisc.c b/newlib/libc/stdlib/gdtoa-dmisc.c
new file mode 100644
index 000000000..f3d8ea71a
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-dmisc.c
@@ -0,0 +1,225 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include "gdtoaimp.h"
+
+#ifndef MULTIPLE_THREADS
+ char *dtoa_result;
+#endif
+
+ char *
+#ifdef KR_headers
+rv_alloc(i) int i;
+#else
+rv_alloc(int i)
+#endif
+{
+	int j, k, *r;
+
+	j = sizeof(ULong);
+	for(k = 0;
+		sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i;
+		j <<= 1)
+			k++;
+	r = (int*)Balloc(k);
+	if (r == NULL)
+		return (
+#ifndef MULTIPLE_THREADS
+		dtoa_result =
+#endif
+			NULL);
+	*r = k;
+	return
+#ifndef MULTIPLE_THREADS
+	dtoa_result =
+#endif
+		(char *)(r+1);
+	}
+
+ char *
+#ifdef KR_headers
+nrv_alloc(s, rve, n) char *s, **rve; int n;
+#else
+nrv_alloc(char *s, char **rve, int n)
+#endif
+{
+	char *rv, *t;
+
+	t = rv = rv_alloc(n);
+	if (t == NULL)
+		return (NULL);
+	while((*t = *s++) !=0)
+		t++;
+	if (rve)
+		*rve = t;
+	return rv;
+	}
+
+/* freedtoa(s) must be used to free values s returned by dtoa
+ * when MULTIPLE_THREADS is #defined.  It should be used in all cases,
+ * but for consistency with earlier versions of dtoa, it is optional
+ * when MULTIPLE_THREADS is not defined.
+ */
+
+ void
+#ifdef KR_headers
+freedtoa(s) char *s;
+#else
+freedtoa(char *s)
+#endif
+{
+	Bigint *b = (Bigint *)((int *)s - 1);
+	b->maxwds = 1 << (b->k = *(int*)b);
+	Bfree(b);
+#ifndef MULTIPLE_THREADS
+	if (s == dtoa_result)
+		dtoa_result = 0;
+#endif
+	}
+DEF_STRONG(freedtoa);
+
+ int
+quorem
+#ifdef KR_headers
+	(b, S) Bigint *b, *S;
+#else
+	(Bigint *b, Bigint *S)
+#endif
+{
+	int n;
+	ULong *bx, *bxe, q, *sx, *sxe;
+#ifdef ULLong
+	ULLong borrow, carry, y, ys;
+#else
+	ULong borrow, carry, y, ys;
+#ifdef Pack_32
+	ULong si, z, zs;
+#endif
+#endif
+
+	n = S->wds;
+#ifdef DEBUG
+	/*debug*/ if (b->wds > n)
+	/*debug*/	Bug("oversize b in quorem");
+#endif
+	if (b->wds < n)
+		return 0;
+	sx = S->x;
+	sxe = sx + --n;
+	bx = b->x;
+	bxe = bx + n;
+	q = *bxe / (*sxe + 1);	/* ensure q <= true quotient */
+#ifdef DEBUG
+	/*debug*/ if (q > 9)
+	/*debug*/	Bug("oversized quotient in quorem");
+#endif
+	if (q) {
+		borrow = 0;
+		carry = 0;
+		do {
+#ifdef ULLong
+			ys = *sx++ * (ULLong)q + carry;
+			carry = ys >> 32;
+			y = *bx - (ys & 0xffffffffUL) - borrow;
+			borrow = y >> 32 & 1UL;
+			*bx++ = y & 0xffffffffUL;
+#else
+#ifdef Pack_32
+			si = *sx++;
+			ys = (si & 0xffff) * q + carry;
+			zs = (si >> 16) * q + (ys >> 16);
+			carry = zs >> 16;
+			y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			z = (*bx >> 16) - (zs & 0xffff) - borrow;
+			borrow = (z & 0x10000) >> 16;
+			Storeinc(bx, z, y);
+#else
+			ys = *sx++ * q + carry;
+			carry = ys >> 16;
+			y = *bx - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			*bx++ = y & 0xffff;
+#endif
+#endif
+			}
+			while(sx <= sxe);
+		if (!*bxe) {
+			bx = b->x;
+			while(--bxe > bx && !*bxe)
+				--n;
+			b->wds = n;
+			}
+		}
+	if (cmp(b, S) >= 0) {
+		q++;
+		borrow = 0;
+		carry = 0;
+		bx = b->x;
+		sx = S->x;
+		do {
+#ifdef ULLong
+			ys = *sx++ + carry;
+			carry = ys >> 32;
+			y = *bx - (ys & 0xffffffffUL) - borrow;
+			borrow = y >> 32 & 1UL;
+			*bx++ = y & 0xffffffffUL;
+#else
+#ifdef Pack_32
+			si = *sx++;
+			ys = (si & 0xffff) + carry;
+			zs = (si >> 16) + (ys >> 16);
+			carry = zs >> 16;
+			y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			z = (*bx >> 16) - (zs & 0xffff) - borrow;
+			borrow = (z & 0x10000) >> 16;
+			Storeinc(bx, z, y);
+#else
+			ys = *sx++ + carry;
+			carry = ys >> 16;
+			y = *bx - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			*bx++ = y & 0xffff;
+#endif
+#endif
+			}
+			while(sx <= sxe);
+		bx = b->x;
+		bxe = bx + n;
+		if (!*bxe) {
+			while(--bxe > bx && !*bxe)
+				--n;
+			b->wds = n;
+			}
+		}
+	return q;
+	}
diff --git a/newlib/libc/stdlib/gdtoa-dtoa.c b/newlib/libc/stdlib/gdtoa-dtoa.c
new file mode 100644
index 000000000..998192764
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-dtoa.c
@@ -0,0 +1,839 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998, 1999 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include "gdtoaimp.h"
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ *	1. Rather than iterating, we use a simple numeric overestimate
+ *	   to determine k = floor(log10(d)).  We scale relevant
+ *	   quantities using O(log2(k)) rather than O(k) multiplications.
+ *	2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ *	   try to generate digits strictly left to right.  Instead, we
+ *	   compute with fewer bits and propagate the carry if necessary
+ *	   when rounding the final digit up.  This is often faster.
+ *	3. Under the assumption that input will be rounded nearest,
+ *	   mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ *	   That is, we allow equality in stopping tests when the
+ *	   round-nearest rule will give the same floating-point value
+ *	   as would satisfaction of the stopping test with strict
+ *	   inequality.
+ *	4. We remove common factors of powers of 2 from relevant
+ *	   quantities.
+ *	5. When converting floating-point integers less than 1e16,
+ *	   we use floating-point arithmetic rather than resorting
+ *	   to multiple-precision integers.
+ *	6. When asked to produce fewer than 15 digits, we first try
+ *	   to get by with floating-point arithmetic; we resort to
+ *	   multiple-precision integer arithmetic only if we cannot
+ *	   guarantee that the floating-point calculation has given
+ *	   the correctly rounded result.  For k requested digits and
+ *	   "uniformly" distributed input, the probability is
+ *	   something like 10^(k-15) that we must resort to the Long
+ *	   calculation.
+ */
+
+#ifdef Honor_FLT_ROUNDS
+#undef Check_FLT_ROUNDS
+#define Check_FLT_ROUNDS
+#else
+#define Rounding Flt_Rounds
+#endif
+
+ char *
+dtoa
+#ifdef KR_headers
+	(d0, mode, ndigits, decpt, sign, rve)
+	double d0; int mode, ndigits, *decpt, *sign; char **rve;
+#else
+	(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
+#endif
+{
+ /*	Arguments ndigits, decpt, sign are similar to those
+	of ecvt and fcvt; trailing zeros are suppressed from
+	the returned string.  If not null, *rve is set to point
+	to the end of the return value.  If d is +-Infinity or NaN,
+	then *decpt is set to 9999.
+
+	mode:
+		0 ==> shortest string that yields d when read in
+			and rounded to nearest.
+		1 ==> like 0, but with Steele & White stopping rule;
+			e.g. with IEEE P754 arithmetic , mode 0 gives
+			1e23 whereas mode 1 gives 9.999999999999999e22.
+		2 ==> max(1,ndigits) significant digits.  This gives a
+			return value similar to that of ecvt, except
+			that trailing zeros are suppressed.
+		3 ==> through ndigits past the decimal point.  This
+			gives a return value similar to that from fcvt,
+			except that trailing zeros are suppressed, and
+			ndigits can be negative.
+		4,5 ==> similar to 2 and 3, respectively, but (in
+			round-nearest mode) with the tests of mode 0 to
+			possibly return a shorter string that rounds to d.
+			With IEEE arithmetic and compilation with
+			-DHonor_FLT_ROUNDS, modes 4 and 5 behave the same
+			as modes 2 and 3 when FLT_ROUNDS != 1.
+		6-9 ==> Debugging modes similar to mode - 4:  don't try
+			fast floating-point estimate (if applicable).
+
+		Values of mode other than 0-9 are treated as mode 0.
+
+		Sufficient space is allocated to the return value
+		to hold the suppressed trailing zeros.
+	*/
+
+	int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,
+		j, j1, k, k0, k_check, leftright, m2, m5, s2, s5,
+		spec_case, try_quick;
+	Long L;
+#ifndef Sudden_Underflow
+	int denorm;
+	ULong x;
+#endif
+	Bigint *b, *b1, *delta, *mlo, *mhi, *S;
+	U d, d2, eps;
+	double ds;
+	char *s, *s0;
+#ifdef SET_INEXACT
+	int inexact, oldinexact;
+#endif
+#ifdef Honor_FLT_ROUNDS /*{*/
+	int Rounding;
+#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */
+	Rounding = Flt_Rounds;
+#else /*}{*/
+	Rounding = 1;
+	switch(fegetround()) {
+	  case FE_TOWARDZERO:	Rounding = 0; break;
+	  case FE_UPWARD:	Rounding = 2; break;
+	  case FE_DOWNWARD:	Rounding = 3;
+	  }
+#endif /*}}*/
+#endif /*}*/
+
+#ifndef MULTIPLE_THREADS
+	if (dtoa_result) {
+		freedtoa(dtoa_result);
+		dtoa_result = 0;
+		}
+#endif
+	d.d = d0;
+	if (word0(&d) & Sign_bit) {
+		/* set sign for everything, including 0's and NaNs */
+		*sign = 1;
+		word0(&d) &= ~Sign_bit;	/* clear sign bit */
+		}
+	else
+		*sign = 0;
+
+#if defined(IEEE_Arith) + defined(VAX)
+#ifdef IEEE_Arith
+	if ((word0(&d) & Exp_mask) == Exp_mask)
+#else
+	if (word0(&d)  == 0x8000)
+#endif
+		{
+		/* Infinity or NaN */
+		*decpt = 9999;
+#ifdef IEEE_Arith
+		if (!word1(&d) && !(word0(&d) & 0xfffff))
+			return nrv_alloc("Infinity", rve, 8);
+#endif
+		return nrv_alloc("NaN", rve, 3);
+		}
+#endif
+#ifdef IBM
+	dval(&d) += 0; /* normalize */
+#endif
+	if (!dval(&d)) {
+		*decpt = 1;
+		return nrv_alloc("0", rve, 1);
+		}
+
+#ifdef SET_INEXACT
+	try_quick = oldinexact = get_inexact();
+	inexact = 1;
+#endif
+#ifdef Honor_FLT_ROUNDS
+	if (Rounding >= 2) {
+		if (*sign)
+			Rounding = Rounding == 2 ? 0 : 2;
+		else
+			if (Rounding != 2)
+				Rounding = 0;
+		}
+#endif
+
+	b = d2b(dval(&d), &be, &bbits);
+	if (b == NULL)
+		return (NULL);
+#ifdef Sudden_Underflow
+	i = (int)(word0(&d) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
+#else
+	if (( i = (int)(word0(&d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)) )!=0) {
+#endif
+		dval(&d2) = dval(&d);
+		word0(&d2) &= Frac_mask1;
+		word0(&d2) |= Exp_11;
+#ifdef IBM
+		if (( j = 11 - hi0bits(word0(&d2) & Frac_mask) )!=0)
+			dval(&d2) /= 1 << j;
+#endif
+
+		/* log(x)	~=~ log(1.5) + (x-1.5)/1.5
+		 * log10(x)	 =  log(x) / log(10)
+		 *		~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+		 * log10(&d) = (i-Bias)*log(2)/log(10) + log10(&d2)
+		 *
+		 * This suggests computing an approximation k to log10(&d) by
+		 *
+		 * k = (i - Bias)*0.301029995663981
+		 *	+ ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+		 *
+		 * We want k to be too large rather than too small.
+		 * The error in the first-order Taylor series approximation
+		 * is in our favor, so we just round up the constant enough
+		 * to compensate for any error in the multiplication of
+		 * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+		 * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+		 * adding 1e-13 to the constant term more than suffices.
+		 * Hence we adjust the constant term to 0.1760912590558.
+		 * (We could get a more accurate k by invoking log10,
+		 *  but this is probably not worthwhile.)
+		 */
+
+		i -= Bias;
+#ifdef IBM
+		i <<= 2;
+		i += j;
+#endif
+#ifndef Sudden_Underflow
+		denorm = 0;
+		}
+	else {
+		/* d is denormalized */
+
+		i = bbits + be + (Bias + (P-1) - 1);
+		x = i > 32  ? word0(&d) << (64 - i) | word1(&d) >> (i - 32)
+			    : word1(&d) << (32 - i);
+		dval(&d2) = x;
+		word0(&d2) -= 31*Exp_msk1; /* adjust exponent */
+		i -= (Bias + (P-1) - 1) + 1;
+		denorm = 1;
+		}
+#endif
+	ds = (dval(&d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
+	k = (int)ds;
+	if (ds < 0. && ds != k)
+		k--;	/* want k = floor(ds) */
+	k_check = 1;
+	if (k >= 0 && k <= Ten_pmax) {
+		if (dval(&d) < tens[k])
+			k--;
+		k_check = 0;
+		}
+	j = bbits - i - 1;
+	if (j >= 0) {
+		b2 = 0;
+		s2 = j;
+		}
+	else {
+		b2 = -j;
+		s2 = 0;
+		}
+	if (k >= 0) {
+		b5 = 0;
+		s5 = k;
+		s2 += k;
+		}
+	else {
+		b2 -= k;
+		b5 = -k;
+		s5 = 0;
+		}
+	if (mode < 0 || mode > 9)
+		mode = 0;
+
+#ifndef SET_INEXACT
+#ifdef Check_FLT_ROUNDS
+	try_quick = Rounding == 1;
+#else
+	try_quick = 1;
+#endif
+#endif /*SET_INEXACT*/
+
+	if (mode > 5) {
+		mode -= 4;
+		try_quick = 0;
+		}
+	leftright = 1;
+	ilim = ilim1 = -1;	/* Values for cases 0 and 1; done here to */
+				/* silence erroneous "gcc -Wall" warning. */
+	switch(mode) {
+		case 0:
+		case 1:
+			i = 18;
+			ndigits = 0;
+			break;
+		case 2:
+			leftright = 0;
+			/* no break */
+		case 4:
+			if (ndigits <= 0)
+				ndigits = 1;
+			ilim = ilim1 = i = ndigits;
+			break;
+		case 3:
+			leftright = 0;
+			/* no break */
+		case 5:
+			i = ndigits + k + 1;
+			ilim = i;
+			ilim1 = i - 1;
+			if (i <= 0)
+				i = 1;
+		}
+	s = s0 = rv_alloc(i);
+	if (s == NULL)
+		return (NULL);
+
+#ifdef Honor_FLT_ROUNDS
+	if (mode > 1 && Rounding != 1)
+		leftright = 0;
+#endif
+
+	if (ilim >= 0 && ilim <= Quick_max && try_quick) {
+
+		/* Try to get by with floating-point arithmetic. */
+
+		i = 0;
+		dval(&d2) = dval(&d);
+		k0 = k;
+		ilim0 = ilim;
+		ieps = 2; /* conservative */
+		if (k > 0) {
+			ds = tens[k&0xf];
+			j = k >> 4;
+			if (j & Bletch) {
+				/* prevent overflows */
+				j &= Bletch - 1;
+				dval(&d) /= bigtens[n_bigtens-1];
+				ieps++;
+				}
+			for(; j; j >>= 1, i++)
+				if (j & 1) {
+					ieps++;
+					ds *= bigtens[i];
+					}
+			dval(&d) /= ds;
+			}
+		else if (( j1 = -k )!=0) {
+			dval(&d) *= tens[j1 & 0xf];
+			for(j = j1 >> 4; j; j >>= 1, i++)
+				if (j & 1) {
+					ieps++;
+					dval(&d) *= bigtens[i];
+					}
+			}
+		if (k_check && dval(&d) < 1. && ilim > 0) {
+			if (ilim1 <= 0)
+				goto fast_failed;
+			ilim = ilim1;
+			k--;
+			dval(&d) *= 10.;
+			ieps++;
+			}
+		dval(&eps) = ieps*dval(&d) + 7.;
+		word0(&eps) -= (P-1)*Exp_msk1;
+		if (ilim == 0) {
+			S = mhi = 0;
+			dval(&d) -= 5.;
+			if (dval(&d) > dval(&eps))
+				goto one_digit;
+			if (dval(&d) < -dval(&eps))
+				goto no_digits;
+			goto fast_failed;
+			}
+#ifndef No_leftright
+		if (leftright) {
+			/* Use Steele & White method of only
+			 * generating digits needed.
+			 */
+			dval(&eps) = 0.5/tens[ilim-1] - dval(&eps);
+			for(i = 0;;) {
+				L = dval(&d);
+				dval(&d) -= L;
+				*s++ = '0' + (int)L;
+				if (dval(&d) < dval(&eps))
+					goto ret1;
+				if (1. - dval(&d) < dval(&eps))
+					goto bump_up;
+				if (++i >= ilim)
+					break;
+				dval(&eps) *= 10.;
+				dval(&d) *= 10.;
+				}
+			}
+		else {
+#endif
+			/* Generate ilim digits, then fix them up. */
+			dval(&eps) *= tens[ilim-1];
+			for(i = 1;; i++, dval(&d) *= 10.) {
+				L = (Long)(dval(&d));
+				if (!(dval(&d) -= L))
+					ilim = i;
+				*s++ = '0' + (int)L;
+				if (i == ilim) {
+					if (dval(&d) > 0.5 + dval(&eps))
+						goto bump_up;
+					else if (dval(&d) < 0.5 - dval(&eps)) {
+						while(*--s == '0');
+						s++;
+						goto ret1;
+						}
+					break;
+					}
+				}
+#ifndef No_leftright
+			}
+#endif
+ fast_failed:
+		s = s0;
+		dval(&d) = dval(&d2);
+		k = k0;
+		ilim = ilim0;
+		}
+
+	/* Do we have a "small" integer? */
+
+	if (be >= 0 && k <= Int_max) {
+		/* Yes. */
+		ds = tens[k];
+		if (ndigits < 0 && ilim <= 0) {
+			S = mhi = 0;
+			if (ilim < 0 || dval(&d) <= 5*ds)
+				goto no_digits;
+			goto one_digit;
+			}
+		for(i = 1;; i++, dval(&d) *= 10.) {
+			L = (Long)(dval(&d) / ds);
+			dval(&d) -= L*ds;
+#ifdef Check_FLT_ROUNDS
+			/* If FLT_ROUNDS == 2, L will usually be high by 1 */
+			if (dval(&d) < 0) {
+				L--;
+				dval(&d) += ds;
+				}
+#endif
+			*s++ = '0' + (int)L;
+			if (!dval(&d)) {
+#ifdef SET_INEXACT
+				inexact = 0;
+#endif
+				break;
+				}
+			if (i == ilim) {
+#ifdef Honor_FLT_ROUNDS
+				if (mode > 1)
+				switch(Rounding) {
+				  case 0: goto ret1;
+				  case 2: goto bump_up;
+				  }
+#endif
+				dval(&d) += dval(&d);
+#ifdef ROUND_BIASED
+				if (dval(&d) >= ds)
+#else
+				if (dval(&d) > ds || (dval(&d) == ds && L & 1))
+#endif
+					{
+ bump_up:
+					while(*--s == '9')
+						if (s == s0) {
+							k++;
+							*s = '0';
+							break;
+							}
+					++*s++;
+					}
+				break;
+				}
+			}
+		goto ret1;
+		}
+
+	m2 = b2;
+	m5 = b5;
+	mhi = mlo = 0;
+	if (leftright) {
+		i =
+#ifndef Sudden_Underflow
+			denorm ? be + (Bias + (P-1) - 1 + 1) :
+#endif
+#ifdef IBM
+			1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3);
+#else
+			1 + P - bbits;
+#endif
+		b2 += i;
+		s2 += i;
+		mhi = i2b(1);
+		if (mhi == NULL)
+			return (NULL);
+		}
+	if (m2 > 0 && s2 > 0) {
+		i = m2 < s2 ? m2 : s2;
+		b2 -= i;
+		m2 -= i;
+		s2 -= i;
+		}
+	if (b5 > 0) {
+		if (leftright) {
+			if (m5 > 0) {
+				mhi = pow5mult(mhi, m5);
+				if (mhi == NULL)
+					return (NULL);
+				b1 = mult(mhi, b);
+				if (b1 == NULL)
+					return (NULL);
+				Bfree(b);
+				b = b1;
+				}
+			if (( j = b5 - m5 )!=0) {
+				b = pow5mult(b, j);
+				if (b == NULL)
+					return (NULL);
+				}
+			}
+		else {
+			b = pow5mult(b, b5);
+			if (b == NULL)
+				return (NULL);
+			}
+		}
+	S = i2b(1);
+	if (S == NULL)
+		return (NULL);
+	if (s5 > 0) {
+		S = pow5mult(S, s5);
+		if (S == NULL)
+			return (NULL);
+		}
+
+	/* Check for special case that d is a normalized power of 2. */
+
+	spec_case = 0;
+	if ((mode < 2 || leftright)
+#ifdef Honor_FLT_ROUNDS
+			&& Rounding == 1
+#endif
+				) {
+		if (!word1(&d) && !(word0(&d) & Bndry_mask)
+#ifndef Sudden_Underflow
+		 && word0(&d) & (Exp_mask & ~Exp_msk1)
+#endif
+				) {
+			/* The special case */
+			b2 += Log2P;
+			s2 += Log2P;
+			spec_case = 1;
+			}
+		}
+
+	/* Arrange for convenient computation of quotients:
+	 * shift left if necessary so divisor has 4 leading 0 bits.
+	 *
+	 * Perhaps we should just compute leading 28 bits of S once
+	 * and for all and pass them and a shift to quorem, so it
+	 * can do shifts and ors to compute the numerator for q.
+	 */
+#ifdef Pack_32
+	if (( i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f )!=0)
+		i = 32 - i;
+#else
+	if (( i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf )!=0)
+		i = 16 - i;
+#endif
+	if (i > 4) {
+		i -= 4;
+		b2 += i;
+		m2 += i;
+		s2 += i;
+		}
+	else if (i < 4) {
+		i += 28;
+		b2 += i;
+		m2 += i;
+		s2 += i;
+		}
+	if (b2 > 0) {
+		b = lshift(b, b2);
+		if (b == NULL)
+			return (NULL);
+		}
+	if (s2 > 0) {
+		S = lshift(S, s2);
+		if (S == NULL)
+			return (NULL);
+		}
+	if (k_check) {
+		if (cmp(b,S) < 0) {
+			k--;
+			b = multadd(b, 10, 0);	/* we botched the k estimate */
+			if (b == NULL)
+				return (NULL);
+			if (leftright) {
+				mhi = multadd(mhi, 10, 0);
+				if (mhi == NULL)
+					return (NULL);
+				}
+			ilim = ilim1;
+			}
+		}
+	if (ilim <= 0 && (mode == 3 || mode == 5)) {
+		S = multadd(S,5,0);
+		if (S == NULL)
+			return (NULL);
+		if (ilim < 0 || cmp(b,S) <= 0) {
+			/* no digits, fcvt style */
+ no_digits:
+			k = -1 - ndigits;
+			goto ret;
+			}
+ one_digit:
+		*s++ = '1';
+		k++;
+		goto ret;
+		}
+	if (leftright) {
+		if (m2 > 0) {
+			mhi = lshift(mhi, m2);
+			if (mhi == NULL)
+				return (NULL);
+			}
+
+		/* Compute mlo -- check for special case
+		 * that d is a normalized power of 2.
+		 */
+
+		mlo = mhi;
+		if (spec_case) {
+			mhi = Balloc(mhi->k);
+			if (mhi == NULL)
+				return (NULL);
+			Bcopy(mhi, mlo);
+			mhi = lshift(mhi, Log2P);
+			if (mhi == NULL)
+				return (NULL);
+			}
+
+		for(i = 1;;i++) {
+			dig = quorem(b,S) + '0';
+			/* Do we yet have the shortest decimal string
+			 * that will round to d?
+			 */
+			j = cmp(b, mlo);
+			delta = diff(S, mhi);
+			if (delta == NULL)
+				return (NULL);
+			j1 = delta->sign ? 1 : cmp(b, delta);
+			Bfree(delta);
+#ifndef ROUND_BIASED
+			if (j1 == 0 && mode != 1 && !(word1(&d) & 1)
+#ifdef Honor_FLT_ROUNDS
+				&& Rounding >= 1
+#endif
+								   ) {
+				if (dig == '9')
+					goto round_9_up;
+				if (j > 0)
+					dig++;
+#ifdef SET_INEXACT
+				else if (!b->x[0] && b->wds <= 1)
+					inexact = 0;
+#endif
+				*s++ = dig;
+				goto ret;
+				}
+#endif
+			if (j < 0 || (j == 0 && mode != 1
+#ifndef ROUND_BIASED
+							&& !(word1(&d) & 1)
+#endif
+					)) {
+				if (!b->x[0] && b->wds <= 1) {
+#ifdef SET_INEXACT
+					inexact = 0;
+#endif
+					goto accept_dig;
+					}
+#ifdef Honor_FLT_ROUNDS
+				if (mode > 1)
+				 switch(Rounding) {
+				  case 0: goto accept_dig;
+				  case 2: goto keep_dig;
+				  }
+#endif /*Honor_FLT_ROUNDS*/
+				if (j1 > 0) {
+					b = lshift(b, 1);
+					if (b == NULL)
+						return (NULL);
+					j1 = cmp(b, S);
+#ifdef ROUND_BIASED
+					if (j1 >= 0 /*)*/
+#else
+					if ((j1 > 0 || (j1 == 0 && dig & 1))
+#endif
+					&& dig++ == '9')
+						goto round_9_up;
+					}
+ accept_dig:
+				*s++ = dig;
+				goto ret;
+				}
+			if (j1 > 0) {
+#ifdef Honor_FLT_ROUNDS
+				if (!Rounding)
+					goto accept_dig;
+#endif
+				if (dig == '9') { /* possible if i == 1 */
+ round_9_up:
+					*s++ = '9';
+					goto roundoff;
+					}
+				*s++ = dig + 1;
+				goto ret;
+				}
+#ifdef Honor_FLT_ROUNDS
+ keep_dig:
+#endif
+			*s++ = dig;
+			if (i == ilim)
+				break;
+			b = multadd(b, 10, 0);
+			if (b == NULL)
+				return (NULL);
+			if (mlo == mhi) {
+				mlo = mhi = multadd(mhi, 10, 0);
+				if (mlo == NULL)
+					return (NULL);
+				}
+			else {
+				mlo = multadd(mlo, 10, 0);
+				if (mlo == NULL)
+					return (NULL);
+				mhi = multadd(mhi, 10, 0);
+				if (mhi == NULL)
+					return (NULL);
+				}
+			}
+		}
+	else
+		for(i = 1;; i++) {
+			*s++ = dig = quorem(b,S) + '0';
+			if (!b->x[0] && b->wds <= 1) {
+#ifdef SET_INEXACT
+				inexact = 0;
+#endif
+				goto ret;
+				}
+			if (i >= ilim)
+				break;
+			b = multadd(b, 10, 0);
+			if (b == NULL)
+				return (NULL);
+			}
+
+	/* Round off last digit */
+
+#ifdef Honor_FLT_ROUNDS
+	switch(Rounding) {
+	  case 0: goto trimzeros;
+	  case 2: goto roundoff;
+	  }
+#endif
+	b = lshift(b, 1);
+	if (b == NULL)
+		return (NULL);
+	j = cmp(b, S);
+#ifdef ROUND_BIASED
+	if (j >= 0)
+#else
+	if (j > 0 || (j == 0 && dig & 1))
+#endif
+		{
+ roundoff:
+		while(*--s == '9')
+			if (s == s0) {
+				k++;
+				*s++ = '1';
+				goto ret;
+				}
+		++*s++;
+		}
+	else {
+#ifdef Honor_FLT_ROUNDS
+ trimzeros:
+#endif
+		while(*--s == '0');
+		s++;
+		}
+ ret:
+	Bfree(S);
+	if (mhi) {
+		if (mlo && mlo != mhi)
+			Bfree(mlo);
+		Bfree(mhi);
+		}
+ ret1:
+#ifdef SET_INEXACT
+	if (inexact) {
+		if (!oldinexact) {
+			word0(&d) = Exp_1 + (70 << Exp_shift);
+			word1(&d) = 0;
+			dval(&d) += 1.;
+			}
+		}
+	else if (!oldinexact)
+		clear_inexact();
+#endif
+	Bfree(b);
+	*s = 0;
+	*decpt = k + 1;
+	if (rve)
+		*rve = s;
+	return s0;
+}
diff --git a/newlib/libc/stdlib/gdtoa-gdtoa.c b/newlib/libc/stdlib/gdtoa-gdtoa.c
new file mode 100644
index 000000000..feae5afa3
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-gdtoa.c
@@ -0,0 +1,830 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998, 1999 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include "gdtoaimp.h"
+
+ static Bigint *
+#ifdef KR_headers
+bitstob(bits, nbits, bbits) ULong *bits; int nbits; int *bbits;
+#else
+bitstob(ULong *bits, int nbits, int *bbits)
+#endif
+{
+	int i, k;
+	Bigint *b;
+	ULong *be, *x, *x0;
+
+	i = ULbits;
+	k = 0;
+	while(i < nbits) {
+		i <<= 1;
+		k++;
+		}
+#ifndef Pack_32
+	if (!k)
+		k = 1;
+#endif
+	b = Balloc(k);
+	if (b == NULL)
+		return (NULL);
+	be = bits + ((nbits - 1) >> kshift);
+	x = x0 = b->x;
+	do {
+		*x++ = *bits & ALL_ON;
+#ifdef Pack_16
+		*x++ = (*bits >> 16) & ALL_ON;
+#endif
+		} while(++bits <= be);
+	i = x - x0;
+	while(!x0[--i])
+		if (!i) {
+			b->wds = 0;
+			*bbits = 0;
+			goto ret;
+			}
+	b->wds = i + 1;
+	*bbits = i*ULbits + 32 - hi0bits(b->x[i]);
+ ret:
+	return b;
+	}
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ *	1. Rather than iterating, we use a simple numeric overestimate
+ *	   to determine k = floor(log10(d)).  We scale relevant
+ *	   quantities using O(log2(k)) rather than O(k) multiplications.
+ *	2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ *	   try to generate digits strictly left to right.  Instead, we
+ *	   compute with fewer bits and propagate the carry if necessary
+ *	   when rounding the final digit up.  This is often faster.
+ *	3. Under the assumption that input will be rounded nearest,
+ *	   mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ *	   That is, we allow equality in stopping tests when the
+ *	   round-nearest rule will give the same floating-point value
+ *	   as would satisfaction of the stopping test with strict
+ *	   inequality.
+ *	4. We remove common factors of powers of 2 from relevant
+ *	   quantities.
+ *	5. When converting floating-point integers less than 1e16,
+ *	   we use floating-point arithmetic rather than resorting
+ *	   to multiple-precision integers.
+ *	6. When asked to produce fewer than 15 digits, we first try
+ *	   to get by with floating-point arithmetic; we resort to
+ *	   multiple-precision integer arithmetic only if we cannot
+ *	   guarantee that the floating-point calculation has given
+ *	   the correctly rounded result.  For k requested digits and
+ *	   "uniformly" distributed input, the probability is
+ *	   something like 10^(k-15) that we must resort to the Long
+ *	   calculation.
+ */
+
+ char *
+gdtoa
+#ifdef KR_headers
+	(fpi, be, bits, kindp, mode, ndigits, decpt, rve)
+	FPI *fpi; int be; ULong *bits;
+	int *kindp, mode, ndigits, *decpt; char **rve;
+#else
+	(FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, int *decpt, char **rve)
+#endif
+{
+ /*	Arguments ndigits and decpt are similar to the second and third
+	arguments of ecvt and fcvt; trailing zeros are suppressed from
+	the returned string.  If not null, *rve is set to point
+	to the end of the return value.  If d is +-Infinity or NaN,
+	then *decpt is set to 9999.
+	be = exponent: value = (integer represented by bits) * (2 to the power of be).
+
+	mode:
+		0 ==> shortest string that yields d when read in
+			and rounded to nearest.
+		1 ==> like 0, but with Steele & White stopping rule;
+			e.g. with IEEE P754 arithmetic , mode 0 gives
+			1e23 whereas mode 1 gives 9.999999999999999e22.
+		2 ==> max(1,ndigits) significant digits.  This gives a
+			return value similar to that of ecvt, except
+			that trailing zeros are suppressed.
+		3 ==> through ndigits past the decimal point.  This
+			gives a return value similar to that from fcvt,
+			except that trailing zeros are suppressed, and
+			ndigits can be negative.
+		4-9 should give the same return values as 2-3, i.e.,
+			4 <= mode <= 9 ==> same return as mode
+			2 + (mode & 1).  These modes are mainly for
+			debugging; often they run slower but sometimes
+			faster than modes 2-3.
+		4,5,8,9 ==> left-to-right digit generation.
+		6-9 ==> don't try fast floating-point estimate
+			(if applicable).
+
+		Values of mode other than 0-9 are treated as mode 0.
+
+		Sufficient space is allocated to the return value
+		to hold the suppressed trailing zeros.
+	*/
+
+	int bbits, b2, b5, be0, dig, i, ieps, ilim, ilim0, ilim1, inex;
+	int j, j1, k, k0, k_check, kind, leftright, m2, m5, nbits;
+	int rdir, s2, s5, spec_case, try_quick;
+	Long L;
+	Bigint *b, *b1, *delta, *mlo, *mhi, *mhi1, *S;
+	double d2, ds;
+	char *s, *s0;
+	U d, eps;
+
+#ifndef MULTIPLE_THREADS
+	if (dtoa_result) {
+		freedtoa(dtoa_result);
+		dtoa_result = 0;
+		}
+#endif
+	inex = 0;
+	kind = *kindp &= ~STRTOG_Inexact;
+	switch(kind & STRTOG_Retmask) {
+	  case STRTOG_Zero:
+		goto ret_zero;
+	  case STRTOG_Normal:
+	  case STRTOG_Denormal:
+		break;
+	  case STRTOG_Infinite:
+		*decpt = -32768;
+		return nrv_alloc("Infinity", rve, 8);
+	  case STRTOG_NaN:
+		*decpt = -32768;
+		return nrv_alloc("NaN", rve, 3);
+	  default:
+		return 0;
+	  }
+	b = bitstob(bits, nbits = fpi->nbits, &bbits);
+	if (b == NULL)
+		return (NULL);
+	be0 = be;
+	if ( (i = trailz(b)) !=0) {
+		rshift(b, i);
+		be += i;
+		bbits -= i;
+		}
+	if (!b->wds) {
+		Bfree(b);
+ ret_zero:
+		*decpt = 1;
+		return nrv_alloc("0", rve, 1);
+		}
+
+	dval(&d) = b2d(b, &i);
+	i = be + bbits - 1;
+	word0(&d) &= Frac_mask1;
+	word0(&d) |= Exp_11;
+#ifdef IBM
+	if ( (j = 11 - hi0bits(word0(&d) & Frac_mask)) !=0)
+		dval(&d) /= 1 << j;
+#endif
+
+	/* log(x)	~=~ log(1.5) + (x-1.5)/1.5
+	 * log10(x)	 =  log(x) / log(10)
+	 *		~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+	 * log10(&d) = (i-Bias)*log(2)/log(10) + log10(d2)
+	 *
+	 * This suggests computing an approximation k to log10(&d) by
+	 *
+	 * k = (i - Bias)*0.301029995663981
+	 *	+ ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+	 *
+	 * We want k to be too large rather than too small.
+	 * The error in the first-order Taylor series approximation
+	 * is in our favor, so we just round up the constant enough
+	 * to compensate for any error in the multiplication of
+	 * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+	 * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+	 * adding 1e-13 to the constant term more than suffices.
+	 * Hence we adjust the constant term to 0.1760912590558.
+	 * (We could get a more accurate k by invoking log10,
+	 *  but this is probably not worthwhile.)
+	 */
+#ifdef IBM
+	i <<= 2;
+	i += j;
+#endif
+	ds = (dval(&d)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
+
+	/* correct assumption about exponent range */
+	if ((j = i) < 0)
+		j = -j;
+	if ((j -= 1077) > 0)
+		ds += j * 7e-17;
+
+	k = (int)ds;
+	if (ds < 0. && ds != k)
+		k--;	/* want k = floor(ds) */
+	k_check = 1;
+#ifdef IBM
+	j = be + bbits - 1;
+	if ( (j1 = j & 3) !=0)
+		dval(&d) *= 1 << j1;
+	word0(&d) += j << Exp_shift - 2 & Exp_mask;
+#else
+	word0(&d) += (be + bbits - 1) << Exp_shift;
+#endif
+	if (k >= 0 && k <= Ten_pmax) {
+		if (dval(&d) < tens[k])
+			k--;
+		k_check = 0;
+		}
+	j = bbits - i - 1;
+	if (j >= 0) {
+		b2 = 0;
+		s2 = j;
+		}
+	else {
+		b2 = -j;
+		s2 = 0;
+		}
+	if (k >= 0) {
+		b5 = 0;
+		s5 = k;
+		s2 += k;
+		}
+	else {
+		b2 -= k;
+		b5 = -k;
+		s5 = 0;
+		}
+	if (mode < 0 || mode > 9)
+		mode = 0;
+	try_quick = 1;
+	if (mode > 5) {
+		mode -= 4;
+		try_quick = 0;
+		}
+	else if (i >= -4 - Emin || i < Emin)
+		try_quick = 0;
+	leftright = 1;
+	ilim = ilim1 = -1;	/* Values for cases 0 and 1; done here to */
+				/* silence erroneous "gcc -Wall" warning. */
+	switch(mode) {
+		case 0:
+		case 1:
+			i = (int)(nbits * .30103) + 3;
+			ndigits = 0;
+			break;
+		case 2:
+			leftright = 0;
+			/* no break */
+		case 4:
+			if (ndigits <= 0)
+				ndigits = 1;
+			ilim = ilim1 = i = ndigits;
+			break;
+		case 3:
+			leftright = 0;
+			/* no break */
+		case 5:
+			i = ndigits + k + 1;
+			ilim = i;
+			ilim1 = i - 1;
+			if (i <= 0)
+				i = 1;
+		}
+	s = s0 = rv_alloc(i);
+	if (s == NULL)
+		return (NULL);
+
+	if ( (rdir = fpi->rounding - 1) !=0) {
+		if (rdir < 0)
+			rdir = 2;
+		if (kind & STRTOG_Neg)
+			rdir = 3 - rdir;
+		}
+
+	/* Now rdir = 0 ==> round near, 1 ==> round up, 2 ==> round down. */
+
+	if (ilim >= 0 && ilim <= Quick_max && try_quick && !rdir
+#ifndef IMPRECISE_INEXACT
+		&& k == 0
+#endif
+								) {
+
+		/* Try to get by with floating-point arithmetic. */
+
+		i = 0;
+		d2 = dval(&d);
+#ifdef IBM
+		if ( (j = 11 - hi0bits(word0(&d) & Frac_mask)) !=0)
+			dval(&d) /= 1 << j;
+#endif
+		k0 = k;
+		ilim0 = ilim;
+		ieps = 2; /* conservative */
+		if (k > 0) {
+			ds = tens[k&0xf];
+			j = k >> 4;
+			if (j & Bletch) {
+				/* prevent overflows */
+				j &= Bletch - 1;
+				dval(&d) /= bigtens[n_bigtens-1];
+				ieps++;
+				}
+			for(; j; j >>= 1, i++)
+				if (j & 1) {
+					ieps++;
+					ds *= bigtens[i];
+					}
+			}
+		else  {
+			ds = 1.;
+			if ( (j1 = -k) !=0) {
+				dval(&d) *= tens[j1 & 0xf];
+				for(j = j1 >> 4; j; j >>= 1, i++)
+					if (j & 1) {
+						ieps++;
+						dval(&d) *= bigtens[i];
+						}
+				}
+			}
+		if (k_check && dval(&d) < 1. && ilim > 0) {
+			if (ilim1 <= 0)
+				goto fast_failed;
+			ilim = ilim1;
+			k--;
+			dval(&d) *= 10.;
+			ieps++;
+			}
+		dval(&eps) = ieps*dval(&d) + 7.;
+		word0(&eps) -= (P-1)*Exp_msk1;
+		if (ilim == 0) {
+			S = mhi = 0;
+			dval(&d) -= 5.;
+			if (dval(&d) > dval(&eps))
+				goto one_digit;
+			if (dval(&d) < -dval(&eps))
+				goto no_digits;
+			goto fast_failed;
+			}
+#ifndef No_leftright
+		if (leftright) {
+			/* Use Steele & White method of only
+			 * generating digits needed.
+			 */
+			dval(&eps) = ds*0.5/tens[ilim-1] - dval(&eps);
+			for(i = 0;;) {
+				L = (Long)(dval(&d)/ds);
+				dval(&d) -= L*ds;
+				*s++ = '0' + (int)L;
+				if (dval(&d) < dval(&eps)) {
+					if (dval(&d))
+						inex = STRTOG_Inexlo;
+					goto ret1;
+					}
+				if (ds - dval(&d) < dval(&eps))
+					goto bump_up;
+				if (++i >= ilim)
+					break;
+				dval(&eps) *= 10.;
+				dval(&d) *= 10.;
+				}
+			}
+		else {
+#endif
+			/* Generate ilim digits, then fix them up. */
+			dval(&eps) *= tens[ilim-1];
+			for(i = 1;; i++, dval(&d) *= 10.) {
+				if ( (L = (Long)(dval(&d)/ds)) !=0)
+					dval(&d) -= L*ds;
+				*s++ = '0' + (int)L;
+				if (i == ilim) {
+					ds *= 0.5;
+					if (dval(&d) > ds + dval(&eps))
+						goto bump_up;
+					else if (dval(&d) < ds - dval(&eps)) {
+						if (dval(&d))
+							inex = STRTOG_Inexlo;
+						goto clear_trailing0;
+						}
+					break;
+					}
+				}
+#ifndef No_leftright
+			}
+#endif
+ fast_failed:
+		s = s0;
+		dval(&d) = d2;
+		k = k0;
+		ilim = ilim0;
+		}
+
+	/* Do we have a "small" integer? */
+
+	if (be >= 0 && k <= Int_max) {
+		/* Yes. */
+		ds = tens[k];
+		if (ndigits < 0 && ilim <= 0) {
+			S = mhi = 0;
+			if (ilim < 0 || dval(&d) <= 5*ds)
+				goto no_digits;
+			goto one_digit;
+			}
+		for(i = 1;; i++, dval(&d) *= 10.) {
+			L = dval(&d) / ds;
+			dval(&d) -= L*ds;
+#ifdef Check_FLT_ROUNDS
+			/* If FLT_ROUNDS == 2, L will usually be high by 1 */
+			if (dval(&d) < 0) {
+				L--;
+				dval(&d) += ds;
+				}
+#endif
+			*s++ = '0' + (int)L;
+			if (dval(&d) == 0.)
+				break;
+			if (i == ilim) {
+				if (rdir) {
+					if (rdir == 1)
+						goto bump_up;
+					inex = STRTOG_Inexlo;
+					goto ret1;
+					}
+				dval(&d) += dval(&d);
+#ifdef ROUND_BIASED
+				if (dval(&d) >= ds)
+#else
+				if (dval(&d) > ds || (dval(&d) == ds && L & 1))
+#endif
+					{
+ bump_up:
+					inex = STRTOG_Inexhi;
+					while(*--s == '9')
+						if (s == s0) {
+							k++;
+							*s = '0';
+							break;
+							}
+					++*s++;
+					}
+				else {
+					inex = STRTOG_Inexlo;
+ clear_trailing0:
+					while(*--s == '0'){}
+					++s;
+					}
+				break;
+				}
+			}
+		goto ret1;
+		}
+
+	m2 = b2;
+	m5 = b5;
+	mhi = mlo = 0;
+	if (leftright) {
+		i = nbits - bbits;
+		if (be - i++ < fpi->emin && mode != 3 && mode != 5) {
+			/* denormal */
+			i = be - fpi->emin + 1;
+			if (mode >= 2 && ilim > 0 && ilim < i)
+				goto small_ilim;
+			}
+		else if (mode >= 2) {
+ small_ilim:
+			j = ilim - 1;
+			if (m5 >= j)
+				m5 -= j;
+			else {
+				s5 += j -= m5;
+				b5 += j;
+				m5 = 0;
+				}
+			if ((i = ilim) < 0) {
+				m2 -= i;
+				i = 0;
+				}
+			}
+		b2 += i;
+		s2 += i;
+		mhi = i2b(1);
+		if (mhi == NULL)
+			return (NULL);
+		}
+	if (m2 > 0 && s2 > 0) {
+		i = m2 < s2 ? m2 : s2;
+		b2 -= i;
+		m2 -= i;
+		s2 -= i;
+		}
+	if (b5 > 0) {
+		if (leftright) {
+			if (m5 > 0) {
+				mhi = pow5mult(mhi, m5);
+				if (mhi == NULL)
+					return (NULL);
+				b1 = mult(mhi, b);
+				if (b1 == NULL)
+					return (NULL);
+				Bfree(b);
+				b = b1;
+				}
+			if ( (j = b5 - m5) !=0) {
+				b = pow5mult(b, j);
+				if (b == NULL)
+					return (NULL);
+				}
+			}
+		else {
+			b = pow5mult(b, b5);
+			if (b == NULL)
+				return (NULL);
+			}
+		}
+	S = i2b(1);
+	if (S == NULL)
+		return (NULL);
+	if (s5 > 0) {
+		S = pow5mult(S, s5);
+		if (S == NULL)
+			return (NULL);
+		}
+
+	/* Check for special case that d is a normalized power of 2. */
+
+	spec_case = 0;
+	if (mode < 2) {
+		if (bbits == 1 && be0 > fpi->emin + 1) {
+			/* The special case */
+			b2++;
+			s2++;
+			spec_case = 1;
+			}
+		}
+
+	/* Arrange for convenient computation of quotients:
+	 * shift left if necessary so divisor has 4 leading 0 bits.
+	 *
+	 * Perhaps we should just compute leading 28 bits of S once
+	 * and for all and pass them and a shift to quorem, so it
+	 * can do shifts and ors to compute the numerator for q.
+	 */
+	i = ((s5 ? hi0bits(S->x[S->wds-1]) : ULbits - 1) - s2 - 4) & kmask;
+	m2 += i;
+	if ((b2 += i) > 0) {
+		b = lshift(b, b2);
+		if (b == NULL)
+			return (NULL);
+		}
+	if ((s2 += i) > 0) {
+		S = lshift(S, s2);
+		if (S == NULL)
+			return (NULL);
+		}
+	if (k_check) {
+		if (cmp(b,S) < 0) {
+			k--;
+			b = multadd(b, 10, 0);	/* we botched the k estimate */
+			if (b == NULL)
+				return (NULL);
+			if (leftright) {
+				mhi = multadd(mhi, 10, 0);
+				if (mhi == NULL)
+					return (NULL);
+				}
+			ilim = ilim1;
+			}
+		}
+	if (ilim <= 0 && mode > 2) {
+		S = multadd(S,5,0);
+		if (S == NULL)
+			return (NULL);
+		if (ilim < 0 || cmp(b,S) <= 0) {
+			/* no digits, fcvt style */
+ no_digits:
+			k = -1 - ndigits;
+			inex = STRTOG_Inexlo;
+			goto ret;
+			}
+ one_digit:
+		inex = STRTOG_Inexhi;
+		*s++ = '1';
+		k++;
+		goto ret;
+		}
+	if (leftright) {
+		if (m2 > 0) {
+			mhi = lshift(mhi, m2);
+			if (mhi == NULL)
+				return (NULL);
+			}
+
+		/* Compute mlo -- check for special case
+		 * that d is a normalized power of 2.
+		 */
+
+		mlo = mhi;
+		if (spec_case) {
+			mhi = Balloc(mhi->k);
+			if (mhi == NULL)
+				return (NULL);
+			Bcopy(mhi, mlo);
+			mhi = lshift(mhi, 1);
+			if (mhi == NULL)
+				return (NULL);
+			}
+
+		for(i = 1;;i++) {
+			dig = quorem(b,S) + '0';
+			/* Do we yet have the shortest decimal string
+			 * that will round to d?
+			 */
+			j = cmp(b, mlo);
+			delta = diff(S, mhi);
+			if (delta == NULL)
+				return (NULL);
+			j1 = delta->sign ? 1 : cmp(b, delta);
+			Bfree(delta);
+#ifndef ROUND_BIASED
+			if (j1 == 0 && !mode && !(bits[0] & 1) && !rdir) {
+				if (dig == '9')
+					goto round_9_up;
+				if (j <= 0) {
+					if (b->wds > 1 || b->x[0])
+						inex = STRTOG_Inexlo;
+					}
+				else {
+					dig++;
+					inex = STRTOG_Inexhi;
+					}
+				*s++ = dig;
+				goto ret;
+				}
+#endif
+			if (j < 0 || (j == 0 && !mode
+#ifndef ROUND_BIASED
+							&& !(bits[0] & 1)
+#endif
+					)) {
+				if (rdir && (b->wds > 1 || b->x[0])) {
+					if (rdir == 2) {
+						inex = STRTOG_Inexlo;
+						goto accept;
+						}
+					while (cmp(S,mhi) > 0) {
+						*s++ = dig;
+						mhi1 = multadd(mhi, 10, 0);
+						if (mhi1 == NULL)
+							return (NULL);
+						if (mlo == mhi)
+							mlo = mhi1;
+						mhi = mhi1;
+						b = multadd(b, 10, 0);
+						if (b == NULL)
+							return (NULL);
+						dig = quorem(b,S) + '0';
+						}
+					if (dig++ == '9')
+						goto round_9_up;
+					inex = STRTOG_Inexhi;
+					goto accept;
+					}
+				if (j1 > 0) {
+					b = lshift(b, 1);
+					if (b == NULL)
+						return (NULL);
+					j1 = cmp(b, S);
+#ifdef ROUND_BIASED
+					if (j1 >= 0 /*)*/
+#else
+					if ((j1 > 0 || (j1 == 0 && dig & 1))
+#endif
+					&& dig++ == '9')
+						goto round_9_up;
+					inex = STRTOG_Inexhi;
+					}
+				if (b->wds > 1 || b->x[0])
+					inex = STRTOG_Inexlo;
+ accept:
+				*s++ = dig;
+				goto ret;
+				}
+			if (j1 > 0 && rdir != 2) {
+				if (dig == '9') { /* possible if i == 1 */
+ round_9_up:
+					*s++ = '9';
+					inex = STRTOG_Inexhi;
+					goto roundoff;
+					}
+				inex = STRTOG_Inexhi;
+				*s++ = dig + 1;
+				goto ret;
+				}
+			*s++ = dig;
+			if (i == ilim)
+				break;
+			b = multadd(b, 10, 0);
+			if (b == NULL)
+				return (NULL);
+			if (mlo == mhi) {
+				mlo = mhi = multadd(mhi, 10, 0);
+				if (mlo == NULL)
+					return (NULL);
+				}
+			else {
+				mlo = multadd(mlo, 10, 0);
+				if (mlo == NULL)
+					return (NULL);
+				mhi = multadd(mhi, 10, 0);
+				if (mhi == NULL)
+					return (NULL);
+				}
+			}
+		}
+	else
+		for(i = 1;; i++) {
+			*s++ = dig = quorem(b,S) + '0';
+			if (i >= ilim)
+				break;
+			b = multadd(b, 10, 0);
+			if (b == NULL)
+				return (NULL);
+			}
+
+	/* Round off last digit */
+
+	if (rdir) {
+		if (rdir == 2 || (b->wds <= 1 && !b->x[0]))
+			goto chopzeros;
+		goto roundoff;
+		}
+	b = lshift(b, 1);
+	if (b == NULL)
+		return (NULL);
+	j = cmp(b, S);
+#ifdef ROUND_BIASED
+	if (j >= 0)
+#else
+	if (j > 0 || (j == 0 && dig & 1))
+#endif
+		{
+ roundoff:
+		inex = STRTOG_Inexhi;
+		while(*--s == '9')
+			if (s == s0) {
+				k++;
+				*s++ = '1';
+				goto ret;
+				}
+		++*s++;
+		}
+	else {
+ chopzeros:
+		if (b->wds > 1 || b->x[0])
+			inex = STRTOG_Inexlo;
+		while(*--s == '0'){}
+		++s;
+		}
+ ret:
+	Bfree(S);
+	if (mhi) {
+		if (mlo && mlo != mhi)
+			Bfree(mlo);
+		Bfree(mhi);
+		}
+ ret1:
+	Bfree(b);
+	*s = 0;
+	*decpt = k + 1;
+	if (rve)
+		*rve = s;
+	*kindp |= inex;
+	return s0;
+	}
+DEF_STRONG(gdtoa);
diff --git a/newlib/libc/stdlib/gdtoa-gmisc.c b/newlib/libc/stdlib/gdtoa-gmisc.c
new file mode 100644
index 000000000..8270ef944
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-gmisc.c
@@ -0,0 +1,86 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include "gdtoaimp.h"
+
+ void
+#ifdef KR_headers
+rshift(b, k) Bigint *b; int k;
+#else
+rshift(Bigint *b, int k)
+#endif
+{
+	ULong *x, *x1, *xe, y;
+	int n;
+
+	x = x1 = b->x;
+	n = k >> kshift;
+	if (n < b->wds) {
+		xe = x + b->wds;
+		x += n;
+		if (k &= kmask) {
+			n = ULbits - k;
+			y = *x++ >> k;
+			while(x < xe) {
+				*x1++ = (y | (*x << n)) & ALL_ON;
+				y = *x++ >> k;
+				}
+			if ((*x1 = y) !=0)
+				x1++;
+			}
+		else
+			while(x < xe)
+				*x1++ = *x++;
+		}
+	if ((b->wds = x1 - b->x) == 0)
+		b->x[0] = 0;
+	}
+
+ int
+#ifdef KR_headers
+trailz(b) Bigint *b;
+#else
+trailz(Bigint *b)
+#endif
+{
+	ULong L, *x, *xe;
+	int n = 0;
+
+	x = b->x;
+	xe = x + b->wds;
+	for(n = 0; x < xe && !*x; x++)
+		n += ULbits;
+	if (x < xe) {
+		L = *x;
+		n += lo0bits(&L);
+		}
+	return n;
+	}
diff --git a/newlib/libc/stdlib/gdtoa-ldtoa.c b/newlib/libc/stdlib/gdtoa-ldtoa.c
new file mode 100644
index 000000000..7282e7a39
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-ldtoa.c
@@ -0,0 +1,124 @@
+/*	$OpenBSD: ldtoa.c,v 1.4 2016/03/09 16:28:47 deraadt Exp $	*/
+/*-
+ * Copyright (c) 2003 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <machine/ieee.h>
+#include <float.h>
+#include <stdint.h>
+#include <limits.h>
+#include <math.h>
+#include <stdlib.h>
+#include "gdtoaimp.h"
+
+#if (LDBL_MANT_DIG > DBL_MANT_DIG)
+
+/*
+ * ldtoa() is a wrapper for gdtoa() that makes it smell like dtoa(),
+ * except that the floating point argument is passed by reference.
+ * When dtoa() is passed a NaN or infinity, it sets expt to 9999.
+ * However, a long double could have a valid exponent of 9999, so we
+ * use INT_MAX in ldtoa() instead.
+ */
+char *
+__ldtoa(long double *ld, int mode, int ndigits, int *decpt, int *sign,
+    char **rve)
+{
+	FPI fpi = {
+		LDBL_MANT_DIG,			/* nbits */
+		LDBL_MIN_EXP - LDBL_MANT_DIG,	/* emin */
+		LDBL_MAX_EXP - LDBL_MANT_DIG,	/* emax */
+		FLT_ROUNDS,	       		/* rounding */
+#ifdef Sudden_Underflow	/* unused, but correct anyway */
+		1
+#else
+		0
+#endif
+	};
+	int be, kind;
+	char *ret;
+	struct ieee_ext *p = (struct ieee_ext *)ld;
+	uint32_t bits[(LDBL_MANT_DIG + 31) / 32];
+	void *vbits = bits;
+
+	/*
+	 * gdtoa doesn't know anything about the sign of the number, so
+	 * if the number is negative, we need to swap rounding modes of
+	 * 2 (upwards) and 3 (downwards).
+	 */
+	*sign = p->ext_sign;
+	fpi.rounding ^= (fpi.rounding >> 1) & p->ext_sign;
+
+	be = p->ext_exp - (LDBL_MAX_EXP - 1) - (LDBL_MANT_DIG - 1);
+	EXT_TO_ARRAY32(p, bits);
+
+	switch (fpclassify(*ld)) {
+	case FP_NORMAL:
+		kind = STRTOG_Normal;
+#ifdef EXT_IMPLICIT_NBIT
+		bits[LDBL_MANT_DIG / 32] |= 1 << ((LDBL_MANT_DIG - 1) % 32);
+#endif /* EXT_IMPLICIT_NBIT */
+		break;
+	case FP_ZERO:
+		kind = STRTOG_Zero;
+		break;
+	case FP_SUBNORMAL:
+		kind = STRTOG_Denormal;
+		be++;
+		break;
+	case FP_INFINITE:
+		kind = STRTOG_Infinite;
+		break;
+	case FP_NAN:
+		kind = STRTOG_NaN;
+		break;
+	default:
+		abort();
+	}
+
+	ret = gdtoa(&fpi, be, vbits, &kind, mode, ndigits, decpt, rve);
+	if (*decpt == -32768)
+		*decpt = INT_MAX;
+	return ret;
+}
+DEF_STRONG(__ldtoa);
+
+#else   /* (LDBL_MANT_DIG == DBL_MANT_DIG) */
+
+char *
+__ldtoa(long double *ld, int mode, int ndigits, int *decpt, int *sign,
+    char **rve)
+{
+	char *ret;
+
+	ret = dtoa((double)*ld, mode, ndigits, decpt, sign, rve);
+	if (*decpt == 9999)
+		*decpt = INT_MAX;
+	return ret;
+}
+DEF_STRONG(__ldtoa);
+
+#endif  /* (LDBL_MANT_DIG == DBL_MANT_DIG) */
diff --git a/newlib/libc/stdlib/gdtoa-misc.c b/newlib/libc/stdlib/gdtoa-misc.c
new file mode 100644
index 000000000..5d1e0ad69
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-misc.c
@@ -0,0 +1,912 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998, 1999 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include "gdtoaimp.h"
+
+ static Bigint *freelist[Kmax+1];
+#ifndef Omit_Private_Memory
+#ifndef PRIVATE_MEM
+#define PRIVATE_MEM 2304
+#endif
+#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double))
+static double private_mem[PRIVATE_mem], *pmem_next = private_mem;
+#endif
+
+#ifdef MULTIPLE_THREADS
+__LOCK_INIT(static, __dtoa_lock0);
+__LOCK_INIT(static, __dtoa_lock1);
+#endif
+
+ Bigint *
+Balloc
+#ifdef KR_headers
+	(k) int k;
+#else
+	(int k)
+#endif
+{
+	int x;
+	Bigint *rv;
+#ifndef Omit_Private_Memory
+	unsigned int len;
+#endif
+
+	ACQUIRE_DTOA_LOCK(0);
+	/* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */
+	/* but this case seems very unlikely. */
+	if (k <= Kmax && (rv = freelist[k]) !=0) {
+		freelist[k] = rv->next;
+		}
+	else {
+		x = 1 << k;
+#ifdef Omit_Private_Memory
+		rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong));
+		if (rv == NULL)
+			return (NULL);
+#else
+		len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1)
+			/sizeof(double);
+		if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem) {
+			rv = (Bigint*)pmem_next;
+			pmem_next += len;
+			}
+		else {
+			rv = (Bigint*)MALLOC(len*sizeof(double));
+			if (rv == NULL)
+				return (NULL);
+		}
+#endif
+		rv->k = k;
+		rv->maxwds = x;
+		}
+	FREE_DTOA_LOCK(0);
+	rv->sign = rv->wds = 0;
+	return rv;
+	}
+
+ void
+Bfree
+#ifdef KR_headers
+	(v) Bigint *v;
+#else
+	(Bigint *v)
+#endif
+{
+	if (v) {
+		if (v->k > Kmax)
+#ifdef FREE
+			FREE(v);
+#else
+			free(v);
+#endif
+		else {
+			ACQUIRE_DTOA_LOCK(0);
+			v->next = freelist[v->k];
+			freelist[v->k] = v;
+			FREE_DTOA_LOCK(0);
+			}
+		}
+	}
+
+ int
+lo0bits
+#ifdef KR_headers
+	(y) ULong *y;
+#else
+	(ULong *y)
+#endif
+{
+	int k;
+	ULong x = *y;
+
+	if (x & 7) {
+		if (x & 1)
+			return 0;
+		if (x & 2) {
+			*y = x >> 1;
+			return 1;
+			}
+		*y = x >> 2;
+		return 2;
+		}
+	k = 0;
+	if (!(x & 0xffff)) {
+		k = 16;
+		x >>= 16;
+		}
+	if (!(x & 0xff)) {
+		k += 8;
+		x >>= 8;
+		}
+	if (!(x & 0xf)) {
+		k += 4;
+		x >>= 4;
+		}
+	if (!(x & 0x3)) {
+		k += 2;
+		x >>= 2;
+		}
+	if (!(x & 1)) {
+		k++;
+		x >>= 1;
+		if (!x)
+			return 32;
+		}
+	*y = x;
+	return k;
+	}
+
+ Bigint *
+multadd
+#ifdef KR_headers
+	(b, m, a) Bigint *b; int m, a;
+#else
+	(Bigint *b, int m, int a)	/* multiply by m and add a */
+#endif
+{
+	int i, wds;
+#ifdef ULLong
+	ULong *x;
+	ULLong carry, y;
+#else
+	ULong carry, *x, y;
+#ifdef Pack_32
+	ULong xi, z;
+#endif
+#endif
+	Bigint *b1;
+
+	wds = b->wds;
+	x = b->x;
+	i = 0;
+	carry = a;
+	do {
+#ifdef ULLong
+		y = *x * (ULLong)m + carry;
+		carry = y >> 32;
+		*x++ = y & 0xffffffffUL;
+#else
+#ifdef Pack_32
+		xi = *x;
+		y = (xi & 0xffff) * m + carry;
+		z = (xi >> 16) * m + (y >> 16);
+		carry = z >> 16;
+		*x++ = (z << 16) + (y & 0xffff);
+#else
+		y = *x * m + carry;
+		carry = y >> 16;
+		*x++ = y & 0xffff;
+#endif
+#endif
+		}
+		while(++i < wds);
+	if (carry) {
+		if (wds >= b->maxwds) {
+			b1 = Balloc(b->k+1);
+			if (b1 == NULL)
+				return (NULL);
+			Bcopy(b1, b);
+			Bfree(b);
+			b = b1;
+			}
+		b->x[wds++] = carry;
+		b->wds = wds;
+		}
+	return b;
+	}
+
+ int
+hi0bits_D2A
+#ifdef KR_headers
+	(x) ULong x;
+#else
+	(ULong x)
+#endif
+{
+	int k = 0;
+
+	if (!(x & 0xffff0000)) {
+		k = 16;
+		x <<= 16;
+		}
+	if (!(x & 0xff000000)) {
+		k += 8;
+		x <<= 8;
+		}
+	if (!(x & 0xf0000000)) {
+		k += 4;
+		x <<= 4;
+		}
+	if (!(x & 0xc0000000)) {
+		k += 2;
+		x <<= 2;
+		}
+	if (!(x & 0x80000000)) {
+		k++;
+		if (!(x & 0x40000000))
+			return 32;
+		}
+	return k;
+	}
+
+ Bigint *
+i2b
+#ifdef KR_headers
+	(i) int i;
+#else
+	(int i)
+#endif
+{
+	Bigint *b;
+
+	b = Balloc(1);
+	if (b == NULL)
+		return (NULL);
+	b->x[0] = i;
+	b->wds = 1;
+	return b;
+	}
+
+ Bigint *
+mult
+#ifdef KR_headers
+	(a, b) Bigint *a, *b;
+#else
+	(Bigint *a, Bigint *b)
+#endif
+{
+	Bigint *c;
+	int k, wa, wb, wc;
+	ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0;
+	ULong y;
+#ifdef ULLong
+	ULLong carry, z;
+#else
+	ULong carry, z;
+#ifdef Pack_32
+	ULong z2;
+#endif
+#endif
+
+	if (a->wds < b->wds) {
+		c = a;
+		a = b;
+		b = c;
+		}
+	k = a->k;
+	wa = a->wds;
+	wb = b->wds;
+	wc = wa + wb;
+	if (wc > a->maxwds)
+		k++;
+	c = Balloc(k);
+	if (c == NULL)
+		return (NULL);
+	for(x = c->x, xa = x + wc; x < xa; x++)
+		*x = 0;
+	xa = a->x;
+	xae = xa + wa;
+	xb = b->x;
+	xbe = xb + wb;
+	xc0 = c->x;
+#ifdef ULLong
+	for(; xb < xbe; xc0++) {
+		if ( (y = *xb++) !=0) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			do {
+				z = *x++ * (ULLong)y + *xc + carry;
+				carry = z >> 32;
+				*xc++ = z & 0xffffffffUL;
+				}
+				while(x < xae);
+			*xc = carry;
+			}
+		}
+#else
+#ifdef Pack_32
+	for(; xb < xbe; xb++, xc0++) {
+		if ( (y = *xb & 0xffff) !=0) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			do {
+				z = (*x & 0xffff) * y + (*xc & 0xffff) + carry;
+				carry = z >> 16;
+				z2 = (*x++ >> 16) * y + (*xc >> 16) + carry;
+				carry = z2 >> 16;
+				Storeinc(xc, z2, z);
+				}
+				while(x < xae);
+			*xc = carry;
+			}
+		if ( (y = *xb >> 16) !=0) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			z2 = *xc;
+			do {
+				z = (*x & 0xffff) * y + (*xc >> 16) + carry;
+				carry = z >> 16;
+				Storeinc(xc, z, z2);
+				z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry;
+				carry = z2 >> 16;
+				}
+				while(x < xae);
+			*xc = z2;
+			}
+		}
+#else
+	for(; xb < xbe; xc0++) {
+		if ( (y = *xb++) !=0) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			do {
+				z = *x++ * y + *xc + carry;
+				carry = z >> 16;
+				*xc++ = z & 0xffff;
+				}
+				while(x < xae);
+			*xc = carry;
+			}
+		}
+#endif
+#endif
+	for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ;
+	c->wds = wc;
+	return c;
+	}
+
+ static Bigint *p5s;
+
+ Bigint *
+pow5mult
+#ifdef KR_headers
+	(b, k) Bigint *b; int k;
+#else
+	(Bigint *b, int k)
+#endif
+{
+	Bigint *b1, *p5, *p51;
+	int i;
+	static int p05[3] = { 5, 25, 125 };
+
+	if ( (i = k & 3) !=0) {
+		b = multadd(b, p05[i-1], 0);
+		if (b == NULL)
+			return (NULL);
+		}
+
+	if (!(k >>= 2))
+		return b;
+	if ((p5 = p5s) == 0) {
+		/* first time */
+#ifdef MULTIPLE_THREADS
+		ACQUIRE_DTOA_LOCK(1);
+		if (!(p5 = p5s)) {
+			p5 = p5s = i2b(625);
+			if (p5 == NULL)
+				return (NULL);
+			p5->next = 0;
+			}
+		FREE_DTOA_LOCK(1);
+#else
+		p5 = p5s = i2b(625);
+		if (p5 == NULL)
+			return (NULL);
+		p5->next = 0;
+#endif
+		}
+	for(;;) {
+		if (k & 1) {
+			b1 = mult(b, p5);
+			if (b1 == NULL)
+				return (NULL);
+			Bfree(b);
+			b = b1;
+			}
+		if (!(k >>= 1))
+			break;
+		if ((p51 = p5->next) == 0) {
+#ifdef MULTIPLE_THREADS
+			ACQUIRE_DTOA_LOCK(1);
+			if (!(p51 = p5->next)) {
+				p51 = p5->next = mult(p5,p5);
+				if (p51 == NULL)
+					return (NULL);
+				p51->next = 0;
+				}
+			FREE_DTOA_LOCK(1);
+#else
+			p51 = p5->next = mult(p5,p5);
+			if (p51 == NULL)
+				return (NULL);
+			p51->next = 0;
+#endif
+			}
+		p5 = p51;
+		}
+	return b;
+	}
+
+ Bigint *
+lshift
+#ifdef KR_headers
+	(b, k) Bigint *b; int k;
+#else
+	(Bigint *b, int k)
+#endif
+{
+	int i, k1, n, n1;
+	Bigint *b1;
+	ULong *x, *x1, *xe, z;
+
+	n = k >> kshift;
+	k1 = b->k;
+	n1 = n + b->wds + 1;
+	for(i = b->maxwds; n1 > i; i <<= 1)
+		k1++;
+	b1 = Balloc(k1);
+	if (b1 == NULL)
+		return (NULL);
+	x1 = b1->x;
+	for(i = 0; i < n; i++)
+		*x1++ = 0;
+	x = b->x;
+	xe = x + b->wds;
+	if (k &= kmask) {
+#ifdef Pack_32
+		k1 = 32 - k;
+		z = 0;
+		do {
+			*x1++ = *x << k | z;
+			z = *x++ >> k1;
+			}
+			while(x < xe);
+		if ((*x1 = z) !=0)
+			++n1;
+#else
+		k1 = 16 - k;
+		z = 0;
+		do {
+			*x1++ = *x << k  & 0xffff | z;
+			z = *x++ >> k1;
+			}
+			while(x < xe);
+		if (*x1 = z)
+			++n1;
+#endif
+		}
+	else do
+		*x1++ = *x++;
+		while(x < xe);
+	b1->wds = n1 - 1;
+	Bfree(b);
+	return b1;
+	}
+
+ int
+cmp
+#ifdef KR_headers
+	(a, b) Bigint *a, *b;
+#else
+	(Bigint *a, Bigint *b)
+#endif
+{
+	ULong *xa, *xa0, *xb, *xb0;
+	int i, j;
+
+	i = a->wds;
+	j = b->wds;
+#ifdef DEBUG
+	if (i > 1 && !a->x[i-1])
+		Bug("cmp called with a->x[a->wds-1] == 0");
+	if (j > 1 && !b->x[j-1])
+		Bug("cmp called with b->x[b->wds-1] == 0");
+#endif
+	if (i -= j)
+		return i;
+	xa0 = a->x;
+	xa = xa0 + j;
+	xb0 = b->x;
+	xb = xb0 + j;
+	for(;;) {
+		if (*--xa != *--xb)
+			return *xa < *xb ? -1 : 1;
+		if (xa <= xa0)
+			break;
+		}
+	return 0;
+	}
+
+ Bigint *
+diff
+#ifdef KR_headers
+	(a, b) Bigint *a, *b;
+#else
+	(Bigint *a, Bigint *b)
+#endif
+{
+	Bigint *c;
+	int i, wa, wb;
+	ULong *xa, *xae, *xb, *xbe, *xc;
+#ifdef ULLong
+	ULLong borrow, y;
+#else
+	ULong borrow, y;
+#ifdef Pack_32
+	ULong z;
+#endif
+#endif
+
+	i = cmp(a,b);
+	if (!i) {
+		c = Balloc(0);
+		if (c == NULL)
+			return (NULL);
+		c->wds = 1;
+		c->x[0] = 0;
+		return c;
+		}
+	if (i < 0) {
+		c = a;
+		a = b;
+		b = c;
+		i = 1;
+		}
+	else
+		i = 0;
+	c = Balloc(a->k);
+	if (c == NULL)
+		return (NULL);
+	c->sign = i;
+	wa = a->wds;
+	xa = a->x;
+	xae = xa + wa;
+	wb = b->wds;
+	xb = b->x;
+	xbe = xb + wb;
+	xc = c->x;
+	borrow = 0;
+#ifdef ULLong
+	do {
+		y = (ULLong)*xa++ - *xb++ - borrow;
+		borrow = y >> 32 & 1UL;
+		*xc++ = y & 0xffffffffUL;
+		}
+		while(xb < xbe);
+	while(xa < xae) {
+		y = *xa++ - borrow;
+		borrow = y >> 32 & 1UL;
+		*xc++ = y & 0xffffffffUL;
+		}
+#else
+#ifdef Pack_32
+	do {
+		y = (*xa & 0xffff) - (*xb & 0xffff) - borrow;
+		borrow = (y & 0x10000) >> 16;
+		z = (*xa++ >> 16) - (*xb++ >> 16) - borrow;
+		borrow = (z & 0x10000) >> 16;
+		Storeinc(xc, z, y);
+		}
+		while(xb < xbe);
+	while(xa < xae) {
+		y = (*xa & 0xffff) - borrow;
+		borrow = (y & 0x10000) >> 16;
+		z = (*xa++ >> 16) - borrow;
+		borrow = (z & 0x10000) >> 16;
+		Storeinc(xc, z, y);
+		}
+#else
+	do {
+		y = *xa++ - *xb++ - borrow;
+		borrow = (y & 0x10000) >> 16;
+		*xc++ = y & 0xffff;
+		}
+		while(xb < xbe);
+	while(xa < xae) {
+		y = *xa++ - borrow;
+		borrow = (y & 0x10000) >> 16;
+		*xc++ = y & 0xffff;
+		}
+#endif
+#endif
+	while(!*--xc)
+		wa--;
+	c->wds = wa;
+	return c;
+	}
+
+ double
+b2d
+#ifdef KR_headers
+	(a, e) Bigint *a; int *e;
+#else
+	(Bigint *a, int *e)
+#endif
+{
+	ULong *xa, *xa0, w, y, z;
+	int k;
+	U d;
+#ifdef VAX
+	ULong d0, d1;
+#else
+#define d0 word0(&d)
+#define d1 word1(&d)
+#endif
+
+	xa0 = a->x;
+	xa = xa0 + a->wds;
+	y = *--xa;
+#ifdef DEBUG
+	if (!y) Bug("zero y in b2d");
+#endif
+	k = hi0bits(y);
+	*e = 32 - k;
+#ifdef Pack_32
+	if (k < Ebits) {
+		d0 = Exp_1 | y >> (Ebits - k);
+		w = xa > xa0 ? *--xa : 0;
+		d1 = y << ((32-Ebits) + k) | w >> (Ebits - k);
+		goto ret_d;
+		}
+	z = xa > xa0 ? *--xa : 0;
+	if (k -= Ebits) {
+		d0 = Exp_1 | y << k | z >> (32 - k);
+		y = xa > xa0 ? *--xa : 0;
+		d1 = z << k | y >> (32 - k);
+		}
+	else {
+		d0 = Exp_1 | y;
+		d1 = z;
+		}
+#else
+	if (k < Ebits + 16) {
+		z = xa > xa0 ? *--xa : 0;
+		d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k;
+		w = xa > xa0 ? *--xa : 0;
+		y = xa > xa0 ? *--xa : 0;
+		d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k;
+		goto ret_d;
+		}
+	z = xa > xa0 ? *--xa : 0;
+	w = xa > xa0 ? *--xa : 0;
+	k -= Ebits + 16;
+	d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k;
+	y = xa > xa0 ? *--xa : 0;
+	d1 = w << k + 16 | y << k;
+#endif
+ ret_d:
+#ifdef VAX
+	word0(&d) = d0 >> 16 | d0 << 16;
+	word1(&d) = d1 >> 16 | d1 << 16;
+#endif
+	return dval(&d);
+	}
+#undef d0
+#undef d1
+
+ Bigint *
+d2b
+#ifdef KR_headers
+	(dd, e, bits) double dd; int *e, *bits;
+#else
+	(double dd, int *e, int *bits)
+#endif
+{
+	Bigint *b;
+	U d;
+#ifndef Sudden_Underflow
+	int i;
+#endif
+	int de, k;
+	ULong *x, y, z;
+#ifdef VAX
+	ULong d0, d1;
+#else
+#define d0 word0(&d)
+#define d1 word1(&d)
+#endif
+	d.d = dd;
+#ifdef VAX
+	d0 = word0(&d) >> 16 | word0(&d) << 16;
+	d1 = word1(&d) >> 16 | word1(&d) << 16;
+#endif
+
+#ifdef Pack_32
+	b = Balloc(1);
+#else
+	b = Balloc(2);
+#endif
+	if (b == NULL)
+		return (NULL);
+	x = b->x;
+
+	z = d0 & Frac_mask;
+	d0 &= 0x7fffffff;	/* clear sign bit, which we ignore */
+#ifdef Sudden_Underflow
+	de = (int)(d0 >> Exp_shift);
+#ifndef IBM
+	z |= Exp_msk11;
+#endif
+#else
+	if ( (de = (int)(d0 >> Exp_shift)) !=0)
+		z |= Exp_msk1;
+#endif
+#ifdef Pack_32
+	if ( (y = d1) !=0) {
+		if ( (k = lo0bits(&y)) !=0) {
+			x[0] = y | z << (32 - k);
+			z >>= k;
+			}
+		else
+			x[0] = y;
+#ifndef Sudden_Underflow
+		i =
+#endif
+		     b->wds = (x[1] = z) !=0 ? 2 : 1;
+		}
+	else {
+		k = lo0bits(&z);
+		x[0] = z;
+#ifndef Sudden_Underflow
+		i =
+#endif
+		    b->wds = 1;
+		k += 32;
+		}
+#else
+	if ( (y = d1) !=0) {
+		if ( (k = lo0bits(&y)) !=0)
+			if (k >= 16) {
+				x[0] = y | z << 32 - k & 0xffff;
+				x[1] = z >> k - 16 & 0xffff;
+				x[2] = z >> k;
+				i = 2;
+				}
+			else {
+				x[0] = y & 0xffff;
+				x[1] = y >> 16 | z << 16 - k & 0xffff;
+				x[2] = z >> k & 0xffff;
+				x[3] = z >> k+16;
+				i = 3;
+				}
+		else {
+			x[0] = y & 0xffff;
+			x[1] = y >> 16;
+			x[2] = z & 0xffff;
+			x[3] = z >> 16;
+			i = 3;
+			}
+		}
+	else {
+#ifdef DEBUG
+		if (!z)
+			Bug("Zero passed to d2b");
+#endif
+		k = lo0bits(&z);
+		if (k >= 16) {
+			x[0] = z;
+			i = 0;
+			}
+		else {
+			x[0] = z & 0xffff;
+			x[1] = z >> 16;
+			i = 1;
+			}
+		k += 32;
+		}
+	while(!x[i])
+		--i;
+	b->wds = i + 1;
+#endif
+#ifndef Sudden_Underflow
+	if (de) {
+#endif
+#ifdef IBM
+		*e = (de - Bias - (P-1) << 2) + k;
+		*bits = 4*P + 8 - k - hi0bits(word0(&d) & Frac_mask);
+#else
+		*e = de - Bias - (P-1) + k;
+		*bits = P - k;
+#endif
+#ifndef Sudden_Underflow
+		}
+	else {
+		*e = de - Bias - (P-1) + 1 + k;
+#ifdef Pack_32
+		*bits = 32*i - hi0bits(x[i-1]);
+#else
+		*bits = (i+2)*16 - hi0bits(x[i]);
+#endif
+		}
+#endif
+	return b;
+	}
+#undef d0
+#undef d1
+
+ CONST double
+#ifdef IEEE_Arith
+bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };
+CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, 1e-256
+		};
+#else
+#ifdef IBM
+bigtens[] = { 1e16, 1e32, 1e64 };
+CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 };
+#else
+bigtens[] = { 1e16, 1e32 };
+CONST double tinytens[] = { 1e-16, 1e-32 };
+#endif
+#endif
+
+ CONST double
+tens[] = {
+		1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+		1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+		1e20, 1e21, 1e22
+#ifdef VAX
+		, 1e23, 1e24
+#endif
+		};
+
+#ifdef NO_STRING_H
+
+ char *
+#ifdef KR_headers
+strcp_D2A(a, b) char *a; char *b;
+#else
+strcp_D2A(char *a, CONST char *b)
+#endif
+{
+	while((*a = *b++))
+		a++;
+	return a;
+	}
+
+ Char *
+#ifdef KR_headers
+memcpy_D2A(a, b, len) Char *a; Char *b; size_t len;
+#else
+memcpy_D2A(void *a1, void *b1, size_t len)
+#endif
+{
+	char *a = (char*)a1, *ae = a + len;
+	char *b = (char*)b1, *a0 = a;
+	while(a < ae)
+		*a++ = *b++;
+	return a0;
+	}
+
+#endif /* NO_STRING_H */
diff --git a/newlib/libc/stdlib/gdtoa.h b/newlib/libc/stdlib/gdtoa.h
index 07506aac1..4f26d8857 100644
--- a/newlib/libc/stdlib/gdtoa.h
+++ b/newlib/libc/stdlib/gdtoa.h
@@ -32,25 +32,61 @@ THIS SOFTWARE.
 #ifndef GDTOA_H_INCLUDED
 #define GDTOA_H_INCLUDED
 
+#include "arith.h"
+#include <stddef.h> /* for size_t */
+
+#define PROTO_NORMAL(x)
+#define __BEGIN_HIDDEN_DECLS
+#define __END_HIDDEN_DECLS
+#define DEF_STRONG(x)
+
+#ifndef Long
+#define Long int
+#endif
+#ifndef ULong
+typedef unsigned Long ULong;
+#endif
+#ifndef UShort
+typedef unsigned short UShort;
+#endif
+
+#ifndef ANSI
+#ifdef KR_headers
+#define ANSI(x) ()
+#define Void /*nothing*/
+#else
+#define ANSI(x) x
+#define Void void
+#endif
+#endif /* ANSI */
+
+#ifndef CONST
+#ifdef KR_headers
+#define CONST /* blank */
+#else
+#define CONST const
+#endif
+#endif /* CONST */
 
  enum {	/* return values from strtodg */
-	STRTOG_Zero	= 0,
-	STRTOG_Normal	= 1,
-	STRTOG_Denormal	= 2,
-	STRTOG_Infinite	= 3,
-	STRTOG_NaN	= 4,
-	STRTOG_NaNbits	= 5,
-	STRTOG_NoNumber	= 6,
-	STRTOG_Retmask	= 7,
+	STRTOG_Zero	= 0x000,
+	STRTOG_Normal	= 0x001,
+	STRTOG_Denormal	= 0x002,
+	STRTOG_Infinite	= 0x003,
+	STRTOG_NaN	= 0x004,
+	STRTOG_NaNbits	= 0x005,
+	STRTOG_NoNumber	= 0x006,
+	STRTOG_NoMemory = 0x007,
+	STRTOG_Retmask	= 0x00f,
 
 	/* The following may be or-ed into one of the above values. */
 
-	STRTOG_Neg	= 0x08,
-	STRTOG_Inexlo	= 0x10,
-	STRTOG_Inexhi	= 0x20,
-	STRTOG_Inexact	= 0x30,
-	STRTOG_Underflow= 0x40,
-	STRTOG_Overflow	= 0x80
+	STRTOG_Inexlo	= 0x010, /* returned result rounded toward zero */
+	STRTOG_Inexhi	= 0x020, /* returned result rounded away from zero */
+	STRTOG_Inexact	= 0x030,
+	STRTOG_Underflow= 0x040,
+	STRTOG_Overflow	= 0x080,
+	STRTOG_Neg	= 0x100 /* does not affect STRTOG_Inexlo or STRTOG_Inexhi */
 	};
 
  typedef struct
@@ -69,6 +105,70 @@ enum {	/* FPI.rounding values: same as FLT_ROUNDS */
 	FPI_Round_down = 3
 	};
 
-#endif /* GDTOA_H_INCLUDED */
-
 typedef unsigned short __UShort;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char* __dtoa  ANSI((double d, int mode, int ndigits, int *decpt,
+			int *sign, char **rve));
+extern char* __gdtoa ANSI((FPI *fpi, int be, ULong *bits, int *kindp,
+			int mode, int ndigits, int *decpt, char **rve));
+extern void __freedtoa ANSI((char*));
+extern float  strtof ANSI((CONST char *, char **));
+extern double strtod ANSI((CONST char *, char **));
+extern int __strtodg ANSI((CONST char*, char**, FPI*, Long*, ULong*));
+char	*__hdtoa(double, const char *, int, int *, int *, char **);
+char	*__hldtoa(long double, const char *, int, int *, int *, char **);
+char	*__ldtoa(long double *, int, int, int *, int *, char **);
+
+PROTO_NORMAL(__dtoa);
+PROTO_NORMAL(__gdtoa);
+PROTO_NORMAL(__freedtoa);
+PROTO_NORMAL(__hdtoa);
+PROTO_NORMAL(__hldtoa);
+PROTO_NORMAL(__ldtoa);
+
+__BEGIN_HIDDEN_DECLS
+extern char*	__g_ddfmt  ANSI((char*, double*, int, size_t));
+extern char*	__g_dfmt   ANSI((char*, double*, int, size_t));
+extern char*	__g_ffmt   ANSI((char*, float*,  int, size_t));
+extern char*	__g_Qfmt   ANSI((char*, void*,   int, size_t));
+extern char*	__g_xfmt   ANSI((char*, void*,   int, size_t));
+extern char*	__g_xLfmt  ANSI((char*, void*,   int, size_t));
+
+extern int	__strtoId  ANSI((CONST char*, char**, double*, double*));
+extern int	__strtoIdd ANSI((CONST char*, char**, double*, double*));
+extern int	__strtoIf  ANSI((CONST char*, char**, float*, float*));
+extern int	__strtoIQ  ANSI((CONST char*, char**, void*, void*));
+extern int	__strtoIx  ANSI((CONST char*, char**, void*, void*));
+extern int	__strtoIxL ANSI((CONST char*, char**, void*, void*));
+extern int	__strtord  ANSI((CONST char*, char**, int, double*));
+extern int	__strtordd ANSI((CONST char*, char**, int, double*));
+extern int	__strtorf  ANSI((CONST char*, char**, int, float*));
+extern int	__strtorQ  ANSI((CONST char*, char**, int, void*));
+extern int	__strtorx  ANSI((CONST char*, char**, int, void*));
+extern int	__strtorxL ANSI((CONST char*, char**, int, void*));
+#if 1
+extern int	__strtodI  ANSI((CONST char*, char**, double*));
+extern int	__strtopd  ANSI((CONST char*, char**, double*));
+extern int	__strtopdd ANSI((CONST char*, char**, double*));
+extern int	__strtopf  ANSI((CONST char*, char**, float*));
+extern int	__strtopQ  ANSI((CONST char*, char**, void*));
+extern int	__strtopx  ANSI((CONST char*, char**, void*));
+extern int	__strtopxL ANSI((CONST char*, char**, void*));
+#else
+#define __strtopd(s,se,x) strtord(s,se,1,x)
+#define __strtopdd(s,se,x) strtordd(s,se,1,x)
+#define __strtopf(s,se,x) strtorf(s,se,1,x)
+#define __strtopQ(s,se,x) strtorQ(s,se,1,x)
+#define __strtopx(s,se,x) strtorx(s,se,1,x)
+#define __strtopxL(s,se,x) strtorxL(s,se,1,x)
+#endif
+__END_HIDDEN_DECLS
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* GDTOA_H_INCLUDED */
diff --git a/newlib/libc/stdlib/gdtoaimp.h b/newlib/libc/stdlib/gdtoaimp.h
new file mode 100644
index 000000000..bf9770955
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoaimp.h
@@ -0,0 +1,672 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998-2000 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* This is a variation on dtoa.c that converts arbitary binary
+   floating-point formats to and from decimal notation.  It uses
+   double-precision arithmetic internally, so there are still
+   various #ifdefs that adapt the calculations to the native
+   double-precision arithmetic (any of IEEE, VAX D_floating,
+   or IBM mainframe arithmetic).
+
+   Please send bug reports to David M. Gay (dmg at acm dot org,
+   with " at " changed at "@" and " dot " changed to ".").
+ */
+
+/* On a machine with IEEE extended-precision registers, it is
+ * necessary to specify double-precision (53-bit) rounding precision
+ * before invoking strtod or dtoa.  If the machine uses (the equivalent
+ * of) Intel 80x87 arithmetic, the call
+ *	_control87(PC_53, MCW_PC);
+ * does this with many compilers.  Whether this or another call is
+ * appropriate depends on the compiler; for this to work, it may be
+ * necessary to #include "float.h" or another system-dependent header
+ * file.
+ */
+
+/* strtod for IEEE-, VAX-, and IBM-arithmetic machines.
+ *
+ * This strtod returns a nearest machine number to the input decimal
+ * string (or sets errno to ERANGE).  With IEEE arithmetic, ties are
+ * broken by the IEEE round-even rule.  Otherwise ties are broken by
+ * biased rounding (add half and chop).
+ *
+ * Inspired loosely by William D. Clinger's paper "How to Read Floating
+ * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ *
+ *	1. We only require IEEE, IBM, or VAX double-precision
+ *		arithmetic (not IEEE double-extended).
+ *	2. We get by with floating-point arithmetic in a case that
+ *		Clinger missed -- when we're computing d * 10^n
+ *		for a small integer d and the integer n is not too
+ *		much larger than 22 (the maximum integer k for which
+ *		we can represent 10^k exactly), we may be able to
+ *		compute (d*10^k) * 10^(e-k) with just one roundoff.
+ *	3. Rather than a bit-at-a-time adjustment of the binary
+ *		result in the hard case, we use floating-point
+ *		arithmetic to determine the adjustment to within
+ *		one bit; only in really hard cases do we need to
+ *		compute a second residual.
+ *	4. Because of 3., we don't need a large table of powers of 10
+ *		for ten-to-e (just some small tables, e.g. of 10^k
+ *		for 0 <= k <= 22).
+ */
+
+/*
+ * #define IEEE_8087 for IEEE-arithmetic machines where the least
+ *	significant byte has the lowest address.
+ * #define IEEE_MC68k for IEEE-arithmetic machines where the most
+ *	significant byte has the lowest address.
+ * #define Long int on machines with 32-bit ints and 64-bit longs.
+ * #define Sudden_Underflow for IEEE-format machines without gradual
+ *	underflow (i.e., that flush to zero on underflow).
+ * #define IBM for IBM mainframe-style floating-point arithmetic.
+ * #define VAX for VAX-style floating-point arithmetic (D_floating).
+ * #define No_leftright to omit left-right logic in fast floating-point
+ *	computation of dtoa and gdtoa.  This will cause modes 4 and 5 to be
+ *	treated the same as modes 2 and 3 for some inputs.
+ * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3.
+ * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines
+ *	that use extended-precision instructions to compute rounded
+ *	products and quotients) with IBM.
+ * #define ROUND_BIASED for IEEE-format with biased rounding and arithmetic
+ *	that rounds toward +Infinity.
+ * #define ROUND_BIASED_without_Round_Up for IEEE-format with biased
+ *	rounding when the underlying floating-point arithmetic uses
+ *	unbiased rounding.  This prevent using ordinary floating-point
+ *	arithmetic when the result could be computed with one rounding error.
+ * #define Inaccurate_Divide for IEEE-format with correctly rounded
+ *	products but inaccurate quotients, e.g., for Intel i860.
+ * #define NO_LONG_LONG on machines that do not have a "long long"
+ *	integer type (of >= 64 bits).  On such machines, you can
+ *	#define Just_16 to store 16 bits per 32-bit Long when doing
+ *	high-precision integer arithmetic.  Whether this speeds things
+ *	up or slows things down depends on the machine and the number
+ *	being converted.  If long long is available and the name is
+ *	something other than "long long", #define Llong to be the name,
+ *	and if "unsigned Llong" does not work as an unsigned version of
+ *	Llong, #define #ULLong to be the corresponding unsigned type.
+ * #define KR_headers for old-style C function headers.
+ * #define Bad_float_h if your system lacks a float.h or if it does not
+ *	define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP,
+ *	FLT_RADIX, FLT_ROUNDS, and DBL_MAX.
+ * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n)
+ *	if memory is available and otherwise does something you deem
+ *	appropriate.  If MALLOC is undefined, malloc will be invoked
+ *	directly -- and assumed always to succeed.  Similarly, if you
+ *	want something other than the system's free() to be called to
+ *	recycle memory acquired from MALLOC, #define FREE to be the
+ *	name of the alternate routine.  (FREE or free is only called in
+ *	pathological cases, e.g., in a gdtoa call after a gdtoa return in
+ *	mode 3 with thousands of digits requested.)
+ * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making
+ *	memory allocations from a private pool of memory when possible.
+ *	When used, the private pool is PRIVATE_MEM bytes long:  2304 bytes,
+ *	unless #defined to be a different length.  This default length
+ *	suffices to get rid of MALLOC calls except for unusual cases,
+ *	such as decimal-to-binary conversion of a very long string of
+ *	digits.  When converting IEEE double precision values, the
+ *	longest string gdtoa can return is about 751 bytes long.  For
+ *	conversions by strtod of strings of 800 digits and all gdtoa
+ *	conversions of IEEE doubles in single-threaded executions with
+ *	8-byte pointers, PRIVATE_MEM >= 7400 appears to suffice; with
+ *	4-byte pointers, PRIVATE_MEM >= 7112 appears adequate.
+ * #define NO_INFNAN_CHECK if you do not wish to have INFNAN_CHECK
+ *	#defined automatically on IEEE systems.  On such systems,
+ *	when INFNAN_CHECK is #defined, strtod checks
+ *	for Infinity and NaN (case insensitively).
+ *	When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined,
+ *	strtodg also accepts (case insensitively) strings of the form
+ *	NaN(x), where x is a string of hexadecimal digits (optionally
+ *	preceded by 0x or 0X) and spaces; if there is only one string
+ *	of hexadecimal digits, it is taken for the fraction bits of the
+ *	resulting NaN; if there are two or more strings of hexadecimal
+ *	digits, each string is assigned to the next available sequence
+ *	of 32-bit words of fractions bits (starting with the most
+ *	significant), right-aligned in each sequence.
+ *	Unless GDTOA_NON_PEDANTIC_NANCHECK is #defined, input "NaN(...)"
+ *	is consumed even when ... has the wrong form (in which case the
+ *	"(...)" is consumed but ignored).
+ * #define MULTIPLE_THREADS if the system offers preemptively scheduled
+ *	multiple threads.  In this case, you must provide (or suitably
+ *	#define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed
+ *	by FREE_DTOA_LOCK(n) for n = 0 or 1.  (The second lock, accessed
+ *	in pow5mult, ensures lazy evaluation of only one copy of high
+ *	powers of 5; omitting this lock would introduce a small
+ *	probability of wasting memory, but would otherwise be harmless.)
+ *	You must also invoke freedtoa(s) to free the value s returned by
+ *	dtoa.  You may do so whether or not MULTIPLE_THREADS is #defined.
+ * #define IMPRECISE_INEXACT if you do not care about the setting of
+ *	the STRTOG_Inexact bits in the special case of doing IEEE double
+ *	precision conversions (which could also be done by the strtod in
+ *	dtoa.c).
+ * #define NO_HEX_FP to disable recognition of C9x's hexadecimal
+ *	floating-point constants.
+ * #define -DNO_ERRNO to suppress setting errno (in strtod.c and
+ *	strtodg.c).
+ * #define NO_STRING_H to use private versions of memcpy.
+ *	On some K&R systems, it may also be necessary to
+ *	#define DECLARE_SIZE_T in this case.
+ * #define USE_LOCALE to use the current locale's decimal_point value.
+ */
+
+#ifndef GDTOAIMP_H_INCLUDED
+#define GDTOAIMP_H_INCLUDED
+#include "gdtoa.h"
+#if 0
+#include "gd_qnan.h"
+#endif
+#ifdef Honor_FLT_ROUNDS
+#include <fenv.h>
+#endif
+
+#ifdef DEBUG
+#include "stdio.h"
+#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);}
+#endif
+
+#include "stdlib.h"
+#include "string.h"
+
+#ifdef KR_headers
+#define Char char
+#else
+#define Char void
+#endif
+
+#ifdef MALLOC
+extern Char *MALLOC ANSI((size_t));
+#else
+#define MALLOC(x) _malloc_r(_REENT, x)
+#endif
+#define FREE(x) _free_r(_REENT, x)
+
+#undef IEEE_Arith
+#undef Avoid_Underflow
+#ifdef IEEE_MC68k
+#define IEEE_Arith
+#endif
+#ifdef IEEE_8087
+#define IEEE_Arith
+#endif
+
+#include "errno.h"
+#ifdef Bad_float_h
+
+#ifdef IEEE_Arith
+#define DBL_DIG 15
+#define DBL_MAX_10_EXP 308
+#define DBL_MAX_EXP 1024
+#define FLT_RADIX 2
+#define DBL_MAX 1.7976931348623157e+308
+#endif
+
+#ifdef IBM
+#define DBL_DIG 16
+#define DBL_MAX_10_EXP 75
+#define DBL_MAX_EXP 63
+#define FLT_RADIX 16
+#define DBL_MAX 7.2370055773322621e+75
+#endif
+
+#ifdef VAX
+#define DBL_DIG 16
+#define DBL_MAX_10_EXP 38
+#define DBL_MAX_EXP 127
+#define FLT_RADIX 2
+#define DBL_MAX 1.7014118346046923e+38
+#define n_bigtens 2
+#endif
+
+#ifndef LONG_MAX
+#define LONG_MAX 2147483647
+#endif
+
+#else /* ifndef Bad_float_h */
+#include "float.h"
+#endif /* Bad_float_h */
+
+#ifdef IEEE_Arith
+#define Scale_Bit 0x10
+#define n_bigtens 5
+#endif
+
+#ifdef IBM
+#define n_bigtens 3
+#endif
+
+#ifdef VAX
+#define n_bigtens 2
+#endif
+
+#ifndef __MATH_H__
+#include "math.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1
+Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined.
+#endif
+
+typedef union { double d; ULong L[2]; } U;
+
+#ifdef IEEE_8087
+#define word0(x) (x)->L[1]
+#define word1(x) (x)->L[0]
+#else
+#define word0(x) (x)->L[0]
+#define word1(x) (x)->L[1]
+#endif
+#define dval(x) (x)->d
+
+/* The following definition of Storeinc is appropriate for MIPS processors.
+ * An alternative that might be better on some machines is
+ * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff)
+ */
+#if defined(IEEE_8087) + defined(VAX)
+#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \
+((unsigned short *)a)[0] = (unsigned short)c, a++)
+#else
+#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \
+((unsigned short *)a)[1] = (unsigned short)c, a++)
+#endif
+
+/* #define P DBL_MANT_DIG */
+/* Ten_pmax = floor(P*log(2)/log(5)) */
+/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */
+/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */
+/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */
+
+#ifdef IEEE_Arith
+#define Exp_shift  20
+#define Exp_shift1 20
+#define Exp_msk1    0x100000
+#define Exp_msk11   0x100000
+#define Exp_mask  0x7ff00000
+#define P 53
+#define Bias 1023
+#define Emin (-1022)
+#define Exp_1  0x3ff00000
+#define Exp_11 0x3ff00000
+#define Ebits 11
+#define Frac_mask  0xfffff
+#define Frac_mask1 0xfffff
+#define Ten_pmax 22
+#define Bletch 0x10
+#define Bndry_mask  0xfffff
+#define Bndry_mask1 0xfffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 1
+#define Tiny0 0
+#define Tiny1 1
+#define Quick_max 14
+#define Int_max 14
+
+#ifndef Flt_Rounds
+#ifdef FLT_ROUNDS
+#define Flt_Rounds FLT_ROUNDS
+#else
+#define Flt_Rounds 1
+#endif
+#endif /*Flt_Rounds*/
+
+#else /* ifndef IEEE_Arith */
+#undef  Sudden_Underflow
+#define Sudden_Underflow
+#ifdef IBM
+#undef Flt_Rounds
+#define Flt_Rounds 0
+#define Exp_shift  24
+#define Exp_shift1 24
+#define Exp_msk1   0x1000000
+#define Exp_msk11  0x1000000
+#define Exp_mask  0x7f000000
+#define P 14
+#define Bias 65
+#define Exp_1  0x41000000
+#define Exp_11 0x41000000
+#define Ebits 8	/* exponent has 7 bits, but 8 is the right value in b2d */
+#define Frac_mask  0xffffff
+#define Frac_mask1 0xffffff
+#define Bletch 4
+#define Ten_pmax 22
+#define Bndry_mask  0xefffff
+#define Bndry_mask1 0xffffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 4
+#define Tiny0 0x100000
+#define Tiny1 0
+#define Quick_max 14
+#define Int_max 15
+#else /* VAX */
+#undef Flt_Rounds
+#define Flt_Rounds 1
+#define Exp_shift  23
+#define Exp_shift1 7
+#define Exp_msk1    0x80
+#define Exp_msk11   0x800000
+#define Exp_mask  0x7f80
+#define P 56
+#define Bias 129
+#define Emin (-127)
+#define Exp_1  0x40800000
+#define Exp_11 0x4080
+#define Ebits 8
+#define Frac_mask  0x7fffff
+#define Frac_mask1 0xffff007f
+#define Ten_pmax 24
+#define Bletch 2
+#define Bndry_mask  0xffff007f
+#define Bndry_mask1 0xffff007f
+#define LSB 0x10000
+#define Sign_bit 0x8000
+#define Log2P 1
+#define Tiny0 0x80
+#define Tiny1 0
+#define Quick_max 15
+#define Int_max 15
+#endif /* IBM, VAX */
+#endif /* IEEE_Arith */
+
+#ifndef IEEE_Arith
+#define ROUND_BIASED
+#else
+#ifdef ROUND_BIASED_without_Round_Up
+#undef  ROUND_BIASED
+#define ROUND_BIASED
+#endif
+#endif
+
+#ifdef RND_PRODQUOT
+#define rounded_product(a,b) a = rnd_prod(a, b)
+#define rounded_quotient(a,b) a = rnd_quot(a, b)
+#ifdef KR_headers
+extern double rnd_prod(), rnd_quot();
+#else
+extern double rnd_prod(double, double), rnd_quot(double, double);
+#endif
+#else
+#define rounded_product(a,b) a *= b
+#define rounded_quotient(a,b) a /= b
+#endif
+
+#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1))
+#define Big1 0xffffffff
+
+#undef  Pack_16
+#ifndef Pack_32
+#define Pack_32
+#endif
+
+#ifdef NO_LONG_LONG
+#undef ULLong
+#ifdef Just_16
+#undef Pack_32
+#define Pack_16
+/* When Pack_32 is not defined, we store 16 bits per 32-bit Long.
+ * This makes some inner loops simpler and sometimes saves work
+ * during multiplications, but it often seems to make things slightly
+ * slower.  Hence the default is now to store 32 bits per Long.
+ */
+#endif
+#else	/* long long available */
+#ifndef Llong
+#define Llong long long
+#endif
+#ifndef ULLong
+#define ULLong unsigned Llong
+#endif
+#endif /* NO_LONG_LONG */
+
+#ifdef Pack_32
+#define ULbits 32
+#define kshift 5
+#define kmask 31
+#define ALL_ON 0xffffffff
+#else
+#define ULbits 16
+#define kshift 4
+#define kmask 15
+#define ALL_ON 0xffff
+#endif
+
+#ifndef __SINGLE_THREAD__
+#define MULTIPLE_THREADS
+#endif
+
+#ifndef MULTIPLE_THREADS
+#define ACQUIRE_DTOA_LOCK(n)	/*nothing*/
+#define FREE_DTOA_LOCK(n)	/*nothing*/
+#else
+#include <sys/lock.h>
+#define ACQUIRE_DTOA_LOCK(n) \
+	n ? __lock_acquire(__dtoa_lock1) : __lock_acquire(__dtoa_lock0)
+#define FREE_DTOA_LOCK(n) \
+	n ? __lock_release(__dtoa_lock1) : __lock_release(__dtoa_lock0)
+#endif
+
+#define Kmax 9
+
+ struct
+Bigint {
+	struct Bigint *next;
+	int k, maxwds, sign, wds;
+	ULong x[1];
+	};
+
+ typedef struct Bigint Bigint;
+
+#ifdef NO_STRING_H
+#ifdef DECLARE_SIZE_T
+typedef unsigned int size_t;
+#endif
+extern void memcpy_D2A ANSI((void*, const void*, size_t));
+#define Bcopy(x,y) memcpy_D2A(&x->sign,&y->sign,y->wds*sizeof(ULong) + 2*sizeof(int))
+#else /* !NO_STRING_H */
+#define Bcopy(x,y) memcpy(&x->sign,&y->sign,y->wds*sizeof(ULong) + 2*sizeof(int))
+#endif /* NO_STRING_H */
+
+#define dtoa __dtoa
+#define gdtoa __gdtoa
+#define freedtoa __freedtoa
+#define strtodg __strtodg
+#define g_ddfmt __g_ddfmt
+#define g_dfmt __g_dfmt
+#define g_ffmt __g_ffmt
+#define g_Qfmt __g_Qfmt
+#define g_xfmt __g_xfmt
+#define g_xLfmt __g_xLfmt
+#define strtoId __strtoId
+#define strtoIdd __strtoIdd
+#define strtoIf __strtoIf
+#define strtoIQ __strtoIQ
+#define strtoIx __strtoIx
+#define strtoIxL __strtoIxL
+#define strtord __strtord
+#define strtordd __strtordd
+#define strtorf __strtorf
+#define strtorQ __strtorQ
+#define strtorx __strtorx
+#define strtorxL __strtorxL
+#define strtodI __strtodI
+#define strtopd __strtopd
+#define strtopdd __strtopdd
+#define strtopf __strtopf
+#define strtopQ __strtopQ
+#define strtopx __strtopx
+#define strtopxL __strtopxL
+
+#define Balloc __Balloc_D2A
+#define Bfree __Bfree_D2A
+#define ULtoQ __ULtoQ_D2A
+#define ULtof __ULtof_D2A
+#define ULtod __ULtod_D2A
+#define ULtodd __ULtodd_D2A
+#define ULtox __ULtox_D2A
+#define ULtoxL __ULtoxL_D2A
+#define any_on __any_on_D2A
+#define b2d __b2d_D2A
+#define bigtens __bigtens_D2A
+#define cmp __cmp_D2A
+#define copybits __copybits_D2A
+#define d2b __d2b_D2A
+#define decrement __decrement_D2A
+#define diff __diff_D2A
+#define dtoa_result __dtoa_result_D2A
+#define g__fmt __g__fmt_D2A
+#define gethex __gethex_D2A
+#define hexdig __hexdig_D2A
+#define hexnan __hexnan_D2A
+#define hi0bits(x) __hi0bits_D2A((ULong)(x))
+#define hi0bits_D2A __hi0bits_D2A
+#define i2b __i2b_D2A
+#define increment __increment_D2A
+#define lo0bits __lo0bits_D2A
+#define lshift __lshift_D2A
+#define match __match_D2A
+#define mult __mult_D2A
+#define multadd __multadd_D2A
+#define nrv_alloc __nrv_alloc_D2A
+#define pow5mult __pow5mult_D2A
+#define quorem __quorem_D2A
+#define ratio __ratio_D2A
+#define rshift __rshift_D2A
+#define rv_alloc __rv_alloc_D2A
+#define s2b __s2b_D2A
+#define set_ones __set_ones_D2A
+#define strcp __strcp_D2A
+#define strtoIg __strtoIg_D2A
+#define sulp __sulp_D2A
+#define sum __sum_D2A
+#define tens __tens_D2A
+#define tinytens __tinytens_D2A
+#define tinytens __tinytens_D2A
+#define trailz __trailz_D2A
+#define ulp __ulp_D2A
+
+__BEGIN_HIDDEN_DECLS
+ extern char *dtoa_result;
+ extern CONST double bigtens[], tens[], tinytens[];
+ extern unsigned char hexdig[];
+
+ extern Bigint *Balloc ANSI((int));
+ extern void Bfree ANSI((Bigint*));
+ extern void ULtof ANSI((ULong*, ULong*, Long, int));
+ extern void ULtod ANSI((ULong*, ULong*, Long, int));
+ extern void ULtodd ANSI((ULong*, ULong*, Long, int));
+ extern void ULtoQ ANSI((ULong*, ULong*, Long, int));
+ extern void ULtox ANSI((UShort*, ULong*, Long, int));
+ extern void ULtoxL ANSI((ULong*, ULong*, Long, int));
+ extern ULong any_on ANSI((Bigint*, int));
+ extern double b2d ANSI((Bigint*, int*));
+ extern int cmp ANSI((Bigint*, Bigint*));
+ extern void copybits ANSI((ULong*, int, Bigint*));
+ extern Bigint *d2b ANSI((double, int*, int*));
+ extern void decrement ANSI((Bigint*));
+ extern Bigint *diff ANSI((Bigint*, Bigint*));
+ extern char *g__fmt ANSI((char*, char*, char*, int, ULong, size_t));
+ extern int gethex ANSI((CONST char**, FPI*, Long*, Bigint**, int));
+ extern void __hexdig_init_D2A(Void);
+ extern int hexnan ANSI((CONST char**, FPI*, ULong*));
+ extern int hi0bits_D2A ANSI((ULong));
+ extern Bigint *i2b ANSI((int));
+ extern Bigint *increment ANSI((Bigint*));
+ extern int lo0bits ANSI((ULong*));
+ extern Bigint *lshift ANSI((Bigint*, int));
+ extern int match ANSI((CONST char**, char*));
+ extern Bigint *mult ANSI((Bigint*, Bigint*));
+ extern Bigint *multadd ANSI((Bigint*, int, int));
+ extern char *nrv_alloc ANSI((char*, char **, int));
+ extern Bigint *pow5mult ANSI((Bigint*, int));
+ extern int quorem ANSI((Bigint*, Bigint*));
+ extern double ratio ANSI((Bigint*, Bigint*));
+ extern void rshift ANSI((Bigint*, int));
+ extern char *rv_alloc ANSI((int));
+ extern Bigint *s2b ANSI((CONST char*, int, int, ULong, int));
+ extern Bigint *set_ones ANSI((Bigint*, int));
+ extern char *strcp ANSI((char*, const char*));
+ extern int strtoIg ANSI((CONST char*, char**, FPI*, Long*, Bigint**, int*));
+ extern Bigint *sum ANSI((Bigint*, Bigint*));
+ extern int trailz ANSI((Bigint*));
+ extern double ulp ANSI((U*));
+__END_HIDDEN_DECLS
+
+#ifdef __cplusplus
+}
+#endif
+/*
+ * NAN_WORD0 and NAN_WORD1 are only referenced in strtod.c.  Prior to
+ * 20050115, they used to be hard-wired here (to 0x7ff80000 and 0,
+ * respectively), but now are determined by compiling and running
+ * qnan.c to generate gd_qnan.h, which specifies d_QNAN0 and d_QNAN1.
+ * Formerly gdtoaimp.h recommended supplying suitable -DNAN_WORD0=...
+ * and -DNAN_WORD1=...  values if necessary.  This should still work.
+ * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.)
+ */
+#ifdef IEEE_Arith
+#ifndef NO_INFNAN_CHECK
+#undef INFNAN_CHECK
+#define INFNAN_CHECK
+#endif
+#ifdef IEEE_MC68k
+#define _0 0
+#define _1 1
+#ifndef NAN_WORD0
+#define NAN_WORD0 d_QNAN0
+#endif
+#ifndef NAN_WORD1
+#define NAN_WORD1 d_QNAN1
+#endif
+#else
+#define _0 1
+#define _1 0
+#ifndef NAN_WORD0
+#define NAN_WORD0 d_QNAN1
+#endif
+#ifndef NAN_WORD1
+#define NAN_WORD1 d_QNAN0
+#endif
+#endif
+#else
+#undef INFNAN_CHECK
+#endif
+
+#undef SI
+#ifdef Sudden_Underflow
+#define SI 1
+#else
+#define SI 0
+#endif
+
+#endif /* GDTOAIMP_H_INCLUDED */
diff --git a/newlib/libc/stdlib/ldtoa.c b/newlib/libc/stdlib/ldtoa.c
index 26c61948b..fbbd3d0b1 100644
--- a/newlib/libc/stdlib/ldtoa.c
+++ b/newlib/libc/stdlib/ldtoa.c
@@ -7,6 +7,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include "mprec.h"
+#include "gdtoa.h"
 
 /* These are the externally visible entries. */
 /* linux name:  long double _IO_strtold (char *, char **); */
@@ -2814,6 +2815,12 @@ _ldtoa_r (struct _reent *ptr, long double d, int mode, int ndigits,
       _REENT_MP_RESULT (ptr) = 0;
     }
 
+  /* Use the result of gdtoa if successfull. */
+  outstr = __ldtoa (&d, mode, ndigits, decpt, sign, rve);
+  /* If it fails, fallback to legacy ldtoa. */
+  if (outstr)
+    return outstr;
+
 #if LDBL_MANT_DIG == 24
   e24toe (&du.pe, e, ldp);
 #elif LDBL_MANT_DIG == 53
-- 
2.33.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed value is incorrectly rounded
  2021-11-28 13:16         ` Takashi Yano
@ 2021-11-29 10:56           ` Takashi Yano
  2021-11-29 14:24             ` Takashi Yano
  0 siblings, 1 reply; 25+ messages in thread
From: Takashi Yano @ 2021-11-29 10:56 UTC (permalink / raw)
  To: newlib

[-- Attachment #1: Type: text/plain, Size: 1854 bytes --]

On Sun, 28 Nov 2021 22:16:46 +0900
Takashi Yano wrote:
> On Sun, 28 Nov 2021 21:38:39 +0900
> Takashi Yano wrote:
> > On Sun, 28 Nov 2021 16:43:11 +0900
> > Takashi Yano wrote:
> > > On Thu, 4 Nov 2021 13:24:42 +0100
> > > Corinna Vinschen wrote:
> > > > However, a much better fix would be to switch to gdtoa, as the BSDs and
> > > > Mingw64 do.
> > > 
> > > I have tried to import gdtoa into newlib from OpenBSD.
> > > 
> > > gdtoa seems to use malloc much, so it may not work in some of
> > > platforms due to insufficient heap. Therefore, new ldtoa.c tries
> > > gdtoa first and fallbacks to legacy ldtoa if gdtoa fails.
> > > 
> > > To import gdtoa to newlib, I did:
> > > 1) Create "machine/ieee.h" which conditionally defines ieee_ext
> > >    structure and EXT_TO_ARRAY32() macro depend on architecture.
> > > 2) Create arith.h which reflects endian of architecture.
> > > 3) Merge gdtoa.h with OpenBSD's gdtoa.h. __BEGIN_HIDDEN_DECLS,
> > >    __END_HIDDEN_DECLS, PROTO_NORMAL() and DEF_STRONG() are
> > >    defined as dummy in this header.
> > > 4) Replace malloc()/free() with _malloc_r()/_free_r().
> > > 5) Implement ACQUIRE_DTOA_LOCK() and FREE_DTOA_LOCK() macros
> > >    using "sys/lock.h" for multi-threading environment.
> > > 6) Remove inclusion of "gd_qnan.h" which is not used.
> > > 
> > > Please see attached patch for more details.
> > > 
> > > I confirmed this works nicely with cygwin. Moreover, it is much
> > > faster than legacy ldtoa (more than 4 times faster).
> > > 
> > > However, this may break some other supported platforms.
> > > 
> > > Could anyone please check this?
> > 
> > Ah, in "machine/ieee.h", struct ieee_ext definition for
> > LDBL_MANT_DIG==64 and __IEEE_BIG_ENDIAN case, is obviously
> > wrong. 
> 
> Fixed.

Bit order for ARMEL without __VFP_FP__ is fixed.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: 0001-ldtoa-Import-gdtoa-from-OpenBSD.patch --]
[-- Type: application/octet-stream, Size: 108934 bytes --]

From fbac77967d90ca0cea53bb3dc1fc8b715276d863 Mon Sep 17 00:00:00 2001
From: Takashi Yano <takashi.yano@nifty.ne.jp>
Date: Mon, 29 Nov 2021 17:45:53 +0900
Subject: [PATCH] ldtoa: Import gdtoa from OpenBSD.

---
 newlib/libc/include/machine/ieee.h | 121 ++++
 newlib/libc/stdlib/Makefile.am     |  14 +-
 newlib/libc/stdlib/Makefile.in     |  82 ++-
 newlib/libc/stdlib/arith.h         |   9 +
 newlib/libc/stdlib/gdtoa-dmisc.c   | 225 +++++++
 newlib/libc/stdlib/gdtoa-dtoa.c    | 839 ++++++++++++++++++++++++++
 newlib/libc/stdlib/gdtoa-gdtoa.c   | 830 ++++++++++++++++++++++++++
 newlib/libc/stdlib/gdtoa-gmisc.c   |  86 +++
 newlib/libc/stdlib/gdtoa-ldtoa.c   | 124 ++++
 newlib/libc/stdlib/gdtoa-misc.c    | 912 +++++++++++++++++++++++++++++
 newlib/libc/stdlib/gdtoa.h         | 132 ++++-
 newlib/libc/stdlib/gdtoaimp.h      | 672 +++++++++++++++++++++
 newlib/libc/stdlib/ldtoa.c         |   7 +
 13 files changed, 4019 insertions(+), 34 deletions(-)
 create mode 100644 newlib/libc/include/machine/ieee.h
 create mode 100644 newlib/libc/stdlib/arith.h
 create mode 100644 newlib/libc/stdlib/gdtoa-dmisc.c
 create mode 100644 newlib/libc/stdlib/gdtoa-dtoa.c
 create mode 100644 newlib/libc/stdlib/gdtoa-gdtoa.c
 create mode 100644 newlib/libc/stdlib/gdtoa-gmisc.c
 create mode 100644 newlib/libc/stdlib/gdtoa-ldtoa.c
 create mode 100644 newlib/libc/stdlib/gdtoa-misc.c
 create mode 100644 newlib/libc/stdlib/gdtoaimp.h

diff --git a/newlib/libc/include/machine/ieee.h b/newlib/libc/include/machine/ieee.h
new file mode 100644
index 000000000..b77682223
--- /dev/null
+++ b/newlib/libc/include/machine/ieee.h
@@ -0,0 +1,121 @@
+#ifndef _MACHINE_IEEE_H_
+#define _MACHINE_IEEE_H_
+#include <sys/types.h>
+#include <sys/cdefs.h>
+#include <machine/ieeefp.h>
+#include <float.h>
+
+#if LDBL_MANT_DIG == 24
+#define EXT_IMPLICIT_NBIT
+#define EXT_TO_ARRAY32(p, a) do {      \
+    (a)[0] = (p)->ext_frac;  \
+} while (0)
+#ifdef __IEEE_LITTLE_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_frac:23;
+    uint32_t   ext_exp:8;
+    uint32_t   ext_sign:1;
+};
+#endif
+#ifdef __IEEE_BIG_ENDIAN
+struct ieee_ext {
+#ifndef ___IEEE_BYTES_LITTLE_ENDIAN
+    uint32_t   ext_sign:1;
+    uint32_t   ext_exp:8;
+    uint32_t   ext_frac:23;
+#else /* ARMEL without __VFP_FP__ */
+    uint32_t   ext_frac:23;
+    uint32_t   ext_exp:8;
+    uint32_t   ext_sign:1;
+#endif
+};
+#endif
+#elif LDBL_MANT_DIG == 53
+#define EXT_IMPLICIT_NBIT
+#define EXT_TO_ARRAY32(p, a) do {       \
+    (a)[0] = (p)->ext_fracl;  \
+    (a)[1] = (p)->ext_frach;  \
+} while (0)
+#ifdef __IEEE_LITTLE_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_fracl;
+    uint32_t   ext_frach:20;
+    uint32_t   ext_exp:11;
+    uint32_t   ext_sign:1;
+};
+#endif
+#ifdef __IEEE_BIG_ENDIAN
+struct ieee_ext {
+#ifndef ___IEEE_BYTES_LITTLE_ENDIAN
+    uint32_t   ext_sign:1;
+    uint32_t   ext_exp:11;
+    uint32_t   ext_frach:20;
+#else /* ARMEL without __VFP_FP__ */
+    uint32_t   ext_frach:20;
+    uint32_t   ext_exp:11;
+    uint32_t   ext_sign:1;
+#endif
+    uint32_t   ext_fracl;
+};
+#endif
+#elif LDBL_MANT_DIG == 64
+#define EXT_TO_ARRAY32(p, a) do {       \
+    (a)[0] = (p)->ext_fracl;  \
+    (a)[1] = (p)->ext_frach;  \
+} while (0)
+#ifdef __IEEE_LITTLE_ENDIAN /* for Intel CPU */
+struct ieee_ext {
+    uint32_t   ext_fracl;
+    uint32_t   ext_frach;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_sign:1;
+    uint32_t   ext_padl:16;
+    uint32_t   ext_padh;
+};
+#endif
+#ifdef __IEEE_BIG_ENDIAN /* for m68k */
+struct ieee_ext {
+    uint32_t   ext_sign:1;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_pad:16;
+    uint32_t   ext_frach;
+    uint32_t   ext_fracl;
+};
+#endif
+#elif LDBL_MANT_DIG == 113
+#define EXT_IMPLICIT_NBIT
+#define EXT_TO_ARRAY32(p, a) do {        \
+    (a)[0] = (p)->ext_fracl;   \
+    (a)[1] = (p)->ext_fraclm;  \
+    (a)[2] = (p)->ext_frachm;  \
+    (a)[3] = (p)->ext_frach;   \
+} while (0)
+#ifdef __IEEE_LITTLE_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_fracl;
+    uint32_t   ext_fraclm;
+    uint32_t   ext_frachm;
+    uint32_t   ext_frach:16;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_sign:1;
+};
+#endif
+#ifdef __IEEE_BIG_ENDIAN
+struct ieee_ext {
+#ifndef ___IEEE_BYTES_LITTLE_ENDIAN
+    uint32_t   ext_sign:1;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_frach:16;
+#else /* ARMEL without __VFP_FP__ */
+    uint32_t   ext_frach:16;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_sign:1;
+#endif
+    uint32_t   ext_frachm;
+    uint32_t   ext_fraclm;
+    uint32_t   ext_fracl;
+};
+#endif
+#endif
+
+#endif /* _MACHINE_IEEE_H_ */
diff --git a/newlib/libc/stdlib/Makefile.am b/newlib/libc/stdlib/Makefile.am
index 357e37beb..04b22d477 100644
--- a/newlib/libc/stdlib/Makefile.am
+++ b/newlib/libc/stdlib/Makefile.am
@@ -38,6 +38,12 @@ GENERAL_SOURCES = \
 	labs.c 		\
 	ldiv.c  	\
 	ldtoa.c		\
+	gdtoa-ldtoa.c	\
+	gdtoa-gdtoa.c	\
+	gdtoa-dtoa.c	\
+	gdtoa-misc.c	\
+	gdtoa-dmisc.c	\
+	gdtoa-gmisc.c	\
 	malloc.c  	\
 	mblen.c		\
 	mblen_r.c	\
@@ -311,7 +317,13 @@ CHEWOUT_FILES= \
 CHAPTERS = stdlib.tex
 
 $(lpfx)dtoa.$(oext): dtoa.c mprec.h
-$(lpfx)ldtoa.$(oext): ldtoa.c mprec.h
+$(lpfx)ldtoa.$(oext): ldtoa.c mprec.h gdtoa.h
+$(lpfx)gdtoa-ldtoa.$(oext): gdtoa-ldtoa.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-gdtoa.$(oext): gdtoa-gdtoa.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-dtoa.$(oext): gdtoa-dtoa.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-misc.$(oext): gdtoa-misc.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-dmisc.$(oext): gdtoa-dmisc.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-gmisc.$(oext): gdtoa-gmisc.c gdtoaimp.h gdtoa.h arith.h
 $(lpfx)ecvtbuf.$(oext): ecvtbuf.c mprec.h
 $(lpfx)mbtowc_r.$(oext): mbtowc_r.c mbctype.h
 $(lpfx)mprec.$(oext): mprec.c mprec.h
diff --git a/newlib/libc/stdlib/Makefile.in b/newlib/libc/stdlib/Makefile.in
index a812b6a95..4e891ced9 100644
--- a/newlib/libc/stdlib/Makefile.in
+++ b/newlib/libc/stdlib/Makefile.in
@@ -101,7 +101,10 @@ am__objects_2 = lib_a-__adjust.$(OBJEXT) lib_a-__atexit.$(OBJEXT) \
 	lib_a-getenv_r.$(OBJEXT) lib_a-imaxabs.$(OBJEXT) \
 	lib_a-imaxdiv.$(OBJEXT) lib_a-itoa.$(OBJEXT) \
 	lib_a-labs.$(OBJEXT) lib_a-ldiv.$(OBJEXT) \
-	lib_a-ldtoa.$(OBJEXT) lib_a-malloc.$(OBJEXT) \
+	lib_a-ldtoa.$(OBJEXT) lib_a-gdtoa-ldtoa.$(OBJEXT) \
+	lib_a-gdtoa-gdtoa.$(OBJEXT) lib_a-gdtoa-dtoa.$(OBJEXT) \
+	lib_a-gdtoa-misc.$(OBJEXT) lib_a-gdtoa-dmisc.$(OBJEXT) \
+	lib_a-gdtoa-gmisc.$(OBJEXT) lib_a-malloc.$(OBJEXT) \
 	lib_a-mblen.$(OBJEXT) lib_a-mblen_r.$(OBJEXT) \
 	lib_a-mbstowcs.$(OBJEXT) lib_a-mbstowcs_r.$(OBJEXT) \
 	lib_a-mbtowc.$(OBJEXT) lib_a-mbtowc_r.$(OBJEXT) \
@@ -165,14 +168,15 @@ am__objects_9 = __adjust.lo __atexit.lo __call_atexit.lo __exp10.lo \
 	div.lo dtoa.lo dtoastub.lo environ.lo envlock.lo eprintf.lo \
 	exit.lo gdtoa-gethex.lo gdtoa-hexnan.lo getenv.lo getenv_r.lo \
 	imaxabs.lo imaxdiv.lo itoa.lo labs.lo ldiv.lo ldtoa.lo \
-	malloc.lo mblen.lo mblen_r.lo mbstowcs.lo mbstowcs_r.lo \
-	mbtowc.lo mbtowc_r.lo mlock.lo mprec.lo mstats.lo \
-	on_exit_args.lo quick_exit.lo rand.lo rand_r.lo random.lo \
-	realloc.lo reallocarray.lo reallocf.lo sb_charsets.lo \
-	strtod.lo strtoimax.lo strtol.lo strtoul.lo strtoumax.lo \
-	utoa.lo wcstod.lo wcstoimax.lo wcstol.lo wcstoul.lo \
-	wcstoumax.lo wcstombs.lo wcstombs_r.lo wctomb.lo wctomb_r.lo \
-	$(am__objects_8)
+	gdtoa-ldtoa.lo gdtoa-gdtoa.lo gdtoa-dtoa.lo gdtoa-misc.lo \
+	gdtoa-dmisc.lo gdtoa-gmisc.lo malloc.lo mblen.lo mblen_r.lo \
+	mbstowcs.lo mbstowcs_r.lo mbtowc.lo mbtowc_r.lo mlock.lo \
+	mprec.lo mstats.lo on_exit_args.lo quick_exit.lo rand.lo \
+	rand_r.lo random.lo realloc.lo reallocarray.lo reallocf.lo \
+	sb_charsets.lo strtod.lo strtoimax.lo strtol.lo strtoul.lo \
+	strtoumax.lo utoa.lo wcstod.lo wcstoimax.lo wcstol.lo \
+	wcstoul.lo wcstoumax.lo wcstombs.lo wcstombs_r.lo wctomb.lo \
+	wctomb_r.lo $(am__objects_8)
 am__objects_10 = arc4random.lo arc4random_uniform.lo cxa_atexit.lo \
 	cxa_finalize.lo drand48.lo ecvtbuf.lo efgcvt.lo erand48.lo \
 	jrand48.lo lcong48.lo lrand48.lo mrand48.lo msize.lo mtrim.lo \
@@ -354,6 +358,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 shared_machine_dir = @shared_machine_dir@
 sharedstatedir = @sharedstatedir@
@@ -372,13 +377,14 @@ GENERAL_SOURCES = __adjust.c __atexit.c __call_atexit.c __exp10.c \
 	atexit.c atof.c atoff.c atoi.c atol.c calloc.c div.c dtoa.c \
 	dtoastub.c environ.c envlock.c eprintf.c exit.c gdtoa-gethex.c \
 	gdtoa-hexnan.c getenv.c getenv_r.c imaxabs.c imaxdiv.c itoa.c \
-	labs.c ldiv.c ldtoa.c malloc.c mblen.c mblen_r.c mbstowcs.c \
-	mbstowcs_r.c mbtowc.c mbtowc_r.c mlock.c mprec.c mstats.c \
-	on_exit_args.c quick_exit.c rand.c rand_r.c random.c realloc.c \
-	reallocarray.c reallocf.c sb_charsets.c strtod.c strtoimax.c \
-	strtol.c strtoul.c strtoumax.c utoa.c wcstod.c wcstoimax.c \
-	wcstol.c wcstoul.c wcstoumax.c wcstombs.c wcstombs_r.c \
-	wctomb.c wctomb_r.c $(am__append_1)
+	labs.c ldiv.c ldtoa.c gdtoa-ldtoa.c gdtoa-gdtoa.c gdtoa-dtoa.c \
+	gdtoa-misc.c gdtoa-dmisc.c gdtoa-gmisc.c malloc.c mblen.c \
+	mblen_r.c mbstowcs.c mbstowcs_r.c mbtowc.c mbtowc_r.c mlock.c \
+	mprec.c mstats.c on_exit_args.c quick_exit.c rand.c rand_r.c \
+	random.c realloc.c reallocarray.c reallocf.c sb_charsets.c \
+	strtod.c strtoimax.c strtol.c strtoul.c strtoumax.c utoa.c \
+	wcstod.c wcstoimax.c wcstol.c wcstoul.c wcstoumax.c wcstombs.c \
+	wcstombs_r.c wctomb.c wctomb_r.c $(am__append_1)
 @NEWLIB_NANO_MALLOC_FALSE@MALIGNR = malignr
 @NEWLIB_NANO_MALLOC_TRUE@MALIGNR = nano-malignr
 @NEWLIB_NANO_MALLOC_FALSE@MALLOPTR = malloptr
@@ -827,6 +833,42 @@ lib_a-ldtoa.o: ldtoa.c
 lib_a-ldtoa.obj: ldtoa.c
 	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-ldtoa.obj `if test -f 'ldtoa.c'; then $(CYGPATH_W) 'ldtoa.c'; else $(CYGPATH_W) '$(srcdir)/ldtoa.c'; fi`
 
+lib_a-gdtoa-ldtoa.o: gdtoa-ldtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-ldtoa.o `test -f 'gdtoa-ldtoa.c' || echo '$(srcdir)/'`gdtoa-ldtoa.c
+
+lib_a-gdtoa-ldtoa.obj: gdtoa-ldtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-ldtoa.obj `if test -f 'gdtoa-ldtoa.c'; then $(CYGPATH_W) 'gdtoa-ldtoa.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-ldtoa.c'; fi`
+
+lib_a-gdtoa-gdtoa.o: gdtoa-gdtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-gdtoa.o `test -f 'gdtoa-gdtoa.c' || echo '$(srcdir)/'`gdtoa-gdtoa.c
+
+lib_a-gdtoa-gdtoa.obj: gdtoa-gdtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-gdtoa.obj `if test -f 'gdtoa-gdtoa.c'; then $(CYGPATH_W) 'gdtoa-gdtoa.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-gdtoa.c'; fi`
+
+lib_a-gdtoa-dtoa.o: gdtoa-dtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-dtoa.o `test -f 'gdtoa-dtoa.c' || echo '$(srcdir)/'`gdtoa-dtoa.c
+
+lib_a-gdtoa-dtoa.obj: gdtoa-dtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-dtoa.obj `if test -f 'gdtoa-dtoa.c'; then $(CYGPATH_W) 'gdtoa-dtoa.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-dtoa.c'; fi`
+
+lib_a-gdtoa-misc.o: gdtoa-misc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-misc.o `test -f 'gdtoa-misc.c' || echo '$(srcdir)/'`gdtoa-misc.c
+
+lib_a-gdtoa-misc.obj: gdtoa-misc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-misc.obj `if test -f 'gdtoa-misc.c'; then $(CYGPATH_W) 'gdtoa-misc.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-misc.c'; fi`
+
+lib_a-gdtoa-dmisc.o: gdtoa-dmisc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-dmisc.o `test -f 'gdtoa-dmisc.c' || echo '$(srcdir)/'`gdtoa-dmisc.c
+
+lib_a-gdtoa-dmisc.obj: gdtoa-dmisc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-dmisc.obj `if test -f 'gdtoa-dmisc.c'; then $(CYGPATH_W) 'gdtoa-dmisc.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-dmisc.c'; fi`
+
+lib_a-gdtoa-gmisc.o: gdtoa-gmisc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-gmisc.o `test -f 'gdtoa-gmisc.c' || echo '$(srcdir)/'`gdtoa-gmisc.c
+
+lib_a-gdtoa-gmisc.obj: gdtoa-gmisc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-gmisc.obj `if test -f 'gdtoa-gmisc.c'; then $(CYGPATH_W) 'gdtoa-gmisc.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-gmisc.c'; fi`
+
 lib_a-malloc.o: malloc.c
 	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-malloc.o `test -f 'malloc.c' || echo '$(srcdir)/'`malloc.c
 
@@ -1610,7 +1652,13 @@ $(lpfx)$(MALLOPTR).$(oext): $(MALLOCR).c
 	$(MALLOC_COMPILE) -DDEFINE_MALLOPT -c $(srcdir)/$(MALLOCR).c -o $@
 
 $(lpfx)dtoa.$(oext): dtoa.c mprec.h
-$(lpfx)ldtoa.$(oext): ldtoa.c mprec.h
+$(lpfx)ldtoa.$(oext): ldtoa.c mprec.h gdtoa.h
+$(lpfx)gdtoa-ldtoa.$(oext): gdtoa-ldtoa.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-gdtoa.$(oext): gdtoa-gdtoa.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-dtoa.$(oext): gdtoa-dtoa.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-misc.$(oext): gdtoa-misc.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-dmisc.$(oext): gdtoa-dmisc.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-gmisc.$(oext): gdtoa-gmisc.c gdtoaimp.h gdtoa.h arith.h
 $(lpfx)ecvtbuf.$(oext): ecvtbuf.c mprec.h
 $(lpfx)mbtowc_r.$(oext): mbtowc_r.c mbctype.h
 $(lpfx)mprec.$(oext): mprec.c mprec.h
diff --git a/newlib/libc/stdlib/arith.h b/newlib/libc/stdlib/arith.h
new file mode 100644
index 000000000..d3b84d867
--- /dev/null
+++ b/newlib/libc/stdlib/arith.h
@@ -0,0 +1,9 @@
+#include <machine/ieeefp.h>
+
+#ifdef __IEEE_LITTLE_ENDIAN
+#define IEEE_8087
+#endif
+
+#ifdef __IEEE_BIG_ENDIAN
+#define IEEE_MC68k
+#endif
diff --git a/newlib/libc/stdlib/gdtoa-dmisc.c b/newlib/libc/stdlib/gdtoa-dmisc.c
new file mode 100644
index 000000000..f3d8ea71a
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-dmisc.c
@@ -0,0 +1,225 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include "gdtoaimp.h"
+
+#ifndef MULTIPLE_THREADS
+ char *dtoa_result;
+#endif
+
+ char *
+#ifdef KR_headers
+rv_alloc(i) int i;
+#else
+rv_alloc(int i)
+#endif
+{
+	int j, k, *r;
+
+	j = sizeof(ULong);
+	for(k = 0;
+		sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i;
+		j <<= 1)
+			k++;
+	r = (int*)Balloc(k);
+	if (r == NULL)
+		return (
+#ifndef MULTIPLE_THREADS
+		dtoa_result =
+#endif
+			NULL);
+	*r = k;
+	return
+#ifndef MULTIPLE_THREADS
+	dtoa_result =
+#endif
+		(char *)(r+1);
+	}
+
+ char *
+#ifdef KR_headers
+nrv_alloc(s, rve, n) char *s, **rve; int n;
+#else
+nrv_alloc(char *s, char **rve, int n)
+#endif
+{
+	char *rv, *t;
+
+	t = rv = rv_alloc(n);
+	if (t == NULL)
+		return (NULL);
+	while((*t = *s++) !=0)
+		t++;
+	if (rve)
+		*rve = t;
+	return rv;
+	}
+
+/* freedtoa(s) must be used to free values s returned by dtoa
+ * when MULTIPLE_THREADS is #defined.  It should be used in all cases,
+ * but for consistency with earlier versions of dtoa, it is optional
+ * when MULTIPLE_THREADS is not defined.
+ */
+
+ void
+#ifdef KR_headers
+freedtoa(s) char *s;
+#else
+freedtoa(char *s)
+#endif
+{
+	Bigint *b = (Bigint *)((int *)s - 1);
+	b->maxwds = 1 << (b->k = *(int*)b);
+	Bfree(b);
+#ifndef MULTIPLE_THREADS
+	if (s == dtoa_result)
+		dtoa_result = 0;
+#endif
+	}
+DEF_STRONG(freedtoa);
+
+ int
+quorem
+#ifdef KR_headers
+	(b, S) Bigint *b, *S;
+#else
+	(Bigint *b, Bigint *S)
+#endif
+{
+	int n;
+	ULong *bx, *bxe, q, *sx, *sxe;
+#ifdef ULLong
+	ULLong borrow, carry, y, ys;
+#else
+	ULong borrow, carry, y, ys;
+#ifdef Pack_32
+	ULong si, z, zs;
+#endif
+#endif
+
+	n = S->wds;
+#ifdef DEBUG
+	/*debug*/ if (b->wds > n)
+	/*debug*/	Bug("oversize b in quorem");
+#endif
+	if (b->wds < n)
+		return 0;
+	sx = S->x;
+	sxe = sx + --n;
+	bx = b->x;
+	bxe = bx + n;
+	q = *bxe / (*sxe + 1);	/* ensure q <= true quotient */
+#ifdef DEBUG
+	/*debug*/ if (q > 9)
+	/*debug*/	Bug("oversized quotient in quorem");
+#endif
+	if (q) {
+		borrow = 0;
+		carry = 0;
+		do {
+#ifdef ULLong
+			ys = *sx++ * (ULLong)q + carry;
+			carry = ys >> 32;
+			y = *bx - (ys & 0xffffffffUL) - borrow;
+			borrow = y >> 32 & 1UL;
+			*bx++ = y & 0xffffffffUL;
+#else
+#ifdef Pack_32
+			si = *sx++;
+			ys = (si & 0xffff) * q + carry;
+			zs = (si >> 16) * q + (ys >> 16);
+			carry = zs >> 16;
+			y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			z = (*bx >> 16) - (zs & 0xffff) - borrow;
+			borrow = (z & 0x10000) >> 16;
+			Storeinc(bx, z, y);
+#else
+			ys = *sx++ * q + carry;
+			carry = ys >> 16;
+			y = *bx - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			*bx++ = y & 0xffff;
+#endif
+#endif
+			}
+			while(sx <= sxe);
+		if (!*bxe) {
+			bx = b->x;
+			while(--bxe > bx && !*bxe)
+				--n;
+			b->wds = n;
+			}
+		}
+	if (cmp(b, S) >= 0) {
+		q++;
+		borrow = 0;
+		carry = 0;
+		bx = b->x;
+		sx = S->x;
+		do {
+#ifdef ULLong
+			ys = *sx++ + carry;
+			carry = ys >> 32;
+			y = *bx - (ys & 0xffffffffUL) - borrow;
+			borrow = y >> 32 & 1UL;
+			*bx++ = y & 0xffffffffUL;
+#else
+#ifdef Pack_32
+			si = *sx++;
+			ys = (si & 0xffff) + carry;
+			zs = (si >> 16) + (ys >> 16);
+			carry = zs >> 16;
+			y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			z = (*bx >> 16) - (zs & 0xffff) - borrow;
+			borrow = (z & 0x10000) >> 16;
+			Storeinc(bx, z, y);
+#else
+			ys = *sx++ + carry;
+			carry = ys >> 16;
+			y = *bx - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			*bx++ = y & 0xffff;
+#endif
+#endif
+			}
+			while(sx <= sxe);
+		bx = b->x;
+		bxe = bx + n;
+		if (!*bxe) {
+			while(--bxe > bx && !*bxe)
+				--n;
+			b->wds = n;
+			}
+		}
+	return q;
+	}
diff --git a/newlib/libc/stdlib/gdtoa-dtoa.c b/newlib/libc/stdlib/gdtoa-dtoa.c
new file mode 100644
index 000000000..998192764
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-dtoa.c
@@ -0,0 +1,839 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998, 1999 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include "gdtoaimp.h"
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ *	1. Rather than iterating, we use a simple numeric overestimate
+ *	   to determine k = floor(log10(d)).  We scale relevant
+ *	   quantities using O(log2(k)) rather than O(k) multiplications.
+ *	2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ *	   try to generate digits strictly left to right.  Instead, we
+ *	   compute with fewer bits and propagate the carry if necessary
+ *	   when rounding the final digit up.  This is often faster.
+ *	3. Under the assumption that input will be rounded nearest,
+ *	   mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ *	   That is, we allow equality in stopping tests when the
+ *	   round-nearest rule will give the same floating-point value
+ *	   as would satisfaction of the stopping test with strict
+ *	   inequality.
+ *	4. We remove common factors of powers of 2 from relevant
+ *	   quantities.
+ *	5. When converting floating-point integers less than 1e16,
+ *	   we use floating-point arithmetic rather than resorting
+ *	   to multiple-precision integers.
+ *	6. When asked to produce fewer than 15 digits, we first try
+ *	   to get by with floating-point arithmetic; we resort to
+ *	   multiple-precision integer arithmetic only if we cannot
+ *	   guarantee that the floating-point calculation has given
+ *	   the correctly rounded result.  For k requested digits and
+ *	   "uniformly" distributed input, the probability is
+ *	   something like 10^(k-15) that we must resort to the Long
+ *	   calculation.
+ */
+
+#ifdef Honor_FLT_ROUNDS
+#undef Check_FLT_ROUNDS
+#define Check_FLT_ROUNDS
+#else
+#define Rounding Flt_Rounds
+#endif
+
+ char *
+dtoa
+#ifdef KR_headers
+	(d0, mode, ndigits, decpt, sign, rve)
+	double d0; int mode, ndigits, *decpt, *sign; char **rve;
+#else
+	(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
+#endif
+{
+ /*	Arguments ndigits, decpt, sign are similar to those
+	of ecvt and fcvt; trailing zeros are suppressed from
+	the returned string.  If not null, *rve is set to point
+	to the end of the return value.  If d is +-Infinity or NaN,
+	then *decpt is set to 9999.
+
+	mode:
+		0 ==> shortest string that yields d when read in
+			and rounded to nearest.
+		1 ==> like 0, but with Steele & White stopping rule;
+			e.g. with IEEE P754 arithmetic , mode 0 gives
+			1e23 whereas mode 1 gives 9.999999999999999e22.
+		2 ==> max(1,ndigits) significant digits.  This gives a
+			return value similar to that of ecvt, except
+			that trailing zeros are suppressed.
+		3 ==> through ndigits past the decimal point.  This
+			gives a return value similar to that from fcvt,
+			except that trailing zeros are suppressed, and
+			ndigits can be negative.
+		4,5 ==> similar to 2 and 3, respectively, but (in
+			round-nearest mode) with the tests of mode 0 to
+			possibly return a shorter string that rounds to d.
+			With IEEE arithmetic and compilation with
+			-DHonor_FLT_ROUNDS, modes 4 and 5 behave the same
+			as modes 2 and 3 when FLT_ROUNDS != 1.
+		6-9 ==> Debugging modes similar to mode - 4:  don't try
+			fast floating-point estimate (if applicable).
+
+		Values of mode other than 0-9 are treated as mode 0.
+
+		Sufficient space is allocated to the return value
+		to hold the suppressed trailing zeros.
+	*/
+
+	int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,
+		j, j1, k, k0, k_check, leftright, m2, m5, s2, s5,
+		spec_case, try_quick;
+	Long L;
+#ifndef Sudden_Underflow
+	int denorm;
+	ULong x;
+#endif
+	Bigint *b, *b1, *delta, *mlo, *mhi, *S;
+	U d, d2, eps;
+	double ds;
+	char *s, *s0;
+#ifdef SET_INEXACT
+	int inexact, oldinexact;
+#endif
+#ifdef Honor_FLT_ROUNDS /*{*/
+	int Rounding;
+#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */
+	Rounding = Flt_Rounds;
+#else /*}{*/
+	Rounding = 1;
+	switch(fegetround()) {
+	  case FE_TOWARDZERO:	Rounding = 0; break;
+	  case FE_UPWARD:	Rounding = 2; break;
+	  case FE_DOWNWARD:	Rounding = 3;
+	  }
+#endif /*}}*/
+#endif /*}*/
+
+#ifndef MULTIPLE_THREADS
+	if (dtoa_result) {
+		freedtoa(dtoa_result);
+		dtoa_result = 0;
+		}
+#endif
+	d.d = d0;
+	if (word0(&d) & Sign_bit) {
+		/* set sign for everything, including 0's and NaNs */
+		*sign = 1;
+		word0(&d) &= ~Sign_bit;	/* clear sign bit */
+		}
+	else
+		*sign = 0;
+
+#if defined(IEEE_Arith) + defined(VAX)
+#ifdef IEEE_Arith
+	if ((word0(&d) & Exp_mask) == Exp_mask)
+#else
+	if (word0(&d)  == 0x8000)
+#endif
+		{
+		/* Infinity or NaN */
+		*decpt = 9999;
+#ifdef IEEE_Arith
+		if (!word1(&d) && !(word0(&d) & 0xfffff))
+			return nrv_alloc("Infinity", rve, 8);
+#endif
+		return nrv_alloc("NaN", rve, 3);
+		}
+#endif
+#ifdef IBM
+	dval(&d) += 0; /* normalize */
+#endif
+	if (!dval(&d)) {
+		*decpt = 1;
+		return nrv_alloc("0", rve, 1);
+		}
+
+#ifdef SET_INEXACT
+	try_quick = oldinexact = get_inexact();
+	inexact = 1;
+#endif
+#ifdef Honor_FLT_ROUNDS
+	if (Rounding >= 2) {
+		if (*sign)
+			Rounding = Rounding == 2 ? 0 : 2;
+		else
+			if (Rounding != 2)
+				Rounding = 0;
+		}
+#endif
+
+	b = d2b(dval(&d), &be, &bbits);
+	if (b == NULL)
+		return (NULL);
+#ifdef Sudden_Underflow
+	i = (int)(word0(&d) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
+#else
+	if (( i = (int)(word0(&d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)) )!=0) {
+#endif
+		dval(&d2) = dval(&d);
+		word0(&d2) &= Frac_mask1;
+		word0(&d2) |= Exp_11;
+#ifdef IBM
+		if (( j = 11 - hi0bits(word0(&d2) & Frac_mask) )!=0)
+			dval(&d2) /= 1 << j;
+#endif
+
+		/* log(x)	~=~ log(1.5) + (x-1.5)/1.5
+		 * log10(x)	 =  log(x) / log(10)
+		 *		~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+		 * log10(&d) = (i-Bias)*log(2)/log(10) + log10(&d2)
+		 *
+		 * This suggests computing an approximation k to log10(&d) by
+		 *
+		 * k = (i - Bias)*0.301029995663981
+		 *	+ ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+		 *
+		 * We want k to be too large rather than too small.
+		 * The error in the first-order Taylor series approximation
+		 * is in our favor, so we just round up the constant enough
+		 * to compensate for any error in the multiplication of
+		 * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+		 * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+		 * adding 1e-13 to the constant term more than suffices.
+		 * Hence we adjust the constant term to 0.1760912590558.
+		 * (We could get a more accurate k by invoking log10,
+		 *  but this is probably not worthwhile.)
+		 */
+
+		i -= Bias;
+#ifdef IBM
+		i <<= 2;
+		i += j;
+#endif
+#ifndef Sudden_Underflow
+		denorm = 0;
+		}
+	else {
+		/* d is denormalized */
+
+		i = bbits + be + (Bias + (P-1) - 1);
+		x = i > 32  ? word0(&d) << (64 - i) | word1(&d) >> (i - 32)
+			    : word1(&d) << (32 - i);
+		dval(&d2) = x;
+		word0(&d2) -= 31*Exp_msk1; /* adjust exponent */
+		i -= (Bias + (P-1) - 1) + 1;
+		denorm = 1;
+		}
+#endif
+	ds = (dval(&d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
+	k = (int)ds;
+	if (ds < 0. && ds != k)
+		k--;	/* want k = floor(ds) */
+	k_check = 1;
+	if (k >= 0 && k <= Ten_pmax) {
+		if (dval(&d) < tens[k])
+			k--;
+		k_check = 0;
+		}
+	j = bbits - i - 1;
+	if (j >= 0) {
+		b2 = 0;
+		s2 = j;
+		}
+	else {
+		b2 = -j;
+		s2 = 0;
+		}
+	if (k >= 0) {
+		b5 = 0;
+		s5 = k;
+		s2 += k;
+		}
+	else {
+		b2 -= k;
+		b5 = -k;
+		s5 = 0;
+		}
+	if (mode < 0 || mode > 9)
+		mode = 0;
+
+#ifndef SET_INEXACT
+#ifdef Check_FLT_ROUNDS
+	try_quick = Rounding == 1;
+#else
+	try_quick = 1;
+#endif
+#endif /*SET_INEXACT*/
+
+	if (mode > 5) {
+		mode -= 4;
+		try_quick = 0;
+		}
+	leftright = 1;
+	ilim = ilim1 = -1;	/* Values for cases 0 and 1; done here to */
+				/* silence erroneous "gcc -Wall" warning. */
+	switch(mode) {
+		case 0:
+		case 1:
+			i = 18;
+			ndigits = 0;
+			break;
+		case 2:
+			leftright = 0;
+			/* no break */
+		case 4:
+			if (ndigits <= 0)
+				ndigits = 1;
+			ilim = ilim1 = i = ndigits;
+			break;
+		case 3:
+			leftright = 0;
+			/* no break */
+		case 5:
+			i = ndigits + k + 1;
+			ilim = i;
+			ilim1 = i - 1;
+			if (i <= 0)
+				i = 1;
+		}
+	s = s0 = rv_alloc(i);
+	if (s == NULL)
+		return (NULL);
+
+#ifdef Honor_FLT_ROUNDS
+	if (mode > 1 && Rounding != 1)
+		leftright = 0;
+#endif
+
+	if (ilim >= 0 && ilim <= Quick_max && try_quick) {
+
+		/* Try to get by with floating-point arithmetic. */
+
+		i = 0;
+		dval(&d2) = dval(&d);
+		k0 = k;
+		ilim0 = ilim;
+		ieps = 2; /* conservative */
+		if (k > 0) {
+			ds = tens[k&0xf];
+			j = k >> 4;
+			if (j & Bletch) {
+				/* prevent overflows */
+				j &= Bletch - 1;
+				dval(&d) /= bigtens[n_bigtens-1];
+				ieps++;
+				}
+			for(; j; j >>= 1, i++)
+				if (j & 1) {
+					ieps++;
+					ds *= bigtens[i];
+					}
+			dval(&d) /= ds;
+			}
+		else if (( j1 = -k )!=0) {
+			dval(&d) *= tens[j1 & 0xf];
+			for(j = j1 >> 4; j; j >>= 1, i++)
+				if (j & 1) {
+					ieps++;
+					dval(&d) *= bigtens[i];
+					}
+			}
+		if (k_check && dval(&d) < 1. && ilim > 0) {
+			if (ilim1 <= 0)
+				goto fast_failed;
+			ilim = ilim1;
+			k--;
+			dval(&d) *= 10.;
+			ieps++;
+			}
+		dval(&eps) = ieps*dval(&d) + 7.;
+		word0(&eps) -= (P-1)*Exp_msk1;
+		if (ilim == 0) {
+			S = mhi = 0;
+			dval(&d) -= 5.;
+			if (dval(&d) > dval(&eps))
+				goto one_digit;
+			if (dval(&d) < -dval(&eps))
+				goto no_digits;
+			goto fast_failed;
+			}
+#ifndef No_leftright
+		if (leftright) {
+			/* Use Steele & White method of only
+			 * generating digits needed.
+			 */
+			dval(&eps) = 0.5/tens[ilim-1] - dval(&eps);
+			for(i = 0;;) {
+				L = dval(&d);
+				dval(&d) -= L;
+				*s++ = '0' + (int)L;
+				if (dval(&d) < dval(&eps))
+					goto ret1;
+				if (1. - dval(&d) < dval(&eps))
+					goto bump_up;
+				if (++i >= ilim)
+					break;
+				dval(&eps) *= 10.;
+				dval(&d) *= 10.;
+				}
+			}
+		else {
+#endif
+			/* Generate ilim digits, then fix them up. */
+			dval(&eps) *= tens[ilim-1];
+			for(i = 1;; i++, dval(&d) *= 10.) {
+				L = (Long)(dval(&d));
+				if (!(dval(&d) -= L))
+					ilim = i;
+				*s++ = '0' + (int)L;
+				if (i == ilim) {
+					if (dval(&d) > 0.5 + dval(&eps))
+						goto bump_up;
+					else if (dval(&d) < 0.5 - dval(&eps)) {
+						while(*--s == '0');
+						s++;
+						goto ret1;
+						}
+					break;
+					}
+				}
+#ifndef No_leftright
+			}
+#endif
+ fast_failed:
+		s = s0;
+		dval(&d) = dval(&d2);
+		k = k0;
+		ilim = ilim0;
+		}
+
+	/* Do we have a "small" integer? */
+
+	if (be >= 0 && k <= Int_max) {
+		/* Yes. */
+		ds = tens[k];
+		if (ndigits < 0 && ilim <= 0) {
+			S = mhi = 0;
+			if (ilim < 0 || dval(&d) <= 5*ds)
+				goto no_digits;
+			goto one_digit;
+			}
+		for(i = 1;; i++, dval(&d) *= 10.) {
+			L = (Long)(dval(&d) / ds);
+			dval(&d) -= L*ds;
+#ifdef Check_FLT_ROUNDS
+			/* If FLT_ROUNDS == 2, L will usually be high by 1 */
+			if (dval(&d) < 0) {
+				L--;
+				dval(&d) += ds;
+				}
+#endif
+			*s++ = '0' + (int)L;
+			if (!dval(&d)) {
+#ifdef SET_INEXACT
+				inexact = 0;
+#endif
+				break;
+				}
+			if (i == ilim) {
+#ifdef Honor_FLT_ROUNDS
+				if (mode > 1)
+				switch(Rounding) {
+				  case 0: goto ret1;
+				  case 2: goto bump_up;
+				  }
+#endif
+				dval(&d) += dval(&d);
+#ifdef ROUND_BIASED
+				if (dval(&d) >= ds)
+#else
+				if (dval(&d) > ds || (dval(&d) == ds && L & 1))
+#endif
+					{
+ bump_up:
+					while(*--s == '9')
+						if (s == s0) {
+							k++;
+							*s = '0';
+							break;
+							}
+					++*s++;
+					}
+				break;
+				}
+			}
+		goto ret1;
+		}
+
+	m2 = b2;
+	m5 = b5;
+	mhi = mlo = 0;
+	if (leftright) {
+		i =
+#ifndef Sudden_Underflow
+			denorm ? be + (Bias + (P-1) - 1 + 1) :
+#endif
+#ifdef IBM
+			1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3);
+#else
+			1 + P - bbits;
+#endif
+		b2 += i;
+		s2 += i;
+		mhi = i2b(1);
+		if (mhi == NULL)
+			return (NULL);
+		}
+	if (m2 > 0 && s2 > 0) {
+		i = m2 < s2 ? m2 : s2;
+		b2 -= i;
+		m2 -= i;
+		s2 -= i;
+		}
+	if (b5 > 0) {
+		if (leftright) {
+			if (m5 > 0) {
+				mhi = pow5mult(mhi, m5);
+				if (mhi == NULL)
+					return (NULL);
+				b1 = mult(mhi, b);
+				if (b1 == NULL)
+					return (NULL);
+				Bfree(b);
+				b = b1;
+				}
+			if (( j = b5 - m5 )!=0) {
+				b = pow5mult(b, j);
+				if (b == NULL)
+					return (NULL);
+				}
+			}
+		else {
+			b = pow5mult(b, b5);
+			if (b == NULL)
+				return (NULL);
+			}
+		}
+	S = i2b(1);
+	if (S == NULL)
+		return (NULL);
+	if (s5 > 0) {
+		S = pow5mult(S, s5);
+		if (S == NULL)
+			return (NULL);
+		}
+
+	/* Check for special case that d is a normalized power of 2. */
+
+	spec_case = 0;
+	if ((mode < 2 || leftright)
+#ifdef Honor_FLT_ROUNDS
+			&& Rounding == 1
+#endif
+				) {
+		if (!word1(&d) && !(word0(&d) & Bndry_mask)
+#ifndef Sudden_Underflow
+		 && word0(&d) & (Exp_mask & ~Exp_msk1)
+#endif
+				) {
+			/* The special case */
+			b2 += Log2P;
+			s2 += Log2P;
+			spec_case = 1;
+			}
+		}
+
+	/* Arrange for convenient computation of quotients:
+	 * shift left if necessary so divisor has 4 leading 0 bits.
+	 *
+	 * Perhaps we should just compute leading 28 bits of S once
+	 * and for all and pass them and a shift to quorem, so it
+	 * can do shifts and ors to compute the numerator for q.
+	 */
+#ifdef Pack_32
+	if (( i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f )!=0)
+		i = 32 - i;
+#else
+	if (( i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf )!=0)
+		i = 16 - i;
+#endif
+	if (i > 4) {
+		i -= 4;
+		b2 += i;
+		m2 += i;
+		s2 += i;
+		}
+	else if (i < 4) {
+		i += 28;
+		b2 += i;
+		m2 += i;
+		s2 += i;
+		}
+	if (b2 > 0) {
+		b = lshift(b, b2);
+		if (b == NULL)
+			return (NULL);
+		}
+	if (s2 > 0) {
+		S = lshift(S, s2);
+		if (S == NULL)
+			return (NULL);
+		}
+	if (k_check) {
+		if (cmp(b,S) < 0) {
+			k--;
+			b = multadd(b, 10, 0);	/* we botched the k estimate */
+			if (b == NULL)
+				return (NULL);
+			if (leftright) {
+				mhi = multadd(mhi, 10, 0);
+				if (mhi == NULL)
+					return (NULL);
+				}
+			ilim = ilim1;
+			}
+		}
+	if (ilim <= 0 && (mode == 3 || mode == 5)) {
+		S = multadd(S,5,0);
+		if (S == NULL)
+			return (NULL);
+		if (ilim < 0 || cmp(b,S) <= 0) {
+			/* no digits, fcvt style */
+ no_digits:
+			k = -1 - ndigits;
+			goto ret;
+			}
+ one_digit:
+		*s++ = '1';
+		k++;
+		goto ret;
+		}
+	if (leftright) {
+		if (m2 > 0) {
+			mhi = lshift(mhi, m2);
+			if (mhi == NULL)
+				return (NULL);
+			}
+
+		/* Compute mlo -- check for special case
+		 * that d is a normalized power of 2.
+		 */
+
+		mlo = mhi;
+		if (spec_case) {
+			mhi = Balloc(mhi->k);
+			if (mhi == NULL)
+				return (NULL);
+			Bcopy(mhi, mlo);
+			mhi = lshift(mhi, Log2P);
+			if (mhi == NULL)
+				return (NULL);
+			}
+
+		for(i = 1;;i++) {
+			dig = quorem(b,S) + '0';
+			/* Do we yet have the shortest decimal string
+			 * that will round to d?
+			 */
+			j = cmp(b, mlo);
+			delta = diff(S, mhi);
+			if (delta == NULL)
+				return (NULL);
+			j1 = delta->sign ? 1 : cmp(b, delta);
+			Bfree(delta);
+#ifndef ROUND_BIASED
+			if (j1 == 0 && mode != 1 && !(word1(&d) & 1)
+#ifdef Honor_FLT_ROUNDS
+				&& Rounding >= 1
+#endif
+								   ) {
+				if (dig == '9')
+					goto round_9_up;
+				if (j > 0)
+					dig++;
+#ifdef SET_INEXACT
+				else if (!b->x[0] && b->wds <= 1)
+					inexact = 0;
+#endif
+				*s++ = dig;
+				goto ret;
+				}
+#endif
+			if (j < 0 || (j == 0 && mode != 1
+#ifndef ROUND_BIASED
+							&& !(word1(&d) & 1)
+#endif
+					)) {
+				if (!b->x[0] && b->wds <= 1) {
+#ifdef SET_INEXACT
+					inexact = 0;
+#endif
+					goto accept_dig;
+					}
+#ifdef Honor_FLT_ROUNDS
+				if (mode > 1)
+				 switch(Rounding) {
+				  case 0: goto accept_dig;
+				  case 2: goto keep_dig;
+				  }
+#endif /*Honor_FLT_ROUNDS*/
+				if (j1 > 0) {
+					b = lshift(b, 1);
+					if (b == NULL)
+						return (NULL);
+					j1 = cmp(b, S);
+#ifdef ROUND_BIASED
+					if (j1 >= 0 /*)*/
+#else
+					if ((j1 > 0 || (j1 == 0 && dig & 1))
+#endif
+					&& dig++ == '9')
+						goto round_9_up;
+					}
+ accept_dig:
+				*s++ = dig;
+				goto ret;
+				}
+			if (j1 > 0) {
+#ifdef Honor_FLT_ROUNDS
+				if (!Rounding)
+					goto accept_dig;
+#endif
+				if (dig == '9') { /* possible if i == 1 */
+ round_9_up:
+					*s++ = '9';
+					goto roundoff;
+					}
+				*s++ = dig + 1;
+				goto ret;
+				}
+#ifdef Honor_FLT_ROUNDS
+ keep_dig:
+#endif
+			*s++ = dig;
+			if (i == ilim)
+				break;
+			b = multadd(b, 10, 0);
+			if (b == NULL)
+				return (NULL);
+			if (mlo == mhi) {
+				mlo = mhi = multadd(mhi, 10, 0);
+				if (mlo == NULL)
+					return (NULL);
+				}
+			else {
+				mlo = multadd(mlo, 10, 0);
+				if (mlo == NULL)
+					return (NULL);
+				mhi = multadd(mhi, 10, 0);
+				if (mhi == NULL)
+					return (NULL);
+				}
+			}
+		}
+	else
+		for(i = 1;; i++) {
+			*s++ = dig = quorem(b,S) + '0';
+			if (!b->x[0] && b->wds <= 1) {
+#ifdef SET_INEXACT
+				inexact = 0;
+#endif
+				goto ret;
+				}
+			if (i >= ilim)
+				break;
+			b = multadd(b, 10, 0);
+			if (b == NULL)
+				return (NULL);
+			}
+
+	/* Round off last digit */
+
+#ifdef Honor_FLT_ROUNDS
+	switch(Rounding) {
+	  case 0: goto trimzeros;
+	  case 2: goto roundoff;
+	  }
+#endif
+	b = lshift(b, 1);
+	if (b == NULL)
+		return (NULL);
+	j = cmp(b, S);
+#ifdef ROUND_BIASED
+	if (j >= 0)
+#else
+	if (j > 0 || (j == 0 && dig & 1))
+#endif
+		{
+ roundoff:
+		while(*--s == '9')
+			if (s == s0) {
+				k++;
+				*s++ = '1';
+				goto ret;
+				}
+		++*s++;
+		}
+	else {
+#ifdef Honor_FLT_ROUNDS
+ trimzeros:
+#endif
+		while(*--s == '0');
+		s++;
+		}
+ ret:
+	Bfree(S);
+	if (mhi) {
+		if (mlo && mlo != mhi)
+			Bfree(mlo);
+		Bfree(mhi);
+		}
+ ret1:
+#ifdef SET_INEXACT
+	if (inexact) {
+		if (!oldinexact) {
+			word0(&d) = Exp_1 + (70 << Exp_shift);
+			word1(&d) = 0;
+			dval(&d) += 1.;
+			}
+		}
+	else if (!oldinexact)
+		clear_inexact();
+#endif
+	Bfree(b);
+	*s = 0;
+	*decpt = k + 1;
+	if (rve)
+		*rve = s;
+	return s0;
+}
diff --git a/newlib/libc/stdlib/gdtoa-gdtoa.c b/newlib/libc/stdlib/gdtoa-gdtoa.c
new file mode 100644
index 000000000..feae5afa3
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-gdtoa.c
@@ -0,0 +1,830 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998, 1999 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include "gdtoaimp.h"
+
+ static Bigint *
+#ifdef KR_headers
+bitstob(bits, nbits, bbits) ULong *bits; int nbits; int *bbits;
+#else
+bitstob(ULong *bits, int nbits, int *bbits)
+#endif
+{
+	int i, k;
+	Bigint *b;
+	ULong *be, *x, *x0;
+
+	i = ULbits;
+	k = 0;
+	while(i < nbits) {
+		i <<= 1;
+		k++;
+		}
+#ifndef Pack_32
+	if (!k)
+		k = 1;
+#endif
+	b = Balloc(k);
+	if (b == NULL)
+		return (NULL);
+	be = bits + ((nbits - 1) >> kshift);
+	x = x0 = b->x;
+	do {
+		*x++ = *bits & ALL_ON;
+#ifdef Pack_16
+		*x++ = (*bits >> 16) & ALL_ON;
+#endif
+		} while(++bits <= be);
+	i = x - x0;
+	while(!x0[--i])
+		if (!i) {
+			b->wds = 0;
+			*bbits = 0;
+			goto ret;
+			}
+	b->wds = i + 1;
+	*bbits = i*ULbits + 32 - hi0bits(b->x[i]);
+ ret:
+	return b;
+	}
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ *	1. Rather than iterating, we use a simple numeric overestimate
+ *	   to determine k = floor(log10(d)).  We scale relevant
+ *	   quantities using O(log2(k)) rather than O(k) multiplications.
+ *	2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ *	   try to generate digits strictly left to right.  Instead, we
+ *	   compute with fewer bits and propagate the carry if necessary
+ *	   when rounding the final digit up.  This is often faster.
+ *	3. Under the assumption that input will be rounded nearest,
+ *	   mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ *	   That is, we allow equality in stopping tests when the
+ *	   round-nearest rule will give the same floating-point value
+ *	   as would satisfaction of the stopping test with strict
+ *	   inequality.
+ *	4. We remove common factors of powers of 2 from relevant
+ *	   quantities.
+ *	5. When converting floating-point integers less than 1e16,
+ *	   we use floating-point arithmetic rather than resorting
+ *	   to multiple-precision integers.
+ *	6. When asked to produce fewer than 15 digits, we first try
+ *	   to get by with floating-point arithmetic; we resort to
+ *	   multiple-precision integer arithmetic only if we cannot
+ *	   guarantee that the floating-point calculation has given
+ *	   the correctly rounded result.  For k requested digits and
+ *	   "uniformly" distributed input, the probability is
+ *	   something like 10^(k-15) that we must resort to the Long
+ *	   calculation.
+ */
+
+ char *
+gdtoa
+#ifdef KR_headers
+	(fpi, be, bits, kindp, mode, ndigits, decpt, rve)
+	FPI *fpi; int be; ULong *bits;
+	int *kindp, mode, ndigits, *decpt; char **rve;
+#else
+	(FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, int *decpt, char **rve)
+#endif
+{
+ /*	Arguments ndigits and decpt are similar to the second and third
+	arguments of ecvt and fcvt; trailing zeros are suppressed from
+	the returned string.  If not null, *rve is set to point
+	to the end of the return value.  If d is +-Infinity or NaN,
+	then *decpt is set to 9999.
+	be = exponent: value = (integer represented by bits) * (2 to the power of be).
+
+	mode:
+		0 ==> shortest string that yields d when read in
+			and rounded to nearest.
+		1 ==> like 0, but with Steele & White stopping rule;
+			e.g. with IEEE P754 arithmetic , mode 0 gives
+			1e23 whereas mode 1 gives 9.999999999999999e22.
+		2 ==> max(1,ndigits) significant digits.  This gives a
+			return value similar to that of ecvt, except
+			that trailing zeros are suppressed.
+		3 ==> through ndigits past the decimal point.  This
+			gives a return value similar to that from fcvt,
+			except that trailing zeros are suppressed, and
+			ndigits can be negative.
+		4-9 should give the same return values as 2-3, i.e.,
+			4 <= mode <= 9 ==> same return as mode
+			2 + (mode & 1).  These modes are mainly for
+			debugging; often they run slower but sometimes
+			faster than modes 2-3.
+		4,5,8,9 ==> left-to-right digit generation.
+		6-9 ==> don't try fast floating-point estimate
+			(if applicable).
+
+		Values of mode other than 0-9 are treated as mode 0.
+
+		Sufficient space is allocated to the return value
+		to hold the suppressed trailing zeros.
+	*/
+
+	int bbits, b2, b5, be0, dig, i, ieps, ilim, ilim0, ilim1, inex;
+	int j, j1, k, k0, k_check, kind, leftright, m2, m5, nbits;
+	int rdir, s2, s5, spec_case, try_quick;
+	Long L;
+	Bigint *b, *b1, *delta, *mlo, *mhi, *mhi1, *S;
+	double d2, ds;
+	char *s, *s0;
+	U d, eps;
+
+#ifndef MULTIPLE_THREADS
+	if (dtoa_result) {
+		freedtoa(dtoa_result);
+		dtoa_result = 0;
+		}
+#endif
+	inex = 0;
+	kind = *kindp &= ~STRTOG_Inexact;
+	switch(kind & STRTOG_Retmask) {
+	  case STRTOG_Zero:
+		goto ret_zero;
+	  case STRTOG_Normal:
+	  case STRTOG_Denormal:
+		break;
+	  case STRTOG_Infinite:
+		*decpt = -32768;
+		return nrv_alloc("Infinity", rve, 8);
+	  case STRTOG_NaN:
+		*decpt = -32768;
+		return nrv_alloc("NaN", rve, 3);
+	  default:
+		return 0;
+	  }
+	b = bitstob(bits, nbits = fpi->nbits, &bbits);
+	if (b == NULL)
+		return (NULL);
+	be0 = be;
+	if ( (i = trailz(b)) !=0) {
+		rshift(b, i);
+		be += i;
+		bbits -= i;
+		}
+	if (!b->wds) {
+		Bfree(b);
+ ret_zero:
+		*decpt = 1;
+		return nrv_alloc("0", rve, 1);
+		}
+
+	dval(&d) = b2d(b, &i);
+	i = be + bbits - 1;
+	word0(&d) &= Frac_mask1;
+	word0(&d) |= Exp_11;
+#ifdef IBM
+	if ( (j = 11 - hi0bits(word0(&d) & Frac_mask)) !=0)
+		dval(&d) /= 1 << j;
+#endif
+
+	/* log(x)	~=~ log(1.5) + (x-1.5)/1.5
+	 * log10(x)	 =  log(x) / log(10)
+	 *		~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+	 * log10(&d) = (i-Bias)*log(2)/log(10) + log10(d2)
+	 *
+	 * This suggests computing an approximation k to log10(&d) by
+	 *
+	 * k = (i - Bias)*0.301029995663981
+	 *	+ ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+	 *
+	 * We want k to be too large rather than too small.
+	 * The error in the first-order Taylor series approximation
+	 * is in our favor, so we just round up the constant enough
+	 * to compensate for any error in the multiplication of
+	 * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+	 * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+	 * adding 1e-13 to the constant term more than suffices.
+	 * Hence we adjust the constant term to 0.1760912590558.
+	 * (We could get a more accurate k by invoking log10,
+	 *  but this is probably not worthwhile.)
+	 */
+#ifdef IBM
+	i <<= 2;
+	i += j;
+#endif
+	ds = (dval(&d)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
+
+	/* correct assumption about exponent range */
+	if ((j = i) < 0)
+		j = -j;
+	if ((j -= 1077) > 0)
+		ds += j * 7e-17;
+
+	k = (int)ds;
+	if (ds < 0. && ds != k)
+		k--;	/* want k = floor(ds) */
+	k_check = 1;
+#ifdef IBM
+	j = be + bbits - 1;
+	if ( (j1 = j & 3) !=0)
+		dval(&d) *= 1 << j1;
+	word0(&d) += j << Exp_shift - 2 & Exp_mask;
+#else
+	word0(&d) += (be + bbits - 1) << Exp_shift;
+#endif
+	if (k >= 0 && k <= Ten_pmax) {
+		if (dval(&d) < tens[k])
+			k--;
+		k_check = 0;
+		}
+	j = bbits - i - 1;
+	if (j >= 0) {
+		b2 = 0;
+		s2 = j;
+		}
+	else {
+		b2 = -j;
+		s2 = 0;
+		}
+	if (k >= 0) {
+		b5 = 0;
+		s5 = k;
+		s2 += k;
+		}
+	else {
+		b2 -= k;
+		b5 = -k;
+		s5 = 0;
+		}
+	if (mode < 0 || mode > 9)
+		mode = 0;
+	try_quick = 1;
+	if (mode > 5) {
+		mode -= 4;
+		try_quick = 0;
+		}
+	else if (i >= -4 - Emin || i < Emin)
+		try_quick = 0;
+	leftright = 1;
+	ilim = ilim1 = -1;	/* Values for cases 0 and 1; done here to */
+				/* silence erroneous "gcc -Wall" warning. */
+	switch(mode) {
+		case 0:
+		case 1:
+			i = (int)(nbits * .30103) + 3;
+			ndigits = 0;
+			break;
+		case 2:
+			leftright = 0;
+			/* no break */
+		case 4:
+			if (ndigits <= 0)
+				ndigits = 1;
+			ilim = ilim1 = i = ndigits;
+			break;
+		case 3:
+			leftright = 0;
+			/* no break */
+		case 5:
+			i = ndigits + k + 1;
+			ilim = i;
+			ilim1 = i - 1;
+			if (i <= 0)
+				i = 1;
+		}
+	s = s0 = rv_alloc(i);
+	if (s == NULL)
+		return (NULL);
+
+	if ( (rdir = fpi->rounding - 1) !=0) {
+		if (rdir < 0)
+			rdir = 2;
+		if (kind & STRTOG_Neg)
+			rdir = 3 - rdir;
+		}
+
+	/* Now rdir = 0 ==> round near, 1 ==> round up, 2 ==> round down. */
+
+	if (ilim >= 0 && ilim <= Quick_max && try_quick && !rdir
+#ifndef IMPRECISE_INEXACT
+		&& k == 0
+#endif
+								) {
+
+		/* Try to get by with floating-point arithmetic. */
+
+		i = 0;
+		d2 = dval(&d);
+#ifdef IBM
+		if ( (j = 11 - hi0bits(word0(&d) & Frac_mask)) !=0)
+			dval(&d) /= 1 << j;
+#endif
+		k0 = k;
+		ilim0 = ilim;
+		ieps = 2; /* conservative */
+		if (k > 0) {
+			ds = tens[k&0xf];
+			j = k >> 4;
+			if (j & Bletch) {
+				/* prevent overflows */
+				j &= Bletch - 1;
+				dval(&d) /= bigtens[n_bigtens-1];
+				ieps++;
+				}
+			for(; j; j >>= 1, i++)
+				if (j & 1) {
+					ieps++;
+					ds *= bigtens[i];
+					}
+			}
+		else  {
+			ds = 1.;
+			if ( (j1 = -k) !=0) {
+				dval(&d) *= tens[j1 & 0xf];
+				for(j = j1 >> 4; j; j >>= 1, i++)
+					if (j & 1) {
+						ieps++;
+						dval(&d) *= bigtens[i];
+						}
+				}
+			}
+		if (k_check && dval(&d) < 1. && ilim > 0) {
+			if (ilim1 <= 0)
+				goto fast_failed;
+			ilim = ilim1;
+			k--;
+			dval(&d) *= 10.;
+			ieps++;
+			}
+		dval(&eps) = ieps*dval(&d) + 7.;
+		word0(&eps) -= (P-1)*Exp_msk1;
+		if (ilim == 0) {
+			S = mhi = 0;
+			dval(&d) -= 5.;
+			if (dval(&d) > dval(&eps))
+				goto one_digit;
+			if (dval(&d) < -dval(&eps))
+				goto no_digits;
+			goto fast_failed;
+			}
+#ifndef No_leftright
+		if (leftright) {
+			/* Use Steele & White method of only
+			 * generating digits needed.
+			 */
+			dval(&eps) = ds*0.5/tens[ilim-1] - dval(&eps);
+			for(i = 0;;) {
+				L = (Long)(dval(&d)/ds);
+				dval(&d) -= L*ds;
+				*s++ = '0' + (int)L;
+				if (dval(&d) < dval(&eps)) {
+					if (dval(&d))
+						inex = STRTOG_Inexlo;
+					goto ret1;
+					}
+				if (ds - dval(&d) < dval(&eps))
+					goto bump_up;
+				if (++i >= ilim)
+					break;
+				dval(&eps) *= 10.;
+				dval(&d) *= 10.;
+				}
+			}
+		else {
+#endif
+			/* Generate ilim digits, then fix them up. */
+			dval(&eps) *= tens[ilim-1];
+			for(i = 1;; i++, dval(&d) *= 10.) {
+				if ( (L = (Long)(dval(&d)/ds)) !=0)
+					dval(&d) -= L*ds;
+				*s++ = '0' + (int)L;
+				if (i == ilim) {
+					ds *= 0.5;
+					if (dval(&d) > ds + dval(&eps))
+						goto bump_up;
+					else if (dval(&d) < ds - dval(&eps)) {
+						if (dval(&d))
+							inex = STRTOG_Inexlo;
+						goto clear_trailing0;
+						}
+					break;
+					}
+				}
+#ifndef No_leftright
+			}
+#endif
+ fast_failed:
+		s = s0;
+		dval(&d) = d2;
+		k = k0;
+		ilim = ilim0;
+		}
+
+	/* Do we have a "small" integer? */
+
+	if (be >= 0 && k <= Int_max) {
+		/* Yes. */
+		ds = tens[k];
+		if (ndigits < 0 && ilim <= 0) {
+			S = mhi = 0;
+			if (ilim < 0 || dval(&d) <= 5*ds)
+				goto no_digits;
+			goto one_digit;
+			}
+		for(i = 1;; i++, dval(&d) *= 10.) {
+			L = dval(&d) / ds;
+			dval(&d) -= L*ds;
+#ifdef Check_FLT_ROUNDS
+			/* If FLT_ROUNDS == 2, L will usually be high by 1 */
+			if (dval(&d) < 0) {
+				L--;
+				dval(&d) += ds;
+				}
+#endif
+			*s++ = '0' + (int)L;
+			if (dval(&d) == 0.)
+				break;
+			if (i == ilim) {
+				if (rdir) {
+					if (rdir == 1)
+						goto bump_up;
+					inex = STRTOG_Inexlo;
+					goto ret1;
+					}
+				dval(&d) += dval(&d);
+#ifdef ROUND_BIASED
+				if (dval(&d) >= ds)
+#else
+				if (dval(&d) > ds || (dval(&d) == ds && L & 1))
+#endif
+					{
+ bump_up:
+					inex = STRTOG_Inexhi;
+					while(*--s == '9')
+						if (s == s0) {
+							k++;
+							*s = '0';
+							break;
+							}
+					++*s++;
+					}
+				else {
+					inex = STRTOG_Inexlo;
+ clear_trailing0:
+					while(*--s == '0'){}
+					++s;
+					}
+				break;
+				}
+			}
+		goto ret1;
+		}
+
+	m2 = b2;
+	m5 = b5;
+	mhi = mlo = 0;
+	if (leftright) {
+		i = nbits - bbits;
+		if (be - i++ < fpi->emin && mode != 3 && mode != 5) {
+			/* denormal */
+			i = be - fpi->emin + 1;
+			if (mode >= 2 && ilim > 0 && ilim < i)
+				goto small_ilim;
+			}
+		else if (mode >= 2) {
+ small_ilim:
+			j = ilim - 1;
+			if (m5 >= j)
+				m5 -= j;
+			else {
+				s5 += j -= m5;
+				b5 += j;
+				m5 = 0;
+				}
+			if ((i = ilim) < 0) {
+				m2 -= i;
+				i = 0;
+				}
+			}
+		b2 += i;
+		s2 += i;
+		mhi = i2b(1);
+		if (mhi == NULL)
+			return (NULL);
+		}
+	if (m2 > 0 && s2 > 0) {
+		i = m2 < s2 ? m2 : s2;
+		b2 -= i;
+		m2 -= i;
+		s2 -= i;
+		}
+	if (b5 > 0) {
+		if (leftright) {
+			if (m5 > 0) {
+				mhi = pow5mult(mhi, m5);
+				if (mhi == NULL)
+					return (NULL);
+				b1 = mult(mhi, b);
+				if (b1 == NULL)
+					return (NULL);
+				Bfree(b);
+				b = b1;
+				}
+			if ( (j = b5 - m5) !=0) {
+				b = pow5mult(b, j);
+				if (b == NULL)
+					return (NULL);
+				}
+			}
+		else {
+			b = pow5mult(b, b5);
+			if (b == NULL)
+				return (NULL);
+			}
+		}
+	S = i2b(1);
+	if (S == NULL)
+		return (NULL);
+	if (s5 > 0) {
+		S = pow5mult(S, s5);
+		if (S == NULL)
+			return (NULL);
+		}
+
+	/* Check for special case that d is a normalized power of 2. */
+
+	spec_case = 0;
+	if (mode < 2) {
+		if (bbits == 1 && be0 > fpi->emin + 1) {
+			/* The special case */
+			b2++;
+			s2++;
+			spec_case = 1;
+			}
+		}
+
+	/* Arrange for convenient computation of quotients:
+	 * shift left if necessary so divisor has 4 leading 0 bits.
+	 *
+	 * Perhaps we should just compute leading 28 bits of S once
+	 * and for all and pass them and a shift to quorem, so it
+	 * can do shifts and ors to compute the numerator for q.
+	 */
+	i = ((s5 ? hi0bits(S->x[S->wds-1]) : ULbits - 1) - s2 - 4) & kmask;
+	m2 += i;
+	if ((b2 += i) > 0) {
+		b = lshift(b, b2);
+		if (b == NULL)
+			return (NULL);
+		}
+	if ((s2 += i) > 0) {
+		S = lshift(S, s2);
+		if (S == NULL)
+			return (NULL);
+		}
+	if (k_check) {
+		if (cmp(b,S) < 0) {
+			k--;
+			b = multadd(b, 10, 0);	/* we botched the k estimate */
+			if (b == NULL)
+				return (NULL);
+			if (leftright) {
+				mhi = multadd(mhi, 10, 0);
+				if (mhi == NULL)
+					return (NULL);
+				}
+			ilim = ilim1;
+			}
+		}
+	if (ilim <= 0 && mode > 2) {
+		S = multadd(S,5,0);
+		if (S == NULL)
+			return (NULL);
+		if (ilim < 0 || cmp(b,S) <= 0) {
+			/* no digits, fcvt style */
+ no_digits:
+			k = -1 - ndigits;
+			inex = STRTOG_Inexlo;
+			goto ret;
+			}
+ one_digit:
+		inex = STRTOG_Inexhi;
+		*s++ = '1';
+		k++;
+		goto ret;
+		}
+	if (leftright) {
+		if (m2 > 0) {
+			mhi = lshift(mhi, m2);
+			if (mhi == NULL)
+				return (NULL);
+			}
+
+		/* Compute mlo -- check for special case
+		 * that d is a normalized power of 2.
+		 */
+
+		mlo = mhi;
+		if (spec_case) {
+			mhi = Balloc(mhi->k);
+			if (mhi == NULL)
+				return (NULL);
+			Bcopy(mhi, mlo);
+			mhi = lshift(mhi, 1);
+			if (mhi == NULL)
+				return (NULL);
+			}
+
+		for(i = 1;;i++) {
+			dig = quorem(b,S) + '0';
+			/* Do we yet have the shortest decimal string
+			 * that will round to d?
+			 */
+			j = cmp(b, mlo);
+			delta = diff(S, mhi);
+			if (delta == NULL)
+				return (NULL);
+			j1 = delta->sign ? 1 : cmp(b, delta);
+			Bfree(delta);
+#ifndef ROUND_BIASED
+			if (j1 == 0 && !mode && !(bits[0] & 1) && !rdir) {
+				if (dig == '9')
+					goto round_9_up;
+				if (j <= 0) {
+					if (b->wds > 1 || b->x[0])
+						inex = STRTOG_Inexlo;
+					}
+				else {
+					dig++;
+					inex = STRTOG_Inexhi;
+					}
+				*s++ = dig;
+				goto ret;
+				}
+#endif
+			if (j < 0 || (j == 0 && !mode
+#ifndef ROUND_BIASED
+							&& !(bits[0] & 1)
+#endif
+					)) {
+				if (rdir && (b->wds > 1 || b->x[0])) {
+					if (rdir == 2) {
+						inex = STRTOG_Inexlo;
+						goto accept;
+						}
+					while (cmp(S,mhi) > 0) {
+						*s++ = dig;
+						mhi1 = multadd(mhi, 10, 0);
+						if (mhi1 == NULL)
+							return (NULL);
+						if (mlo == mhi)
+							mlo = mhi1;
+						mhi = mhi1;
+						b = multadd(b, 10, 0);
+						if (b == NULL)
+							return (NULL);
+						dig = quorem(b,S) + '0';
+						}
+					if (dig++ == '9')
+						goto round_9_up;
+					inex = STRTOG_Inexhi;
+					goto accept;
+					}
+				if (j1 > 0) {
+					b = lshift(b, 1);
+					if (b == NULL)
+						return (NULL);
+					j1 = cmp(b, S);
+#ifdef ROUND_BIASED
+					if (j1 >= 0 /*)*/
+#else
+					if ((j1 > 0 || (j1 == 0 && dig & 1))
+#endif
+					&& dig++ == '9')
+						goto round_9_up;
+					inex = STRTOG_Inexhi;
+					}
+				if (b->wds > 1 || b->x[0])
+					inex = STRTOG_Inexlo;
+ accept:
+				*s++ = dig;
+				goto ret;
+				}
+			if (j1 > 0 && rdir != 2) {
+				if (dig == '9') { /* possible if i == 1 */
+ round_9_up:
+					*s++ = '9';
+					inex = STRTOG_Inexhi;
+					goto roundoff;
+					}
+				inex = STRTOG_Inexhi;
+				*s++ = dig + 1;
+				goto ret;
+				}
+			*s++ = dig;
+			if (i == ilim)
+				break;
+			b = multadd(b, 10, 0);
+			if (b == NULL)
+				return (NULL);
+			if (mlo == mhi) {
+				mlo = mhi = multadd(mhi, 10, 0);
+				if (mlo == NULL)
+					return (NULL);
+				}
+			else {
+				mlo = multadd(mlo, 10, 0);
+				if (mlo == NULL)
+					return (NULL);
+				mhi = multadd(mhi, 10, 0);
+				if (mhi == NULL)
+					return (NULL);
+				}
+			}
+		}
+	else
+		for(i = 1;; i++) {
+			*s++ = dig = quorem(b,S) + '0';
+			if (i >= ilim)
+				break;
+			b = multadd(b, 10, 0);
+			if (b == NULL)
+				return (NULL);
+			}
+
+	/* Round off last digit */
+
+	if (rdir) {
+		if (rdir == 2 || (b->wds <= 1 && !b->x[0]))
+			goto chopzeros;
+		goto roundoff;
+		}
+	b = lshift(b, 1);
+	if (b == NULL)
+		return (NULL);
+	j = cmp(b, S);
+#ifdef ROUND_BIASED
+	if (j >= 0)
+#else
+	if (j > 0 || (j == 0 && dig & 1))
+#endif
+		{
+ roundoff:
+		inex = STRTOG_Inexhi;
+		while(*--s == '9')
+			if (s == s0) {
+				k++;
+				*s++ = '1';
+				goto ret;
+				}
+		++*s++;
+		}
+	else {
+ chopzeros:
+		if (b->wds > 1 || b->x[0])
+			inex = STRTOG_Inexlo;
+		while(*--s == '0'){}
+		++s;
+		}
+ ret:
+	Bfree(S);
+	if (mhi) {
+		if (mlo && mlo != mhi)
+			Bfree(mlo);
+		Bfree(mhi);
+		}
+ ret1:
+	Bfree(b);
+	*s = 0;
+	*decpt = k + 1;
+	if (rve)
+		*rve = s;
+	*kindp |= inex;
+	return s0;
+	}
+DEF_STRONG(gdtoa);
diff --git a/newlib/libc/stdlib/gdtoa-gmisc.c b/newlib/libc/stdlib/gdtoa-gmisc.c
new file mode 100644
index 000000000..8270ef944
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-gmisc.c
@@ -0,0 +1,86 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include "gdtoaimp.h"
+
+ void
+#ifdef KR_headers
+rshift(b, k) Bigint *b; int k;
+#else
+rshift(Bigint *b, int k)
+#endif
+{
+	ULong *x, *x1, *xe, y;
+	int n;
+
+	x = x1 = b->x;
+	n = k >> kshift;
+	if (n < b->wds) {
+		xe = x + b->wds;
+		x += n;
+		if (k &= kmask) {
+			n = ULbits - k;
+			y = *x++ >> k;
+			while(x < xe) {
+				*x1++ = (y | (*x << n)) & ALL_ON;
+				y = *x++ >> k;
+				}
+			if ((*x1 = y) !=0)
+				x1++;
+			}
+		else
+			while(x < xe)
+				*x1++ = *x++;
+		}
+	if ((b->wds = x1 - b->x) == 0)
+		b->x[0] = 0;
+	}
+
+ int
+#ifdef KR_headers
+trailz(b) Bigint *b;
+#else
+trailz(Bigint *b)
+#endif
+{
+	ULong L, *x, *xe;
+	int n = 0;
+
+	x = b->x;
+	xe = x + b->wds;
+	for(n = 0; x < xe && !*x; x++)
+		n += ULbits;
+	if (x < xe) {
+		L = *x;
+		n += lo0bits(&L);
+		}
+	return n;
+	}
diff --git a/newlib/libc/stdlib/gdtoa-ldtoa.c b/newlib/libc/stdlib/gdtoa-ldtoa.c
new file mode 100644
index 000000000..7282e7a39
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-ldtoa.c
@@ -0,0 +1,124 @@
+/*	$OpenBSD: ldtoa.c,v 1.4 2016/03/09 16:28:47 deraadt Exp $	*/
+/*-
+ * Copyright (c) 2003 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <machine/ieee.h>
+#include <float.h>
+#include <stdint.h>
+#include <limits.h>
+#include <math.h>
+#include <stdlib.h>
+#include "gdtoaimp.h"
+
+#if (LDBL_MANT_DIG > DBL_MANT_DIG)
+
+/*
+ * ldtoa() is a wrapper for gdtoa() that makes it smell like dtoa(),
+ * except that the floating point argument is passed by reference.
+ * When dtoa() is passed a NaN or infinity, it sets expt to 9999.
+ * However, a long double could have a valid exponent of 9999, so we
+ * use INT_MAX in ldtoa() instead.
+ */
+char *
+__ldtoa(long double *ld, int mode, int ndigits, int *decpt, int *sign,
+    char **rve)
+{
+	FPI fpi = {
+		LDBL_MANT_DIG,			/* nbits */
+		LDBL_MIN_EXP - LDBL_MANT_DIG,	/* emin */
+		LDBL_MAX_EXP - LDBL_MANT_DIG,	/* emax */
+		FLT_ROUNDS,	       		/* rounding */
+#ifdef Sudden_Underflow	/* unused, but correct anyway */
+		1
+#else
+		0
+#endif
+	};
+	int be, kind;
+	char *ret;
+	struct ieee_ext *p = (struct ieee_ext *)ld;
+	uint32_t bits[(LDBL_MANT_DIG + 31) / 32];
+	void *vbits = bits;
+
+	/*
+	 * gdtoa doesn't know anything about the sign of the number, so
+	 * if the number is negative, we need to swap rounding modes of
+	 * 2 (upwards) and 3 (downwards).
+	 */
+	*sign = p->ext_sign;
+	fpi.rounding ^= (fpi.rounding >> 1) & p->ext_sign;
+
+	be = p->ext_exp - (LDBL_MAX_EXP - 1) - (LDBL_MANT_DIG - 1);
+	EXT_TO_ARRAY32(p, bits);
+
+	switch (fpclassify(*ld)) {
+	case FP_NORMAL:
+		kind = STRTOG_Normal;
+#ifdef EXT_IMPLICIT_NBIT
+		bits[LDBL_MANT_DIG / 32] |= 1 << ((LDBL_MANT_DIG - 1) % 32);
+#endif /* EXT_IMPLICIT_NBIT */
+		break;
+	case FP_ZERO:
+		kind = STRTOG_Zero;
+		break;
+	case FP_SUBNORMAL:
+		kind = STRTOG_Denormal;
+		be++;
+		break;
+	case FP_INFINITE:
+		kind = STRTOG_Infinite;
+		break;
+	case FP_NAN:
+		kind = STRTOG_NaN;
+		break;
+	default:
+		abort();
+	}
+
+	ret = gdtoa(&fpi, be, vbits, &kind, mode, ndigits, decpt, rve);
+	if (*decpt == -32768)
+		*decpt = INT_MAX;
+	return ret;
+}
+DEF_STRONG(__ldtoa);
+
+#else   /* (LDBL_MANT_DIG == DBL_MANT_DIG) */
+
+char *
+__ldtoa(long double *ld, int mode, int ndigits, int *decpt, int *sign,
+    char **rve)
+{
+	char *ret;
+
+	ret = dtoa((double)*ld, mode, ndigits, decpt, sign, rve);
+	if (*decpt == 9999)
+		*decpt = INT_MAX;
+	return ret;
+}
+DEF_STRONG(__ldtoa);
+
+#endif  /* (LDBL_MANT_DIG == DBL_MANT_DIG) */
diff --git a/newlib/libc/stdlib/gdtoa-misc.c b/newlib/libc/stdlib/gdtoa-misc.c
new file mode 100644
index 000000000..5d1e0ad69
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-misc.c
@@ -0,0 +1,912 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998, 1999 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include "gdtoaimp.h"
+
+ static Bigint *freelist[Kmax+1];
+#ifndef Omit_Private_Memory
+#ifndef PRIVATE_MEM
+#define PRIVATE_MEM 2304
+#endif
+#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double))
+static double private_mem[PRIVATE_mem], *pmem_next = private_mem;
+#endif
+
+#ifdef MULTIPLE_THREADS
+__LOCK_INIT(static, __dtoa_lock0);
+__LOCK_INIT(static, __dtoa_lock1);
+#endif
+
+ Bigint *
+Balloc
+#ifdef KR_headers
+	(k) int k;
+#else
+	(int k)
+#endif
+{
+	int x;
+	Bigint *rv;
+#ifndef Omit_Private_Memory
+	unsigned int len;
+#endif
+
+	ACQUIRE_DTOA_LOCK(0);
+	/* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */
+	/* but this case seems very unlikely. */
+	if (k <= Kmax && (rv = freelist[k]) !=0) {
+		freelist[k] = rv->next;
+		}
+	else {
+		x = 1 << k;
+#ifdef Omit_Private_Memory
+		rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong));
+		if (rv == NULL)
+			return (NULL);
+#else
+		len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1)
+			/sizeof(double);
+		if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem) {
+			rv = (Bigint*)pmem_next;
+			pmem_next += len;
+			}
+		else {
+			rv = (Bigint*)MALLOC(len*sizeof(double));
+			if (rv == NULL)
+				return (NULL);
+		}
+#endif
+		rv->k = k;
+		rv->maxwds = x;
+		}
+	FREE_DTOA_LOCK(0);
+	rv->sign = rv->wds = 0;
+	return rv;
+	}
+
+ void
+Bfree
+#ifdef KR_headers
+	(v) Bigint *v;
+#else
+	(Bigint *v)
+#endif
+{
+	if (v) {
+		if (v->k > Kmax)
+#ifdef FREE
+			FREE(v);
+#else
+			free(v);
+#endif
+		else {
+			ACQUIRE_DTOA_LOCK(0);
+			v->next = freelist[v->k];
+			freelist[v->k] = v;
+			FREE_DTOA_LOCK(0);
+			}
+		}
+	}
+
+ int
+lo0bits
+#ifdef KR_headers
+	(y) ULong *y;
+#else
+	(ULong *y)
+#endif
+{
+	int k;
+	ULong x = *y;
+
+	if (x & 7) {
+		if (x & 1)
+			return 0;
+		if (x & 2) {
+			*y = x >> 1;
+			return 1;
+			}
+		*y = x >> 2;
+		return 2;
+		}
+	k = 0;
+	if (!(x & 0xffff)) {
+		k = 16;
+		x >>= 16;
+		}
+	if (!(x & 0xff)) {
+		k += 8;
+		x >>= 8;
+		}
+	if (!(x & 0xf)) {
+		k += 4;
+		x >>= 4;
+		}
+	if (!(x & 0x3)) {
+		k += 2;
+		x >>= 2;
+		}
+	if (!(x & 1)) {
+		k++;
+		x >>= 1;
+		if (!x)
+			return 32;
+		}
+	*y = x;
+	return k;
+	}
+
+ Bigint *
+multadd
+#ifdef KR_headers
+	(b, m, a) Bigint *b; int m, a;
+#else
+	(Bigint *b, int m, int a)	/* multiply by m and add a */
+#endif
+{
+	int i, wds;
+#ifdef ULLong
+	ULong *x;
+	ULLong carry, y;
+#else
+	ULong carry, *x, y;
+#ifdef Pack_32
+	ULong xi, z;
+#endif
+#endif
+	Bigint *b1;
+
+	wds = b->wds;
+	x = b->x;
+	i = 0;
+	carry = a;
+	do {
+#ifdef ULLong
+		y = *x * (ULLong)m + carry;
+		carry = y >> 32;
+		*x++ = y & 0xffffffffUL;
+#else
+#ifdef Pack_32
+		xi = *x;
+		y = (xi & 0xffff) * m + carry;
+		z = (xi >> 16) * m + (y >> 16);
+		carry = z >> 16;
+		*x++ = (z << 16) + (y & 0xffff);
+#else
+		y = *x * m + carry;
+		carry = y >> 16;
+		*x++ = y & 0xffff;
+#endif
+#endif
+		}
+		while(++i < wds);
+	if (carry) {
+		if (wds >= b->maxwds) {
+			b1 = Balloc(b->k+1);
+			if (b1 == NULL)
+				return (NULL);
+			Bcopy(b1, b);
+			Bfree(b);
+			b = b1;
+			}
+		b->x[wds++] = carry;
+		b->wds = wds;
+		}
+	return b;
+	}
+
+ int
+hi0bits_D2A
+#ifdef KR_headers
+	(x) ULong x;
+#else
+	(ULong x)
+#endif
+{
+	int k = 0;
+
+	if (!(x & 0xffff0000)) {
+		k = 16;
+		x <<= 16;
+		}
+	if (!(x & 0xff000000)) {
+		k += 8;
+		x <<= 8;
+		}
+	if (!(x & 0xf0000000)) {
+		k += 4;
+		x <<= 4;
+		}
+	if (!(x & 0xc0000000)) {
+		k += 2;
+		x <<= 2;
+		}
+	if (!(x & 0x80000000)) {
+		k++;
+		if (!(x & 0x40000000))
+			return 32;
+		}
+	return k;
+	}
+
+ Bigint *
+i2b
+#ifdef KR_headers
+	(i) int i;
+#else
+	(int i)
+#endif
+{
+	Bigint *b;
+
+	b = Balloc(1);
+	if (b == NULL)
+		return (NULL);
+	b->x[0] = i;
+	b->wds = 1;
+	return b;
+	}
+
+ Bigint *
+mult
+#ifdef KR_headers
+	(a, b) Bigint *a, *b;
+#else
+	(Bigint *a, Bigint *b)
+#endif
+{
+	Bigint *c;
+	int k, wa, wb, wc;
+	ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0;
+	ULong y;
+#ifdef ULLong
+	ULLong carry, z;
+#else
+	ULong carry, z;
+#ifdef Pack_32
+	ULong z2;
+#endif
+#endif
+
+	if (a->wds < b->wds) {
+		c = a;
+		a = b;
+		b = c;
+		}
+	k = a->k;
+	wa = a->wds;
+	wb = b->wds;
+	wc = wa + wb;
+	if (wc > a->maxwds)
+		k++;
+	c = Balloc(k);
+	if (c == NULL)
+		return (NULL);
+	for(x = c->x, xa = x + wc; x < xa; x++)
+		*x = 0;
+	xa = a->x;
+	xae = xa + wa;
+	xb = b->x;
+	xbe = xb + wb;
+	xc0 = c->x;
+#ifdef ULLong
+	for(; xb < xbe; xc0++) {
+		if ( (y = *xb++) !=0) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			do {
+				z = *x++ * (ULLong)y + *xc + carry;
+				carry = z >> 32;
+				*xc++ = z & 0xffffffffUL;
+				}
+				while(x < xae);
+			*xc = carry;
+			}
+		}
+#else
+#ifdef Pack_32
+	for(; xb < xbe; xb++, xc0++) {
+		if ( (y = *xb & 0xffff) !=0) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			do {
+				z = (*x & 0xffff) * y + (*xc & 0xffff) + carry;
+				carry = z >> 16;
+				z2 = (*x++ >> 16) * y + (*xc >> 16) + carry;
+				carry = z2 >> 16;
+				Storeinc(xc, z2, z);
+				}
+				while(x < xae);
+			*xc = carry;
+			}
+		if ( (y = *xb >> 16) !=0) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			z2 = *xc;
+			do {
+				z = (*x & 0xffff) * y + (*xc >> 16) + carry;
+				carry = z >> 16;
+				Storeinc(xc, z, z2);
+				z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry;
+				carry = z2 >> 16;
+				}
+				while(x < xae);
+			*xc = z2;
+			}
+		}
+#else
+	for(; xb < xbe; xc0++) {
+		if ( (y = *xb++) !=0) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			do {
+				z = *x++ * y + *xc + carry;
+				carry = z >> 16;
+				*xc++ = z & 0xffff;
+				}
+				while(x < xae);
+			*xc = carry;
+			}
+		}
+#endif
+#endif
+	for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ;
+	c->wds = wc;
+	return c;
+	}
+
+ static Bigint *p5s;
+
+ Bigint *
+pow5mult
+#ifdef KR_headers
+	(b, k) Bigint *b; int k;
+#else
+	(Bigint *b, int k)
+#endif
+{
+	Bigint *b1, *p5, *p51;
+	int i;
+	static int p05[3] = { 5, 25, 125 };
+
+	if ( (i = k & 3) !=0) {
+		b = multadd(b, p05[i-1], 0);
+		if (b == NULL)
+			return (NULL);
+		}
+
+	if (!(k >>= 2))
+		return b;
+	if ((p5 = p5s) == 0) {
+		/* first time */
+#ifdef MULTIPLE_THREADS
+		ACQUIRE_DTOA_LOCK(1);
+		if (!(p5 = p5s)) {
+			p5 = p5s = i2b(625);
+			if (p5 == NULL)
+				return (NULL);
+			p5->next = 0;
+			}
+		FREE_DTOA_LOCK(1);
+#else
+		p5 = p5s = i2b(625);
+		if (p5 == NULL)
+			return (NULL);
+		p5->next = 0;
+#endif
+		}
+	for(;;) {
+		if (k & 1) {
+			b1 = mult(b, p5);
+			if (b1 == NULL)
+				return (NULL);
+			Bfree(b);
+			b = b1;
+			}
+		if (!(k >>= 1))
+			break;
+		if ((p51 = p5->next) == 0) {
+#ifdef MULTIPLE_THREADS
+			ACQUIRE_DTOA_LOCK(1);
+			if (!(p51 = p5->next)) {
+				p51 = p5->next = mult(p5,p5);
+				if (p51 == NULL)
+					return (NULL);
+				p51->next = 0;
+				}
+			FREE_DTOA_LOCK(1);
+#else
+			p51 = p5->next = mult(p5,p5);
+			if (p51 == NULL)
+				return (NULL);
+			p51->next = 0;
+#endif
+			}
+		p5 = p51;
+		}
+	return b;
+	}
+
+ Bigint *
+lshift
+#ifdef KR_headers
+	(b, k) Bigint *b; int k;
+#else
+	(Bigint *b, int k)
+#endif
+{
+	int i, k1, n, n1;
+	Bigint *b1;
+	ULong *x, *x1, *xe, z;
+
+	n = k >> kshift;
+	k1 = b->k;
+	n1 = n + b->wds + 1;
+	for(i = b->maxwds; n1 > i; i <<= 1)
+		k1++;
+	b1 = Balloc(k1);
+	if (b1 == NULL)
+		return (NULL);
+	x1 = b1->x;
+	for(i = 0; i < n; i++)
+		*x1++ = 0;
+	x = b->x;
+	xe = x + b->wds;
+	if (k &= kmask) {
+#ifdef Pack_32
+		k1 = 32 - k;
+		z = 0;
+		do {
+			*x1++ = *x << k | z;
+			z = *x++ >> k1;
+			}
+			while(x < xe);
+		if ((*x1 = z) !=0)
+			++n1;
+#else
+		k1 = 16 - k;
+		z = 0;
+		do {
+			*x1++ = *x << k  & 0xffff | z;
+			z = *x++ >> k1;
+			}
+			while(x < xe);
+		if (*x1 = z)
+			++n1;
+#endif
+		}
+	else do
+		*x1++ = *x++;
+		while(x < xe);
+	b1->wds = n1 - 1;
+	Bfree(b);
+	return b1;
+	}
+
+ int
+cmp
+#ifdef KR_headers
+	(a, b) Bigint *a, *b;
+#else
+	(Bigint *a, Bigint *b)
+#endif
+{
+	ULong *xa, *xa0, *xb, *xb0;
+	int i, j;
+
+	i = a->wds;
+	j = b->wds;
+#ifdef DEBUG
+	if (i > 1 && !a->x[i-1])
+		Bug("cmp called with a->x[a->wds-1] == 0");
+	if (j > 1 && !b->x[j-1])
+		Bug("cmp called with b->x[b->wds-1] == 0");
+#endif
+	if (i -= j)
+		return i;
+	xa0 = a->x;
+	xa = xa0 + j;
+	xb0 = b->x;
+	xb = xb0 + j;
+	for(;;) {
+		if (*--xa != *--xb)
+			return *xa < *xb ? -1 : 1;
+		if (xa <= xa0)
+			break;
+		}
+	return 0;
+	}
+
+ Bigint *
+diff
+#ifdef KR_headers
+	(a, b) Bigint *a, *b;
+#else
+	(Bigint *a, Bigint *b)
+#endif
+{
+	Bigint *c;
+	int i, wa, wb;
+	ULong *xa, *xae, *xb, *xbe, *xc;
+#ifdef ULLong
+	ULLong borrow, y;
+#else
+	ULong borrow, y;
+#ifdef Pack_32
+	ULong z;
+#endif
+#endif
+
+	i = cmp(a,b);
+	if (!i) {
+		c = Balloc(0);
+		if (c == NULL)
+			return (NULL);
+		c->wds = 1;
+		c->x[0] = 0;
+		return c;
+		}
+	if (i < 0) {
+		c = a;
+		a = b;
+		b = c;
+		i = 1;
+		}
+	else
+		i = 0;
+	c = Balloc(a->k);
+	if (c == NULL)
+		return (NULL);
+	c->sign = i;
+	wa = a->wds;
+	xa = a->x;
+	xae = xa + wa;
+	wb = b->wds;
+	xb = b->x;
+	xbe = xb + wb;
+	xc = c->x;
+	borrow = 0;
+#ifdef ULLong
+	do {
+		y = (ULLong)*xa++ - *xb++ - borrow;
+		borrow = y >> 32 & 1UL;
+		*xc++ = y & 0xffffffffUL;
+		}
+		while(xb < xbe);
+	while(xa < xae) {
+		y = *xa++ - borrow;
+		borrow = y >> 32 & 1UL;
+		*xc++ = y & 0xffffffffUL;
+		}
+#else
+#ifdef Pack_32
+	do {
+		y = (*xa & 0xffff) - (*xb & 0xffff) - borrow;
+		borrow = (y & 0x10000) >> 16;
+		z = (*xa++ >> 16) - (*xb++ >> 16) - borrow;
+		borrow = (z & 0x10000) >> 16;
+		Storeinc(xc, z, y);
+		}
+		while(xb < xbe);
+	while(xa < xae) {
+		y = (*xa & 0xffff) - borrow;
+		borrow = (y & 0x10000) >> 16;
+		z = (*xa++ >> 16) - borrow;
+		borrow = (z & 0x10000) >> 16;
+		Storeinc(xc, z, y);
+		}
+#else
+	do {
+		y = *xa++ - *xb++ - borrow;
+		borrow = (y & 0x10000) >> 16;
+		*xc++ = y & 0xffff;
+		}
+		while(xb < xbe);
+	while(xa < xae) {
+		y = *xa++ - borrow;
+		borrow = (y & 0x10000) >> 16;
+		*xc++ = y & 0xffff;
+		}
+#endif
+#endif
+	while(!*--xc)
+		wa--;
+	c->wds = wa;
+	return c;
+	}
+
+ double
+b2d
+#ifdef KR_headers
+	(a, e) Bigint *a; int *e;
+#else
+	(Bigint *a, int *e)
+#endif
+{
+	ULong *xa, *xa0, w, y, z;
+	int k;
+	U d;
+#ifdef VAX
+	ULong d0, d1;
+#else
+#define d0 word0(&d)
+#define d1 word1(&d)
+#endif
+
+	xa0 = a->x;
+	xa = xa0 + a->wds;
+	y = *--xa;
+#ifdef DEBUG
+	if (!y) Bug("zero y in b2d");
+#endif
+	k = hi0bits(y);
+	*e = 32 - k;
+#ifdef Pack_32
+	if (k < Ebits) {
+		d0 = Exp_1 | y >> (Ebits - k);
+		w = xa > xa0 ? *--xa : 0;
+		d1 = y << ((32-Ebits) + k) | w >> (Ebits - k);
+		goto ret_d;
+		}
+	z = xa > xa0 ? *--xa : 0;
+	if (k -= Ebits) {
+		d0 = Exp_1 | y << k | z >> (32 - k);
+		y = xa > xa0 ? *--xa : 0;
+		d1 = z << k | y >> (32 - k);
+		}
+	else {
+		d0 = Exp_1 | y;
+		d1 = z;
+		}
+#else
+	if (k < Ebits + 16) {
+		z = xa > xa0 ? *--xa : 0;
+		d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k;
+		w = xa > xa0 ? *--xa : 0;
+		y = xa > xa0 ? *--xa : 0;
+		d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k;
+		goto ret_d;
+		}
+	z = xa > xa0 ? *--xa : 0;
+	w = xa > xa0 ? *--xa : 0;
+	k -= Ebits + 16;
+	d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k;
+	y = xa > xa0 ? *--xa : 0;
+	d1 = w << k + 16 | y << k;
+#endif
+ ret_d:
+#ifdef VAX
+	word0(&d) = d0 >> 16 | d0 << 16;
+	word1(&d) = d1 >> 16 | d1 << 16;
+#endif
+	return dval(&d);
+	}
+#undef d0
+#undef d1
+
+ Bigint *
+d2b
+#ifdef KR_headers
+	(dd, e, bits) double dd; int *e, *bits;
+#else
+	(double dd, int *e, int *bits)
+#endif
+{
+	Bigint *b;
+	U d;
+#ifndef Sudden_Underflow
+	int i;
+#endif
+	int de, k;
+	ULong *x, y, z;
+#ifdef VAX
+	ULong d0, d1;
+#else
+#define d0 word0(&d)
+#define d1 word1(&d)
+#endif
+	d.d = dd;
+#ifdef VAX
+	d0 = word0(&d) >> 16 | word0(&d) << 16;
+	d1 = word1(&d) >> 16 | word1(&d) << 16;
+#endif
+
+#ifdef Pack_32
+	b = Balloc(1);
+#else
+	b = Balloc(2);
+#endif
+	if (b == NULL)
+		return (NULL);
+	x = b->x;
+
+	z = d0 & Frac_mask;
+	d0 &= 0x7fffffff;	/* clear sign bit, which we ignore */
+#ifdef Sudden_Underflow
+	de = (int)(d0 >> Exp_shift);
+#ifndef IBM
+	z |= Exp_msk11;
+#endif
+#else
+	if ( (de = (int)(d0 >> Exp_shift)) !=0)
+		z |= Exp_msk1;
+#endif
+#ifdef Pack_32
+	if ( (y = d1) !=0) {
+		if ( (k = lo0bits(&y)) !=0) {
+			x[0] = y | z << (32 - k);
+			z >>= k;
+			}
+		else
+			x[0] = y;
+#ifndef Sudden_Underflow
+		i =
+#endif
+		     b->wds = (x[1] = z) !=0 ? 2 : 1;
+		}
+	else {
+		k = lo0bits(&z);
+		x[0] = z;
+#ifndef Sudden_Underflow
+		i =
+#endif
+		    b->wds = 1;
+		k += 32;
+		}
+#else
+	if ( (y = d1) !=0) {
+		if ( (k = lo0bits(&y)) !=0)
+			if (k >= 16) {
+				x[0] = y | z << 32 - k & 0xffff;
+				x[1] = z >> k - 16 & 0xffff;
+				x[2] = z >> k;
+				i = 2;
+				}
+			else {
+				x[0] = y & 0xffff;
+				x[1] = y >> 16 | z << 16 - k & 0xffff;
+				x[2] = z >> k & 0xffff;
+				x[3] = z >> k+16;
+				i = 3;
+				}
+		else {
+			x[0] = y & 0xffff;
+			x[1] = y >> 16;
+			x[2] = z & 0xffff;
+			x[3] = z >> 16;
+			i = 3;
+			}
+		}
+	else {
+#ifdef DEBUG
+		if (!z)
+			Bug("Zero passed to d2b");
+#endif
+		k = lo0bits(&z);
+		if (k >= 16) {
+			x[0] = z;
+			i = 0;
+			}
+		else {
+			x[0] = z & 0xffff;
+			x[1] = z >> 16;
+			i = 1;
+			}
+		k += 32;
+		}
+	while(!x[i])
+		--i;
+	b->wds = i + 1;
+#endif
+#ifndef Sudden_Underflow
+	if (de) {
+#endif
+#ifdef IBM
+		*e = (de - Bias - (P-1) << 2) + k;
+		*bits = 4*P + 8 - k - hi0bits(word0(&d) & Frac_mask);
+#else
+		*e = de - Bias - (P-1) + k;
+		*bits = P - k;
+#endif
+#ifndef Sudden_Underflow
+		}
+	else {
+		*e = de - Bias - (P-1) + 1 + k;
+#ifdef Pack_32
+		*bits = 32*i - hi0bits(x[i-1]);
+#else
+		*bits = (i+2)*16 - hi0bits(x[i]);
+#endif
+		}
+#endif
+	return b;
+	}
+#undef d0
+#undef d1
+
+ CONST double
+#ifdef IEEE_Arith
+bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };
+CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, 1e-256
+		};
+#else
+#ifdef IBM
+bigtens[] = { 1e16, 1e32, 1e64 };
+CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 };
+#else
+bigtens[] = { 1e16, 1e32 };
+CONST double tinytens[] = { 1e-16, 1e-32 };
+#endif
+#endif
+
+ CONST double
+tens[] = {
+		1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+		1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+		1e20, 1e21, 1e22
+#ifdef VAX
+		, 1e23, 1e24
+#endif
+		};
+
+#ifdef NO_STRING_H
+
+ char *
+#ifdef KR_headers
+strcp_D2A(a, b) char *a; char *b;
+#else
+strcp_D2A(char *a, CONST char *b)
+#endif
+{
+	while((*a = *b++))
+		a++;
+	return a;
+	}
+
+ Char *
+#ifdef KR_headers
+memcpy_D2A(a, b, len) Char *a; Char *b; size_t len;
+#else
+memcpy_D2A(void *a1, void *b1, size_t len)
+#endif
+{
+	char *a = (char*)a1, *ae = a + len;
+	char *b = (char*)b1, *a0 = a;
+	while(a < ae)
+		*a++ = *b++;
+	return a0;
+	}
+
+#endif /* NO_STRING_H */
diff --git a/newlib/libc/stdlib/gdtoa.h b/newlib/libc/stdlib/gdtoa.h
index 07506aac1..4f26d8857 100644
--- a/newlib/libc/stdlib/gdtoa.h
+++ b/newlib/libc/stdlib/gdtoa.h
@@ -32,25 +32,61 @@ THIS SOFTWARE.
 #ifndef GDTOA_H_INCLUDED
 #define GDTOA_H_INCLUDED
 
+#include "arith.h"
+#include <stddef.h> /* for size_t */
+
+#define PROTO_NORMAL(x)
+#define __BEGIN_HIDDEN_DECLS
+#define __END_HIDDEN_DECLS
+#define DEF_STRONG(x)
+
+#ifndef Long
+#define Long int
+#endif
+#ifndef ULong
+typedef unsigned Long ULong;
+#endif
+#ifndef UShort
+typedef unsigned short UShort;
+#endif
+
+#ifndef ANSI
+#ifdef KR_headers
+#define ANSI(x) ()
+#define Void /*nothing*/
+#else
+#define ANSI(x) x
+#define Void void
+#endif
+#endif /* ANSI */
+
+#ifndef CONST
+#ifdef KR_headers
+#define CONST /* blank */
+#else
+#define CONST const
+#endif
+#endif /* CONST */
 
  enum {	/* return values from strtodg */
-	STRTOG_Zero	= 0,
-	STRTOG_Normal	= 1,
-	STRTOG_Denormal	= 2,
-	STRTOG_Infinite	= 3,
-	STRTOG_NaN	= 4,
-	STRTOG_NaNbits	= 5,
-	STRTOG_NoNumber	= 6,
-	STRTOG_Retmask	= 7,
+	STRTOG_Zero	= 0x000,
+	STRTOG_Normal	= 0x001,
+	STRTOG_Denormal	= 0x002,
+	STRTOG_Infinite	= 0x003,
+	STRTOG_NaN	= 0x004,
+	STRTOG_NaNbits	= 0x005,
+	STRTOG_NoNumber	= 0x006,
+	STRTOG_NoMemory = 0x007,
+	STRTOG_Retmask	= 0x00f,
 
 	/* The following may be or-ed into one of the above values. */
 
-	STRTOG_Neg	= 0x08,
-	STRTOG_Inexlo	= 0x10,
-	STRTOG_Inexhi	= 0x20,
-	STRTOG_Inexact	= 0x30,
-	STRTOG_Underflow= 0x40,
-	STRTOG_Overflow	= 0x80
+	STRTOG_Inexlo	= 0x010, /* returned result rounded toward zero */
+	STRTOG_Inexhi	= 0x020, /* returned result rounded away from zero */
+	STRTOG_Inexact	= 0x030,
+	STRTOG_Underflow= 0x040,
+	STRTOG_Overflow	= 0x080,
+	STRTOG_Neg	= 0x100 /* does not affect STRTOG_Inexlo or STRTOG_Inexhi */
 	};
 
  typedef struct
@@ -69,6 +105,70 @@ enum {	/* FPI.rounding values: same as FLT_ROUNDS */
 	FPI_Round_down = 3
 	};
 
-#endif /* GDTOA_H_INCLUDED */
-
 typedef unsigned short __UShort;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char* __dtoa  ANSI((double d, int mode, int ndigits, int *decpt,
+			int *sign, char **rve));
+extern char* __gdtoa ANSI((FPI *fpi, int be, ULong *bits, int *kindp,
+			int mode, int ndigits, int *decpt, char **rve));
+extern void __freedtoa ANSI((char*));
+extern float  strtof ANSI((CONST char *, char **));
+extern double strtod ANSI((CONST char *, char **));
+extern int __strtodg ANSI((CONST char*, char**, FPI*, Long*, ULong*));
+char	*__hdtoa(double, const char *, int, int *, int *, char **);
+char	*__hldtoa(long double, const char *, int, int *, int *, char **);
+char	*__ldtoa(long double *, int, int, int *, int *, char **);
+
+PROTO_NORMAL(__dtoa);
+PROTO_NORMAL(__gdtoa);
+PROTO_NORMAL(__freedtoa);
+PROTO_NORMAL(__hdtoa);
+PROTO_NORMAL(__hldtoa);
+PROTO_NORMAL(__ldtoa);
+
+__BEGIN_HIDDEN_DECLS
+extern char*	__g_ddfmt  ANSI((char*, double*, int, size_t));
+extern char*	__g_dfmt   ANSI((char*, double*, int, size_t));
+extern char*	__g_ffmt   ANSI((char*, float*,  int, size_t));
+extern char*	__g_Qfmt   ANSI((char*, void*,   int, size_t));
+extern char*	__g_xfmt   ANSI((char*, void*,   int, size_t));
+extern char*	__g_xLfmt  ANSI((char*, void*,   int, size_t));
+
+extern int	__strtoId  ANSI((CONST char*, char**, double*, double*));
+extern int	__strtoIdd ANSI((CONST char*, char**, double*, double*));
+extern int	__strtoIf  ANSI((CONST char*, char**, float*, float*));
+extern int	__strtoIQ  ANSI((CONST char*, char**, void*, void*));
+extern int	__strtoIx  ANSI((CONST char*, char**, void*, void*));
+extern int	__strtoIxL ANSI((CONST char*, char**, void*, void*));
+extern int	__strtord  ANSI((CONST char*, char**, int, double*));
+extern int	__strtordd ANSI((CONST char*, char**, int, double*));
+extern int	__strtorf  ANSI((CONST char*, char**, int, float*));
+extern int	__strtorQ  ANSI((CONST char*, char**, int, void*));
+extern int	__strtorx  ANSI((CONST char*, char**, int, void*));
+extern int	__strtorxL ANSI((CONST char*, char**, int, void*));
+#if 1
+extern int	__strtodI  ANSI((CONST char*, char**, double*));
+extern int	__strtopd  ANSI((CONST char*, char**, double*));
+extern int	__strtopdd ANSI((CONST char*, char**, double*));
+extern int	__strtopf  ANSI((CONST char*, char**, float*));
+extern int	__strtopQ  ANSI((CONST char*, char**, void*));
+extern int	__strtopx  ANSI((CONST char*, char**, void*));
+extern int	__strtopxL ANSI((CONST char*, char**, void*));
+#else
+#define __strtopd(s,se,x) strtord(s,se,1,x)
+#define __strtopdd(s,se,x) strtordd(s,se,1,x)
+#define __strtopf(s,se,x) strtorf(s,se,1,x)
+#define __strtopQ(s,se,x) strtorQ(s,se,1,x)
+#define __strtopx(s,se,x) strtorx(s,se,1,x)
+#define __strtopxL(s,se,x) strtorxL(s,se,1,x)
+#endif
+__END_HIDDEN_DECLS
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* GDTOA_H_INCLUDED */
diff --git a/newlib/libc/stdlib/gdtoaimp.h b/newlib/libc/stdlib/gdtoaimp.h
new file mode 100644
index 000000000..bf9770955
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoaimp.h
@@ -0,0 +1,672 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998-2000 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* This is a variation on dtoa.c that converts arbitary binary
+   floating-point formats to and from decimal notation.  It uses
+   double-precision arithmetic internally, so there are still
+   various #ifdefs that adapt the calculations to the native
+   double-precision arithmetic (any of IEEE, VAX D_floating,
+   or IBM mainframe arithmetic).
+
+   Please send bug reports to David M. Gay (dmg at acm dot org,
+   with " at " changed at "@" and " dot " changed to ".").
+ */
+
+/* On a machine with IEEE extended-precision registers, it is
+ * necessary to specify double-precision (53-bit) rounding precision
+ * before invoking strtod or dtoa.  If the machine uses (the equivalent
+ * of) Intel 80x87 arithmetic, the call
+ *	_control87(PC_53, MCW_PC);
+ * does this with many compilers.  Whether this or another call is
+ * appropriate depends on the compiler; for this to work, it may be
+ * necessary to #include "float.h" or another system-dependent header
+ * file.
+ */
+
+/* strtod for IEEE-, VAX-, and IBM-arithmetic machines.
+ *
+ * This strtod returns a nearest machine number to the input decimal
+ * string (or sets errno to ERANGE).  With IEEE arithmetic, ties are
+ * broken by the IEEE round-even rule.  Otherwise ties are broken by
+ * biased rounding (add half and chop).
+ *
+ * Inspired loosely by William D. Clinger's paper "How to Read Floating
+ * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ *
+ *	1. We only require IEEE, IBM, or VAX double-precision
+ *		arithmetic (not IEEE double-extended).
+ *	2. We get by with floating-point arithmetic in a case that
+ *		Clinger missed -- when we're computing d * 10^n
+ *		for a small integer d and the integer n is not too
+ *		much larger than 22 (the maximum integer k for which
+ *		we can represent 10^k exactly), we may be able to
+ *		compute (d*10^k) * 10^(e-k) with just one roundoff.
+ *	3. Rather than a bit-at-a-time adjustment of the binary
+ *		result in the hard case, we use floating-point
+ *		arithmetic to determine the adjustment to within
+ *		one bit; only in really hard cases do we need to
+ *		compute a second residual.
+ *	4. Because of 3., we don't need a large table of powers of 10
+ *		for ten-to-e (just some small tables, e.g. of 10^k
+ *		for 0 <= k <= 22).
+ */
+
+/*
+ * #define IEEE_8087 for IEEE-arithmetic machines where the least
+ *	significant byte has the lowest address.
+ * #define IEEE_MC68k for IEEE-arithmetic machines where the most
+ *	significant byte has the lowest address.
+ * #define Long int on machines with 32-bit ints and 64-bit longs.
+ * #define Sudden_Underflow for IEEE-format machines without gradual
+ *	underflow (i.e., that flush to zero on underflow).
+ * #define IBM for IBM mainframe-style floating-point arithmetic.
+ * #define VAX for VAX-style floating-point arithmetic (D_floating).
+ * #define No_leftright to omit left-right logic in fast floating-point
+ *	computation of dtoa and gdtoa.  This will cause modes 4 and 5 to be
+ *	treated the same as modes 2 and 3 for some inputs.
+ * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3.
+ * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines
+ *	that use extended-precision instructions to compute rounded
+ *	products and quotients) with IBM.
+ * #define ROUND_BIASED for IEEE-format with biased rounding and arithmetic
+ *	that rounds toward +Infinity.
+ * #define ROUND_BIASED_without_Round_Up for IEEE-format with biased
+ *	rounding when the underlying floating-point arithmetic uses
+ *	unbiased rounding.  This prevent using ordinary floating-point
+ *	arithmetic when the result could be computed with one rounding error.
+ * #define Inaccurate_Divide for IEEE-format with correctly rounded
+ *	products but inaccurate quotients, e.g., for Intel i860.
+ * #define NO_LONG_LONG on machines that do not have a "long long"
+ *	integer type (of >= 64 bits).  On such machines, you can
+ *	#define Just_16 to store 16 bits per 32-bit Long when doing
+ *	high-precision integer arithmetic.  Whether this speeds things
+ *	up or slows things down depends on the machine and the number
+ *	being converted.  If long long is available and the name is
+ *	something other than "long long", #define Llong to be the name,
+ *	and if "unsigned Llong" does not work as an unsigned version of
+ *	Llong, #define #ULLong to be the corresponding unsigned type.
+ * #define KR_headers for old-style C function headers.
+ * #define Bad_float_h if your system lacks a float.h or if it does not
+ *	define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP,
+ *	FLT_RADIX, FLT_ROUNDS, and DBL_MAX.
+ * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n)
+ *	if memory is available and otherwise does something you deem
+ *	appropriate.  If MALLOC is undefined, malloc will be invoked
+ *	directly -- and assumed always to succeed.  Similarly, if you
+ *	want something other than the system's free() to be called to
+ *	recycle memory acquired from MALLOC, #define FREE to be the
+ *	name of the alternate routine.  (FREE or free is only called in
+ *	pathological cases, e.g., in a gdtoa call after a gdtoa return in
+ *	mode 3 with thousands of digits requested.)
+ * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making
+ *	memory allocations from a private pool of memory when possible.
+ *	When used, the private pool is PRIVATE_MEM bytes long:  2304 bytes,
+ *	unless #defined to be a different length.  This default length
+ *	suffices to get rid of MALLOC calls except for unusual cases,
+ *	such as decimal-to-binary conversion of a very long string of
+ *	digits.  When converting IEEE double precision values, the
+ *	longest string gdtoa can return is about 751 bytes long.  For
+ *	conversions by strtod of strings of 800 digits and all gdtoa
+ *	conversions of IEEE doubles in single-threaded executions with
+ *	8-byte pointers, PRIVATE_MEM >= 7400 appears to suffice; with
+ *	4-byte pointers, PRIVATE_MEM >= 7112 appears adequate.
+ * #define NO_INFNAN_CHECK if you do not wish to have INFNAN_CHECK
+ *	#defined automatically on IEEE systems.  On such systems,
+ *	when INFNAN_CHECK is #defined, strtod checks
+ *	for Infinity and NaN (case insensitively).
+ *	When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined,
+ *	strtodg also accepts (case insensitively) strings of the form
+ *	NaN(x), where x is a string of hexadecimal digits (optionally
+ *	preceded by 0x or 0X) and spaces; if there is only one string
+ *	of hexadecimal digits, it is taken for the fraction bits of the
+ *	resulting NaN; if there are two or more strings of hexadecimal
+ *	digits, each string is assigned to the next available sequence
+ *	of 32-bit words of fractions bits (starting with the most
+ *	significant), right-aligned in each sequence.
+ *	Unless GDTOA_NON_PEDANTIC_NANCHECK is #defined, input "NaN(...)"
+ *	is consumed even when ... has the wrong form (in which case the
+ *	"(...)" is consumed but ignored).
+ * #define MULTIPLE_THREADS if the system offers preemptively scheduled
+ *	multiple threads.  In this case, you must provide (or suitably
+ *	#define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed
+ *	by FREE_DTOA_LOCK(n) for n = 0 or 1.  (The second lock, accessed
+ *	in pow5mult, ensures lazy evaluation of only one copy of high
+ *	powers of 5; omitting this lock would introduce a small
+ *	probability of wasting memory, but would otherwise be harmless.)
+ *	You must also invoke freedtoa(s) to free the value s returned by
+ *	dtoa.  You may do so whether or not MULTIPLE_THREADS is #defined.
+ * #define IMPRECISE_INEXACT if you do not care about the setting of
+ *	the STRTOG_Inexact bits in the special case of doing IEEE double
+ *	precision conversions (which could also be done by the strtod in
+ *	dtoa.c).
+ * #define NO_HEX_FP to disable recognition of C9x's hexadecimal
+ *	floating-point constants.
+ * #define -DNO_ERRNO to suppress setting errno (in strtod.c and
+ *	strtodg.c).
+ * #define NO_STRING_H to use private versions of memcpy.
+ *	On some K&R systems, it may also be necessary to
+ *	#define DECLARE_SIZE_T in this case.
+ * #define USE_LOCALE to use the current locale's decimal_point value.
+ */
+
+#ifndef GDTOAIMP_H_INCLUDED
+#define GDTOAIMP_H_INCLUDED
+#include "gdtoa.h"
+#if 0
+#include "gd_qnan.h"
+#endif
+#ifdef Honor_FLT_ROUNDS
+#include <fenv.h>
+#endif
+
+#ifdef DEBUG
+#include "stdio.h"
+#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);}
+#endif
+
+#include "stdlib.h"
+#include "string.h"
+
+#ifdef KR_headers
+#define Char char
+#else
+#define Char void
+#endif
+
+#ifdef MALLOC
+extern Char *MALLOC ANSI((size_t));
+#else
+#define MALLOC(x) _malloc_r(_REENT, x)
+#endif
+#define FREE(x) _free_r(_REENT, x)
+
+#undef IEEE_Arith
+#undef Avoid_Underflow
+#ifdef IEEE_MC68k
+#define IEEE_Arith
+#endif
+#ifdef IEEE_8087
+#define IEEE_Arith
+#endif
+
+#include "errno.h"
+#ifdef Bad_float_h
+
+#ifdef IEEE_Arith
+#define DBL_DIG 15
+#define DBL_MAX_10_EXP 308
+#define DBL_MAX_EXP 1024
+#define FLT_RADIX 2
+#define DBL_MAX 1.7976931348623157e+308
+#endif
+
+#ifdef IBM
+#define DBL_DIG 16
+#define DBL_MAX_10_EXP 75
+#define DBL_MAX_EXP 63
+#define FLT_RADIX 16
+#define DBL_MAX 7.2370055773322621e+75
+#endif
+
+#ifdef VAX
+#define DBL_DIG 16
+#define DBL_MAX_10_EXP 38
+#define DBL_MAX_EXP 127
+#define FLT_RADIX 2
+#define DBL_MAX 1.7014118346046923e+38
+#define n_bigtens 2
+#endif
+
+#ifndef LONG_MAX
+#define LONG_MAX 2147483647
+#endif
+
+#else /* ifndef Bad_float_h */
+#include "float.h"
+#endif /* Bad_float_h */
+
+#ifdef IEEE_Arith
+#define Scale_Bit 0x10
+#define n_bigtens 5
+#endif
+
+#ifdef IBM
+#define n_bigtens 3
+#endif
+
+#ifdef VAX
+#define n_bigtens 2
+#endif
+
+#ifndef __MATH_H__
+#include "math.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1
+Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined.
+#endif
+
+typedef union { double d; ULong L[2]; } U;
+
+#ifdef IEEE_8087
+#define word0(x) (x)->L[1]
+#define word1(x) (x)->L[0]
+#else
+#define word0(x) (x)->L[0]
+#define word1(x) (x)->L[1]
+#endif
+#define dval(x) (x)->d
+
+/* The following definition of Storeinc is appropriate for MIPS processors.
+ * An alternative that might be better on some machines is
+ * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff)
+ */
+#if defined(IEEE_8087) + defined(VAX)
+#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \
+((unsigned short *)a)[0] = (unsigned short)c, a++)
+#else
+#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \
+((unsigned short *)a)[1] = (unsigned short)c, a++)
+#endif
+
+/* #define P DBL_MANT_DIG */
+/* Ten_pmax = floor(P*log(2)/log(5)) */
+/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */
+/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */
+/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */
+
+#ifdef IEEE_Arith
+#define Exp_shift  20
+#define Exp_shift1 20
+#define Exp_msk1    0x100000
+#define Exp_msk11   0x100000
+#define Exp_mask  0x7ff00000
+#define P 53
+#define Bias 1023
+#define Emin (-1022)
+#define Exp_1  0x3ff00000
+#define Exp_11 0x3ff00000
+#define Ebits 11
+#define Frac_mask  0xfffff
+#define Frac_mask1 0xfffff
+#define Ten_pmax 22
+#define Bletch 0x10
+#define Bndry_mask  0xfffff
+#define Bndry_mask1 0xfffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 1
+#define Tiny0 0
+#define Tiny1 1
+#define Quick_max 14
+#define Int_max 14
+
+#ifndef Flt_Rounds
+#ifdef FLT_ROUNDS
+#define Flt_Rounds FLT_ROUNDS
+#else
+#define Flt_Rounds 1
+#endif
+#endif /*Flt_Rounds*/
+
+#else /* ifndef IEEE_Arith */
+#undef  Sudden_Underflow
+#define Sudden_Underflow
+#ifdef IBM
+#undef Flt_Rounds
+#define Flt_Rounds 0
+#define Exp_shift  24
+#define Exp_shift1 24
+#define Exp_msk1   0x1000000
+#define Exp_msk11  0x1000000
+#define Exp_mask  0x7f000000
+#define P 14
+#define Bias 65
+#define Exp_1  0x41000000
+#define Exp_11 0x41000000
+#define Ebits 8	/* exponent has 7 bits, but 8 is the right value in b2d */
+#define Frac_mask  0xffffff
+#define Frac_mask1 0xffffff
+#define Bletch 4
+#define Ten_pmax 22
+#define Bndry_mask  0xefffff
+#define Bndry_mask1 0xffffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 4
+#define Tiny0 0x100000
+#define Tiny1 0
+#define Quick_max 14
+#define Int_max 15
+#else /* VAX */
+#undef Flt_Rounds
+#define Flt_Rounds 1
+#define Exp_shift  23
+#define Exp_shift1 7
+#define Exp_msk1    0x80
+#define Exp_msk11   0x800000
+#define Exp_mask  0x7f80
+#define P 56
+#define Bias 129
+#define Emin (-127)
+#define Exp_1  0x40800000
+#define Exp_11 0x4080
+#define Ebits 8
+#define Frac_mask  0x7fffff
+#define Frac_mask1 0xffff007f
+#define Ten_pmax 24
+#define Bletch 2
+#define Bndry_mask  0xffff007f
+#define Bndry_mask1 0xffff007f
+#define LSB 0x10000
+#define Sign_bit 0x8000
+#define Log2P 1
+#define Tiny0 0x80
+#define Tiny1 0
+#define Quick_max 15
+#define Int_max 15
+#endif /* IBM, VAX */
+#endif /* IEEE_Arith */
+
+#ifndef IEEE_Arith
+#define ROUND_BIASED
+#else
+#ifdef ROUND_BIASED_without_Round_Up
+#undef  ROUND_BIASED
+#define ROUND_BIASED
+#endif
+#endif
+
+#ifdef RND_PRODQUOT
+#define rounded_product(a,b) a = rnd_prod(a, b)
+#define rounded_quotient(a,b) a = rnd_quot(a, b)
+#ifdef KR_headers
+extern double rnd_prod(), rnd_quot();
+#else
+extern double rnd_prod(double, double), rnd_quot(double, double);
+#endif
+#else
+#define rounded_product(a,b) a *= b
+#define rounded_quotient(a,b) a /= b
+#endif
+
+#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1))
+#define Big1 0xffffffff
+
+#undef  Pack_16
+#ifndef Pack_32
+#define Pack_32
+#endif
+
+#ifdef NO_LONG_LONG
+#undef ULLong
+#ifdef Just_16
+#undef Pack_32
+#define Pack_16
+/* When Pack_32 is not defined, we store 16 bits per 32-bit Long.
+ * This makes some inner loops simpler and sometimes saves work
+ * during multiplications, but it often seems to make things slightly
+ * slower.  Hence the default is now to store 32 bits per Long.
+ */
+#endif
+#else	/* long long available */
+#ifndef Llong
+#define Llong long long
+#endif
+#ifndef ULLong
+#define ULLong unsigned Llong
+#endif
+#endif /* NO_LONG_LONG */
+
+#ifdef Pack_32
+#define ULbits 32
+#define kshift 5
+#define kmask 31
+#define ALL_ON 0xffffffff
+#else
+#define ULbits 16
+#define kshift 4
+#define kmask 15
+#define ALL_ON 0xffff
+#endif
+
+#ifndef __SINGLE_THREAD__
+#define MULTIPLE_THREADS
+#endif
+
+#ifndef MULTIPLE_THREADS
+#define ACQUIRE_DTOA_LOCK(n)	/*nothing*/
+#define FREE_DTOA_LOCK(n)	/*nothing*/
+#else
+#include <sys/lock.h>
+#define ACQUIRE_DTOA_LOCK(n) \
+	n ? __lock_acquire(__dtoa_lock1) : __lock_acquire(__dtoa_lock0)
+#define FREE_DTOA_LOCK(n) \
+	n ? __lock_release(__dtoa_lock1) : __lock_release(__dtoa_lock0)
+#endif
+
+#define Kmax 9
+
+ struct
+Bigint {
+	struct Bigint *next;
+	int k, maxwds, sign, wds;
+	ULong x[1];
+	};
+
+ typedef struct Bigint Bigint;
+
+#ifdef NO_STRING_H
+#ifdef DECLARE_SIZE_T
+typedef unsigned int size_t;
+#endif
+extern void memcpy_D2A ANSI((void*, const void*, size_t));
+#define Bcopy(x,y) memcpy_D2A(&x->sign,&y->sign,y->wds*sizeof(ULong) + 2*sizeof(int))
+#else /* !NO_STRING_H */
+#define Bcopy(x,y) memcpy(&x->sign,&y->sign,y->wds*sizeof(ULong) + 2*sizeof(int))
+#endif /* NO_STRING_H */
+
+#define dtoa __dtoa
+#define gdtoa __gdtoa
+#define freedtoa __freedtoa
+#define strtodg __strtodg
+#define g_ddfmt __g_ddfmt
+#define g_dfmt __g_dfmt
+#define g_ffmt __g_ffmt
+#define g_Qfmt __g_Qfmt
+#define g_xfmt __g_xfmt
+#define g_xLfmt __g_xLfmt
+#define strtoId __strtoId
+#define strtoIdd __strtoIdd
+#define strtoIf __strtoIf
+#define strtoIQ __strtoIQ
+#define strtoIx __strtoIx
+#define strtoIxL __strtoIxL
+#define strtord __strtord
+#define strtordd __strtordd
+#define strtorf __strtorf
+#define strtorQ __strtorQ
+#define strtorx __strtorx
+#define strtorxL __strtorxL
+#define strtodI __strtodI
+#define strtopd __strtopd
+#define strtopdd __strtopdd
+#define strtopf __strtopf
+#define strtopQ __strtopQ
+#define strtopx __strtopx
+#define strtopxL __strtopxL
+
+#define Balloc __Balloc_D2A
+#define Bfree __Bfree_D2A
+#define ULtoQ __ULtoQ_D2A
+#define ULtof __ULtof_D2A
+#define ULtod __ULtod_D2A
+#define ULtodd __ULtodd_D2A
+#define ULtox __ULtox_D2A
+#define ULtoxL __ULtoxL_D2A
+#define any_on __any_on_D2A
+#define b2d __b2d_D2A
+#define bigtens __bigtens_D2A
+#define cmp __cmp_D2A
+#define copybits __copybits_D2A
+#define d2b __d2b_D2A
+#define decrement __decrement_D2A
+#define diff __diff_D2A
+#define dtoa_result __dtoa_result_D2A
+#define g__fmt __g__fmt_D2A
+#define gethex __gethex_D2A
+#define hexdig __hexdig_D2A
+#define hexnan __hexnan_D2A
+#define hi0bits(x) __hi0bits_D2A((ULong)(x))
+#define hi0bits_D2A __hi0bits_D2A
+#define i2b __i2b_D2A
+#define increment __increment_D2A
+#define lo0bits __lo0bits_D2A
+#define lshift __lshift_D2A
+#define match __match_D2A
+#define mult __mult_D2A
+#define multadd __multadd_D2A
+#define nrv_alloc __nrv_alloc_D2A
+#define pow5mult __pow5mult_D2A
+#define quorem __quorem_D2A
+#define ratio __ratio_D2A
+#define rshift __rshift_D2A
+#define rv_alloc __rv_alloc_D2A
+#define s2b __s2b_D2A
+#define set_ones __set_ones_D2A
+#define strcp __strcp_D2A
+#define strtoIg __strtoIg_D2A
+#define sulp __sulp_D2A
+#define sum __sum_D2A
+#define tens __tens_D2A
+#define tinytens __tinytens_D2A
+#define tinytens __tinytens_D2A
+#define trailz __trailz_D2A
+#define ulp __ulp_D2A
+
+__BEGIN_HIDDEN_DECLS
+ extern char *dtoa_result;
+ extern CONST double bigtens[], tens[], tinytens[];
+ extern unsigned char hexdig[];
+
+ extern Bigint *Balloc ANSI((int));
+ extern void Bfree ANSI((Bigint*));
+ extern void ULtof ANSI((ULong*, ULong*, Long, int));
+ extern void ULtod ANSI((ULong*, ULong*, Long, int));
+ extern void ULtodd ANSI((ULong*, ULong*, Long, int));
+ extern void ULtoQ ANSI((ULong*, ULong*, Long, int));
+ extern void ULtox ANSI((UShort*, ULong*, Long, int));
+ extern void ULtoxL ANSI((ULong*, ULong*, Long, int));
+ extern ULong any_on ANSI((Bigint*, int));
+ extern double b2d ANSI((Bigint*, int*));
+ extern int cmp ANSI((Bigint*, Bigint*));
+ extern void copybits ANSI((ULong*, int, Bigint*));
+ extern Bigint *d2b ANSI((double, int*, int*));
+ extern void decrement ANSI((Bigint*));
+ extern Bigint *diff ANSI((Bigint*, Bigint*));
+ extern char *g__fmt ANSI((char*, char*, char*, int, ULong, size_t));
+ extern int gethex ANSI((CONST char**, FPI*, Long*, Bigint**, int));
+ extern void __hexdig_init_D2A(Void);
+ extern int hexnan ANSI((CONST char**, FPI*, ULong*));
+ extern int hi0bits_D2A ANSI((ULong));
+ extern Bigint *i2b ANSI((int));
+ extern Bigint *increment ANSI((Bigint*));
+ extern int lo0bits ANSI((ULong*));
+ extern Bigint *lshift ANSI((Bigint*, int));
+ extern int match ANSI((CONST char**, char*));
+ extern Bigint *mult ANSI((Bigint*, Bigint*));
+ extern Bigint *multadd ANSI((Bigint*, int, int));
+ extern char *nrv_alloc ANSI((char*, char **, int));
+ extern Bigint *pow5mult ANSI((Bigint*, int));
+ extern int quorem ANSI((Bigint*, Bigint*));
+ extern double ratio ANSI((Bigint*, Bigint*));
+ extern void rshift ANSI((Bigint*, int));
+ extern char *rv_alloc ANSI((int));
+ extern Bigint *s2b ANSI((CONST char*, int, int, ULong, int));
+ extern Bigint *set_ones ANSI((Bigint*, int));
+ extern char *strcp ANSI((char*, const char*));
+ extern int strtoIg ANSI((CONST char*, char**, FPI*, Long*, Bigint**, int*));
+ extern Bigint *sum ANSI((Bigint*, Bigint*));
+ extern int trailz ANSI((Bigint*));
+ extern double ulp ANSI((U*));
+__END_HIDDEN_DECLS
+
+#ifdef __cplusplus
+}
+#endif
+/*
+ * NAN_WORD0 and NAN_WORD1 are only referenced in strtod.c.  Prior to
+ * 20050115, they used to be hard-wired here (to 0x7ff80000 and 0,
+ * respectively), but now are determined by compiling and running
+ * qnan.c to generate gd_qnan.h, which specifies d_QNAN0 and d_QNAN1.
+ * Formerly gdtoaimp.h recommended supplying suitable -DNAN_WORD0=...
+ * and -DNAN_WORD1=...  values if necessary.  This should still work.
+ * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.)
+ */
+#ifdef IEEE_Arith
+#ifndef NO_INFNAN_CHECK
+#undef INFNAN_CHECK
+#define INFNAN_CHECK
+#endif
+#ifdef IEEE_MC68k
+#define _0 0
+#define _1 1
+#ifndef NAN_WORD0
+#define NAN_WORD0 d_QNAN0
+#endif
+#ifndef NAN_WORD1
+#define NAN_WORD1 d_QNAN1
+#endif
+#else
+#define _0 1
+#define _1 0
+#ifndef NAN_WORD0
+#define NAN_WORD0 d_QNAN1
+#endif
+#ifndef NAN_WORD1
+#define NAN_WORD1 d_QNAN0
+#endif
+#endif
+#else
+#undef INFNAN_CHECK
+#endif
+
+#undef SI
+#ifdef Sudden_Underflow
+#define SI 1
+#else
+#define SI 0
+#endif
+
+#endif /* GDTOAIMP_H_INCLUDED */
diff --git a/newlib/libc/stdlib/ldtoa.c b/newlib/libc/stdlib/ldtoa.c
index 26c61948b..fbbd3d0b1 100644
--- a/newlib/libc/stdlib/ldtoa.c
+++ b/newlib/libc/stdlib/ldtoa.c
@@ -7,6 +7,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include "mprec.h"
+#include "gdtoa.h"
 
 /* These are the externally visible entries. */
 /* linux name:  long double _IO_strtold (char *, char **); */
@@ -2814,6 +2815,12 @@ _ldtoa_r (struct _reent *ptr, long double d, int mode, int ndigits,
       _REENT_MP_RESULT (ptr) = 0;
     }
 
+  /* Use the result of gdtoa if successfull. */
+  outstr = __ldtoa (&d, mode, ndigits, decpt, sign, rve);
+  /* If it fails, fallback to legacy ldtoa. */
+  if (outstr)
+    return outstr;
+
 #if LDBL_MANT_DIG == 24
   e24toe (&du.pe, e, ldp);
 #elif LDBL_MANT_DIG == 53
-- 
2.33.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed value is incorrectly rounded
  2021-11-29 10:56           ` Takashi Yano
@ 2021-11-29 14:24             ` Takashi Yano
  2021-11-29 15:55               ` Corinna Vinschen
  0 siblings, 1 reply; 25+ messages in thread
From: Takashi Yano @ 2021-11-29 14:24 UTC (permalink / raw)
  To: newlib

[-- Attachment #1: Type: text/plain, Size: 2070 bytes --]

On Mon, 29 Nov 2021 19:56:46 +0900
Takashi Yano wrote:
> On Sun, 28 Nov 2021 22:16:46 +0900
> Takashi Yano wrote:
> > On Sun, 28 Nov 2021 21:38:39 +0900
> > Takashi Yano wrote:
> > > On Sun, 28 Nov 2021 16:43:11 +0900
> > > Takashi Yano wrote:
> > > > On Thu, 4 Nov 2021 13:24:42 +0100
> > > > Corinna Vinschen wrote:
> > > > > However, a much better fix would be to switch to gdtoa, as the BSDs and
> > > > > Mingw64 do.
> > > > 
> > > > I have tried to import gdtoa into newlib from OpenBSD.
> > > > 
> > > > gdtoa seems to use malloc much, so it may not work in some of
> > > > platforms due to insufficient heap. Therefore, new ldtoa.c tries
> > > > gdtoa first and fallbacks to legacy ldtoa if gdtoa fails.
> > > > 
> > > > To import gdtoa to newlib, I did:
> > > > 1) Create "machine/ieee.h" which conditionally defines ieee_ext
> > > >    structure and EXT_TO_ARRAY32() macro depend on architecture.
> > > > 2) Create arith.h which reflects endian of architecture.
> > > > 3) Merge gdtoa.h with OpenBSD's gdtoa.h. __BEGIN_HIDDEN_DECLS,
> > > >    __END_HIDDEN_DECLS, PROTO_NORMAL() and DEF_STRONG() are
> > > >    defined as dummy in this header.
> > > > 4) Replace malloc()/free() with _malloc_r()/_free_r().
> > > > 5) Implement ACQUIRE_DTOA_LOCK() and FREE_DTOA_LOCK() macros
> > > >    using "sys/lock.h" for multi-threading environment.
> > > > 6) Remove inclusion of "gd_qnan.h" which is not used.
> > > > 
> > > > Please see attached patch for more details.
> > > > 
> > > > I confirmed this works nicely with cygwin. Moreover, it is much
> > > > faster than legacy ldtoa (more than 4 times faster).
> > > > 
> > > > However, this may break some other supported platforms.
> > > > 
> > > > Could anyone please check this?
> > > 
> > > Ah, in "machine/ieee.h", struct ieee_ext definition for
> > > LDBL_MANT_DIG==64 and __IEEE_BIG_ENDIAN case, is obviously
> > > wrong. 
> > 
> > Fixed.
> 
> Bit order for ARMEL without __VFP_FP__ is fixed.

Add support for ARM FPA10 math coprocessor extended precision format.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: 0001-ldtoa-Import-gdtoa-from-OpenBSD.patch --]
[-- Type: application/octet-stream, Size: 109103 bytes --]

From 919029f5df7ee46cdf32845053540a812d6030ed Mon Sep 17 00:00:00 2001
From: Takashi Yano <takashi.yano@nifty.ne.jp>
Date: Mon, 29 Nov 2021 21:36:47 +0900
Subject: [PATCH] ldtoa: Import gdtoa from OpenBSD.

---
 newlib/libc/include/machine/ieee.h | 127 ++++
 newlib/libc/stdlib/Makefile.am     |  14 +-
 newlib/libc/stdlib/Makefile.in     |  82 ++-
 newlib/libc/stdlib/arith.h         |   9 +
 newlib/libc/stdlib/gdtoa-dmisc.c   | 225 +++++++
 newlib/libc/stdlib/gdtoa-dtoa.c    | 839 ++++++++++++++++++++++++++
 newlib/libc/stdlib/gdtoa-gdtoa.c   | 830 ++++++++++++++++++++++++++
 newlib/libc/stdlib/gdtoa-gmisc.c   |  86 +++
 newlib/libc/stdlib/gdtoa-ldtoa.c   | 124 ++++
 newlib/libc/stdlib/gdtoa-misc.c    | 912 +++++++++++++++++++++++++++++
 newlib/libc/stdlib/gdtoa.h         | 132 ++++-
 newlib/libc/stdlib/gdtoaimp.h      | 672 +++++++++++++++++++++
 newlib/libc/stdlib/ldtoa.c         |   7 +
 13 files changed, 4025 insertions(+), 34 deletions(-)
 create mode 100644 newlib/libc/include/machine/ieee.h
 create mode 100644 newlib/libc/stdlib/arith.h
 create mode 100644 newlib/libc/stdlib/gdtoa-dmisc.c
 create mode 100644 newlib/libc/stdlib/gdtoa-dtoa.c
 create mode 100644 newlib/libc/stdlib/gdtoa-gdtoa.c
 create mode 100644 newlib/libc/stdlib/gdtoa-gmisc.c
 create mode 100644 newlib/libc/stdlib/gdtoa-ldtoa.c
 create mode 100644 newlib/libc/stdlib/gdtoa-misc.c
 create mode 100644 newlib/libc/stdlib/gdtoaimp.h

diff --git a/newlib/libc/include/machine/ieee.h b/newlib/libc/include/machine/ieee.h
new file mode 100644
index 000000000..79d72a645
--- /dev/null
+++ b/newlib/libc/include/machine/ieee.h
@@ -0,0 +1,127 @@
+#ifndef _MACHINE_IEEE_H_
+#define _MACHINE_IEEE_H_
+#include <sys/types.h>
+#include <sys/cdefs.h>
+#include <machine/ieeefp.h>
+#include <float.h>
+
+#if LDBL_MANT_DIG == 24
+#define EXT_IMPLICIT_NBIT
+#define EXT_TO_ARRAY32(p, a) do {      \
+    (a)[0] = (p)->ext_frac;  \
+} while (0)
+#ifdef __IEEE_LITTLE_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_frac:23;
+    uint32_t   ext_exp:8;
+    uint32_t   ext_sign:1;
+};
+#endif
+#ifdef __IEEE_BIG_ENDIAN
+struct ieee_ext {
+#ifndef ___IEEE_BYTES_LITTLE_ENDIAN
+    uint32_t   ext_sign:1;
+    uint32_t   ext_exp:8;
+    uint32_t   ext_frac:23;
+#else /* ARMEL without __VFP_FP__ */
+    uint32_t   ext_frac:23;
+    uint32_t   ext_exp:8;
+    uint32_t   ext_sign:1;
+#endif
+};
+#endif
+#elif LDBL_MANT_DIG == 53
+#define EXT_IMPLICIT_NBIT
+#define EXT_TO_ARRAY32(p, a) do {       \
+    (a)[0] = (p)->ext_fracl;  \
+    (a)[1] = (p)->ext_frach;  \
+} while (0)
+#ifdef __IEEE_LITTLE_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_fracl;
+    uint32_t   ext_frach:20;
+    uint32_t   ext_exp:11;
+    uint32_t   ext_sign:1;
+};
+#endif
+#ifdef __IEEE_BIG_ENDIAN
+struct ieee_ext {
+#ifndef ___IEEE_BYTES_LITTLE_ENDIAN
+    uint32_t   ext_sign:1;
+    uint32_t   ext_exp:11;
+    uint32_t   ext_frach:20;
+#else /* ARMEL without __VFP_FP__ */
+    uint32_t   ext_frach:20;
+    uint32_t   ext_exp:11;
+    uint32_t   ext_sign:1;
+#endif
+    uint32_t   ext_fracl;
+};
+#endif
+#elif LDBL_MANT_DIG == 64
+#define EXT_TO_ARRAY32(p, a) do {       \
+    (a)[0] = (p)->ext_fracl;  \
+    (a)[1] = (p)->ext_frach;  \
+} while (0)
+#ifdef __IEEE_LITTLE_ENDIAN /* for Intel CPU */
+struct ieee_ext {
+    uint32_t   ext_fracl;
+    uint32_t   ext_frach;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_sign:1;
+    uint32_t   ext_padl:16;
+    uint32_t   ext_padh;
+};
+#endif
+#ifdef __IEEE_BIG_ENDIAN
+struct ieee_ext {
+#ifndef ___IEEE_BYTES_LITTLE_ENDIAN /* for m68k */
+    uint32_t   ext_sign:1;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_pad:16;
+#else /* ARM FPA10 math coprocessor */
+    uint32_t   ext_exp:15;
+    uint32_t   ext_pad:16;
+    uint32_t   ext_sign:1;
+#endif
+    uint32_t   ext_frach;
+    uint32_t   ext_fracl;
+};
+#endif
+#elif LDBL_MANT_DIG == 113
+#define EXT_IMPLICIT_NBIT
+#define EXT_TO_ARRAY32(p, a) do {        \
+    (a)[0] = (p)->ext_fracl;   \
+    (a)[1] = (p)->ext_fraclm;  \
+    (a)[2] = (p)->ext_frachm;  \
+    (a)[3] = (p)->ext_frach;   \
+} while (0)
+#ifdef __IEEE_LITTLE_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_fracl;
+    uint32_t   ext_fraclm;
+    uint32_t   ext_frachm;
+    uint32_t   ext_frach:16;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_sign:1;
+};
+#endif
+#ifdef __IEEE_BIG_ENDIAN
+struct ieee_ext {
+#ifndef ___IEEE_BYTES_LITTLE_ENDIAN
+    uint32_t   ext_sign:1;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_frach:16;
+#else /* ARMEL without __VFP_FP__ */
+    uint32_t   ext_frach:16;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_sign:1;
+#endif
+    uint32_t   ext_frachm;
+    uint32_t   ext_fraclm;
+    uint32_t   ext_fracl;
+};
+#endif
+#endif
+
+#endif /* _MACHINE_IEEE_H_ */
diff --git a/newlib/libc/stdlib/Makefile.am b/newlib/libc/stdlib/Makefile.am
index 357e37beb..04b22d477 100644
--- a/newlib/libc/stdlib/Makefile.am
+++ b/newlib/libc/stdlib/Makefile.am
@@ -38,6 +38,12 @@ GENERAL_SOURCES = \
 	labs.c 		\
 	ldiv.c  	\
 	ldtoa.c		\
+	gdtoa-ldtoa.c	\
+	gdtoa-gdtoa.c	\
+	gdtoa-dtoa.c	\
+	gdtoa-misc.c	\
+	gdtoa-dmisc.c	\
+	gdtoa-gmisc.c	\
 	malloc.c  	\
 	mblen.c		\
 	mblen_r.c	\
@@ -311,7 +317,13 @@ CHEWOUT_FILES= \
 CHAPTERS = stdlib.tex
 
 $(lpfx)dtoa.$(oext): dtoa.c mprec.h
-$(lpfx)ldtoa.$(oext): ldtoa.c mprec.h
+$(lpfx)ldtoa.$(oext): ldtoa.c mprec.h gdtoa.h
+$(lpfx)gdtoa-ldtoa.$(oext): gdtoa-ldtoa.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-gdtoa.$(oext): gdtoa-gdtoa.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-dtoa.$(oext): gdtoa-dtoa.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-misc.$(oext): gdtoa-misc.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-dmisc.$(oext): gdtoa-dmisc.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-gmisc.$(oext): gdtoa-gmisc.c gdtoaimp.h gdtoa.h arith.h
 $(lpfx)ecvtbuf.$(oext): ecvtbuf.c mprec.h
 $(lpfx)mbtowc_r.$(oext): mbtowc_r.c mbctype.h
 $(lpfx)mprec.$(oext): mprec.c mprec.h
diff --git a/newlib/libc/stdlib/Makefile.in b/newlib/libc/stdlib/Makefile.in
index a812b6a95..4e891ced9 100644
--- a/newlib/libc/stdlib/Makefile.in
+++ b/newlib/libc/stdlib/Makefile.in
@@ -101,7 +101,10 @@ am__objects_2 = lib_a-__adjust.$(OBJEXT) lib_a-__atexit.$(OBJEXT) \
 	lib_a-getenv_r.$(OBJEXT) lib_a-imaxabs.$(OBJEXT) \
 	lib_a-imaxdiv.$(OBJEXT) lib_a-itoa.$(OBJEXT) \
 	lib_a-labs.$(OBJEXT) lib_a-ldiv.$(OBJEXT) \
-	lib_a-ldtoa.$(OBJEXT) lib_a-malloc.$(OBJEXT) \
+	lib_a-ldtoa.$(OBJEXT) lib_a-gdtoa-ldtoa.$(OBJEXT) \
+	lib_a-gdtoa-gdtoa.$(OBJEXT) lib_a-gdtoa-dtoa.$(OBJEXT) \
+	lib_a-gdtoa-misc.$(OBJEXT) lib_a-gdtoa-dmisc.$(OBJEXT) \
+	lib_a-gdtoa-gmisc.$(OBJEXT) lib_a-malloc.$(OBJEXT) \
 	lib_a-mblen.$(OBJEXT) lib_a-mblen_r.$(OBJEXT) \
 	lib_a-mbstowcs.$(OBJEXT) lib_a-mbstowcs_r.$(OBJEXT) \
 	lib_a-mbtowc.$(OBJEXT) lib_a-mbtowc_r.$(OBJEXT) \
@@ -165,14 +168,15 @@ am__objects_9 = __adjust.lo __atexit.lo __call_atexit.lo __exp10.lo \
 	div.lo dtoa.lo dtoastub.lo environ.lo envlock.lo eprintf.lo \
 	exit.lo gdtoa-gethex.lo gdtoa-hexnan.lo getenv.lo getenv_r.lo \
 	imaxabs.lo imaxdiv.lo itoa.lo labs.lo ldiv.lo ldtoa.lo \
-	malloc.lo mblen.lo mblen_r.lo mbstowcs.lo mbstowcs_r.lo \
-	mbtowc.lo mbtowc_r.lo mlock.lo mprec.lo mstats.lo \
-	on_exit_args.lo quick_exit.lo rand.lo rand_r.lo random.lo \
-	realloc.lo reallocarray.lo reallocf.lo sb_charsets.lo \
-	strtod.lo strtoimax.lo strtol.lo strtoul.lo strtoumax.lo \
-	utoa.lo wcstod.lo wcstoimax.lo wcstol.lo wcstoul.lo \
-	wcstoumax.lo wcstombs.lo wcstombs_r.lo wctomb.lo wctomb_r.lo \
-	$(am__objects_8)
+	gdtoa-ldtoa.lo gdtoa-gdtoa.lo gdtoa-dtoa.lo gdtoa-misc.lo \
+	gdtoa-dmisc.lo gdtoa-gmisc.lo malloc.lo mblen.lo mblen_r.lo \
+	mbstowcs.lo mbstowcs_r.lo mbtowc.lo mbtowc_r.lo mlock.lo \
+	mprec.lo mstats.lo on_exit_args.lo quick_exit.lo rand.lo \
+	rand_r.lo random.lo realloc.lo reallocarray.lo reallocf.lo \
+	sb_charsets.lo strtod.lo strtoimax.lo strtol.lo strtoul.lo \
+	strtoumax.lo utoa.lo wcstod.lo wcstoimax.lo wcstol.lo \
+	wcstoul.lo wcstoumax.lo wcstombs.lo wcstombs_r.lo wctomb.lo \
+	wctomb_r.lo $(am__objects_8)
 am__objects_10 = arc4random.lo arc4random_uniform.lo cxa_atexit.lo \
 	cxa_finalize.lo drand48.lo ecvtbuf.lo efgcvt.lo erand48.lo \
 	jrand48.lo lcong48.lo lrand48.lo mrand48.lo msize.lo mtrim.lo \
@@ -354,6 +358,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 shared_machine_dir = @shared_machine_dir@
 sharedstatedir = @sharedstatedir@
@@ -372,13 +377,14 @@ GENERAL_SOURCES = __adjust.c __atexit.c __call_atexit.c __exp10.c \
 	atexit.c atof.c atoff.c atoi.c atol.c calloc.c div.c dtoa.c \
 	dtoastub.c environ.c envlock.c eprintf.c exit.c gdtoa-gethex.c \
 	gdtoa-hexnan.c getenv.c getenv_r.c imaxabs.c imaxdiv.c itoa.c \
-	labs.c ldiv.c ldtoa.c malloc.c mblen.c mblen_r.c mbstowcs.c \
-	mbstowcs_r.c mbtowc.c mbtowc_r.c mlock.c mprec.c mstats.c \
-	on_exit_args.c quick_exit.c rand.c rand_r.c random.c realloc.c \
-	reallocarray.c reallocf.c sb_charsets.c strtod.c strtoimax.c \
-	strtol.c strtoul.c strtoumax.c utoa.c wcstod.c wcstoimax.c \
-	wcstol.c wcstoul.c wcstoumax.c wcstombs.c wcstombs_r.c \
-	wctomb.c wctomb_r.c $(am__append_1)
+	labs.c ldiv.c ldtoa.c gdtoa-ldtoa.c gdtoa-gdtoa.c gdtoa-dtoa.c \
+	gdtoa-misc.c gdtoa-dmisc.c gdtoa-gmisc.c malloc.c mblen.c \
+	mblen_r.c mbstowcs.c mbstowcs_r.c mbtowc.c mbtowc_r.c mlock.c \
+	mprec.c mstats.c on_exit_args.c quick_exit.c rand.c rand_r.c \
+	random.c realloc.c reallocarray.c reallocf.c sb_charsets.c \
+	strtod.c strtoimax.c strtol.c strtoul.c strtoumax.c utoa.c \
+	wcstod.c wcstoimax.c wcstol.c wcstoul.c wcstoumax.c wcstombs.c \
+	wcstombs_r.c wctomb.c wctomb_r.c $(am__append_1)
 @NEWLIB_NANO_MALLOC_FALSE@MALIGNR = malignr
 @NEWLIB_NANO_MALLOC_TRUE@MALIGNR = nano-malignr
 @NEWLIB_NANO_MALLOC_FALSE@MALLOPTR = malloptr
@@ -827,6 +833,42 @@ lib_a-ldtoa.o: ldtoa.c
 lib_a-ldtoa.obj: ldtoa.c
 	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-ldtoa.obj `if test -f 'ldtoa.c'; then $(CYGPATH_W) 'ldtoa.c'; else $(CYGPATH_W) '$(srcdir)/ldtoa.c'; fi`
 
+lib_a-gdtoa-ldtoa.o: gdtoa-ldtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-ldtoa.o `test -f 'gdtoa-ldtoa.c' || echo '$(srcdir)/'`gdtoa-ldtoa.c
+
+lib_a-gdtoa-ldtoa.obj: gdtoa-ldtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-ldtoa.obj `if test -f 'gdtoa-ldtoa.c'; then $(CYGPATH_W) 'gdtoa-ldtoa.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-ldtoa.c'; fi`
+
+lib_a-gdtoa-gdtoa.o: gdtoa-gdtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-gdtoa.o `test -f 'gdtoa-gdtoa.c' || echo '$(srcdir)/'`gdtoa-gdtoa.c
+
+lib_a-gdtoa-gdtoa.obj: gdtoa-gdtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-gdtoa.obj `if test -f 'gdtoa-gdtoa.c'; then $(CYGPATH_W) 'gdtoa-gdtoa.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-gdtoa.c'; fi`
+
+lib_a-gdtoa-dtoa.o: gdtoa-dtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-dtoa.o `test -f 'gdtoa-dtoa.c' || echo '$(srcdir)/'`gdtoa-dtoa.c
+
+lib_a-gdtoa-dtoa.obj: gdtoa-dtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-dtoa.obj `if test -f 'gdtoa-dtoa.c'; then $(CYGPATH_W) 'gdtoa-dtoa.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-dtoa.c'; fi`
+
+lib_a-gdtoa-misc.o: gdtoa-misc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-misc.o `test -f 'gdtoa-misc.c' || echo '$(srcdir)/'`gdtoa-misc.c
+
+lib_a-gdtoa-misc.obj: gdtoa-misc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-misc.obj `if test -f 'gdtoa-misc.c'; then $(CYGPATH_W) 'gdtoa-misc.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-misc.c'; fi`
+
+lib_a-gdtoa-dmisc.o: gdtoa-dmisc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-dmisc.o `test -f 'gdtoa-dmisc.c' || echo '$(srcdir)/'`gdtoa-dmisc.c
+
+lib_a-gdtoa-dmisc.obj: gdtoa-dmisc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-dmisc.obj `if test -f 'gdtoa-dmisc.c'; then $(CYGPATH_W) 'gdtoa-dmisc.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-dmisc.c'; fi`
+
+lib_a-gdtoa-gmisc.o: gdtoa-gmisc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-gmisc.o `test -f 'gdtoa-gmisc.c' || echo '$(srcdir)/'`gdtoa-gmisc.c
+
+lib_a-gdtoa-gmisc.obj: gdtoa-gmisc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-gmisc.obj `if test -f 'gdtoa-gmisc.c'; then $(CYGPATH_W) 'gdtoa-gmisc.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-gmisc.c'; fi`
+
 lib_a-malloc.o: malloc.c
 	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-malloc.o `test -f 'malloc.c' || echo '$(srcdir)/'`malloc.c
 
@@ -1610,7 +1652,13 @@ $(lpfx)$(MALLOPTR).$(oext): $(MALLOCR).c
 	$(MALLOC_COMPILE) -DDEFINE_MALLOPT -c $(srcdir)/$(MALLOCR).c -o $@
 
 $(lpfx)dtoa.$(oext): dtoa.c mprec.h
-$(lpfx)ldtoa.$(oext): ldtoa.c mprec.h
+$(lpfx)ldtoa.$(oext): ldtoa.c mprec.h gdtoa.h
+$(lpfx)gdtoa-ldtoa.$(oext): gdtoa-ldtoa.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-gdtoa.$(oext): gdtoa-gdtoa.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-dtoa.$(oext): gdtoa-dtoa.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-misc.$(oext): gdtoa-misc.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-dmisc.$(oext): gdtoa-dmisc.c gdtoaimp.h gdtoa.h arith.h
+$(lpfx)gdtoa-gmisc.$(oext): gdtoa-gmisc.c gdtoaimp.h gdtoa.h arith.h
 $(lpfx)ecvtbuf.$(oext): ecvtbuf.c mprec.h
 $(lpfx)mbtowc_r.$(oext): mbtowc_r.c mbctype.h
 $(lpfx)mprec.$(oext): mprec.c mprec.h
diff --git a/newlib/libc/stdlib/arith.h b/newlib/libc/stdlib/arith.h
new file mode 100644
index 000000000..d3b84d867
--- /dev/null
+++ b/newlib/libc/stdlib/arith.h
@@ -0,0 +1,9 @@
+#include <machine/ieeefp.h>
+
+#ifdef __IEEE_LITTLE_ENDIAN
+#define IEEE_8087
+#endif
+
+#ifdef __IEEE_BIG_ENDIAN
+#define IEEE_MC68k
+#endif
diff --git a/newlib/libc/stdlib/gdtoa-dmisc.c b/newlib/libc/stdlib/gdtoa-dmisc.c
new file mode 100644
index 000000000..f3d8ea71a
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-dmisc.c
@@ -0,0 +1,225 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include "gdtoaimp.h"
+
+#ifndef MULTIPLE_THREADS
+ char *dtoa_result;
+#endif
+
+ char *
+#ifdef KR_headers
+rv_alloc(i) int i;
+#else
+rv_alloc(int i)
+#endif
+{
+	int j, k, *r;
+
+	j = sizeof(ULong);
+	for(k = 0;
+		sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i;
+		j <<= 1)
+			k++;
+	r = (int*)Balloc(k);
+	if (r == NULL)
+		return (
+#ifndef MULTIPLE_THREADS
+		dtoa_result =
+#endif
+			NULL);
+	*r = k;
+	return
+#ifndef MULTIPLE_THREADS
+	dtoa_result =
+#endif
+		(char *)(r+1);
+	}
+
+ char *
+#ifdef KR_headers
+nrv_alloc(s, rve, n) char *s, **rve; int n;
+#else
+nrv_alloc(char *s, char **rve, int n)
+#endif
+{
+	char *rv, *t;
+
+	t = rv = rv_alloc(n);
+	if (t == NULL)
+		return (NULL);
+	while((*t = *s++) !=0)
+		t++;
+	if (rve)
+		*rve = t;
+	return rv;
+	}
+
+/* freedtoa(s) must be used to free values s returned by dtoa
+ * when MULTIPLE_THREADS is #defined.  It should be used in all cases,
+ * but for consistency with earlier versions of dtoa, it is optional
+ * when MULTIPLE_THREADS is not defined.
+ */
+
+ void
+#ifdef KR_headers
+freedtoa(s) char *s;
+#else
+freedtoa(char *s)
+#endif
+{
+	Bigint *b = (Bigint *)((int *)s - 1);
+	b->maxwds = 1 << (b->k = *(int*)b);
+	Bfree(b);
+#ifndef MULTIPLE_THREADS
+	if (s == dtoa_result)
+		dtoa_result = 0;
+#endif
+	}
+DEF_STRONG(freedtoa);
+
+ int
+quorem
+#ifdef KR_headers
+	(b, S) Bigint *b, *S;
+#else
+	(Bigint *b, Bigint *S)
+#endif
+{
+	int n;
+	ULong *bx, *bxe, q, *sx, *sxe;
+#ifdef ULLong
+	ULLong borrow, carry, y, ys;
+#else
+	ULong borrow, carry, y, ys;
+#ifdef Pack_32
+	ULong si, z, zs;
+#endif
+#endif
+
+	n = S->wds;
+#ifdef DEBUG
+	/*debug*/ if (b->wds > n)
+	/*debug*/	Bug("oversize b in quorem");
+#endif
+	if (b->wds < n)
+		return 0;
+	sx = S->x;
+	sxe = sx + --n;
+	bx = b->x;
+	bxe = bx + n;
+	q = *bxe / (*sxe + 1);	/* ensure q <= true quotient */
+#ifdef DEBUG
+	/*debug*/ if (q > 9)
+	/*debug*/	Bug("oversized quotient in quorem");
+#endif
+	if (q) {
+		borrow = 0;
+		carry = 0;
+		do {
+#ifdef ULLong
+			ys = *sx++ * (ULLong)q + carry;
+			carry = ys >> 32;
+			y = *bx - (ys & 0xffffffffUL) - borrow;
+			borrow = y >> 32 & 1UL;
+			*bx++ = y & 0xffffffffUL;
+#else
+#ifdef Pack_32
+			si = *sx++;
+			ys = (si & 0xffff) * q + carry;
+			zs = (si >> 16) * q + (ys >> 16);
+			carry = zs >> 16;
+			y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			z = (*bx >> 16) - (zs & 0xffff) - borrow;
+			borrow = (z & 0x10000) >> 16;
+			Storeinc(bx, z, y);
+#else
+			ys = *sx++ * q + carry;
+			carry = ys >> 16;
+			y = *bx - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			*bx++ = y & 0xffff;
+#endif
+#endif
+			}
+			while(sx <= sxe);
+		if (!*bxe) {
+			bx = b->x;
+			while(--bxe > bx && !*bxe)
+				--n;
+			b->wds = n;
+			}
+		}
+	if (cmp(b, S) >= 0) {
+		q++;
+		borrow = 0;
+		carry = 0;
+		bx = b->x;
+		sx = S->x;
+		do {
+#ifdef ULLong
+			ys = *sx++ + carry;
+			carry = ys >> 32;
+			y = *bx - (ys & 0xffffffffUL) - borrow;
+			borrow = y >> 32 & 1UL;
+			*bx++ = y & 0xffffffffUL;
+#else
+#ifdef Pack_32
+			si = *sx++;
+			ys = (si & 0xffff) + carry;
+			zs = (si >> 16) + (ys >> 16);
+			carry = zs >> 16;
+			y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			z = (*bx >> 16) - (zs & 0xffff) - borrow;
+			borrow = (z & 0x10000) >> 16;
+			Storeinc(bx, z, y);
+#else
+			ys = *sx++ + carry;
+			carry = ys >> 16;
+			y = *bx - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			*bx++ = y & 0xffff;
+#endif
+#endif
+			}
+			while(sx <= sxe);
+		bx = b->x;
+		bxe = bx + n;
+		if (!*bxe) {
+			while(--bxe > bx && !*bxe)
+				--n;
+			b->wds = n;
+			}
+		}
+	return q;
+	}
diff --git a/newlib/libc/stdlib/gdtoa-dtoa.c b/newlib/libc/stdlib/gdtoa-dtoa.c
new file mode 100644
index 000000000..998192764
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-dtoa.c
@@ -0,0 +1,839 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998, 1999 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include "gdtoaimp.h"
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ *	1. Rather than iterating, we use a simple numeric overestimate
+ *	   to determine k = floor(log10(d)).  We scale relevant
+ *	   quantities using O(log2(k)) rather than O(k) multiplications.
+ *	2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ *	   try to generate digits strictly left to right.  Instead, we
+ *	   compute with fewer bits and propagate the carry if necessary
+ *	   when rounding the final digit up.  This is often faster.
+ *	3. Under the assumption that input will be rounded nearest,
+ *	   mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ *	   That is, we allow equality in stopping tests when the
+ *	   round-nearest rule will give the same floating-point value
+ *	   as would satisfaction of the stopping test with strict
+ *	   inequality.
+ *	4. We remove common factors of powers of 2 from relevant
+ *	   quantities.
+ *	5. When converting floating-point integers less than 1e16,
+ *	   we use floating-point arithmetic rather than resorting
+ *	   to multiple-precision integers.
+ *	6. When asked to produce fewer than 15 digits, we first try
+ *	   to get by with floating-point arithmetic; we resort to
+ *	   multiple-precision integer arithmetic only if we cannot
+ *	   guarantee that the floating-point calculation has given
+ *	   the correctly rounded result.  For k requested digits and
+ *	   "uniformly" distributed input, the probability is
+ *	   something like 10^(k-15) that we must resort to the Long
+ *	   calculation.
+ */
+
+#ifdef Honor_FLT_ROUNDS
+#undef Check_FLT_ROUNDS
+#define Check_FLT_ROUNDS
+#else
+#define Rounding Flt_Rounds
+#endif
+
+ char *
+dtoa
+#ifdef KR_headers
+	(d0, mode, ndigits, decpt, sign, rve)
+	double d0; int mode, ndigits, *decpt, *sign; char **rve;
+#else
+	(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
+#endif
+{
+ /*	Arguments ndigits, decpt, sign are similar to those
+	of ecvt and fcvt; trailing zeros are suppressed from
+	the returned string.  If not null, *rve is set to point
+	to the end of the return value.  If d is +-Infinity or NaN,
+	then *decpt is set to 9999.
+
+	mode:
+		0 ==> shortest string that yields d when read in
+			and rounded to nearest.
+		1 ==> like 0, but with Steele & White stopping rule;
+			e.g. with IEEE P754 arithmetic , mode 0 gives
+			1e23 whereas mode 1 gives 9.999999999999999e22.
+		2 ==> max(1,ndigits) significant digits.  This gives a
+			return value similar to that of ecvt, except
+			that trailing zeros are suppressed.
+		3 ==> through ndigits past the decimal point.  This
+			gives a return value similar to that from fcvt,
+			except that trailing zeros are suppressed, and
+			ndigits can be negative.
+		4,5 ==> similar to 2 and 3, respectively, but (in
+			round-nearest mode) with the tests of mode 0 to
+			possibly return a shorter string that rounds to d.
+			With IEEE arithmetic and compilation with
+			-DHonor_FLT_ROUNDS, modes 4 and 5 behave the same
+			as modes 2 and 3 when FLT_ROUNDS != 1.
+		6-9 ==> Debugging modes similar to mode - 4:  don't try
+			fast floating-point estimate (if applicable).
+
+		Values of mode other than 0-9 are treated as mode 0.
+
+		Sufficient space is allocated to the return value
+		to hold the suppressed trailing zeros.
+	*/
+
+	int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,
+		j, j1, k, k0, k_check, leftright, m2, m5, s2, s5,
+		spec_case, try_quick;
+	Long L;
+#ifndef Sudden_Underflow
+	int denorm;
+	ULong x;
+#endif
+	Bigint *b, *b1, *delta, *mlo, *mhi, *S;
+	U d, d2, eps;
+	double ds;
+	char *s, *s0;
+#ifdef SET_INEXACT
+	int inexact, oldinexact;
+#endif
+#ifdef Honor_FLT_ROUNDS /*{*/
+	int Rounding;
+#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */
+	Rounding = Flt_Rounds;
+#else /*}{*/
+	Rounding = 1;
+	switch(fegetround()) {
+	  case FE_TOWARDZERO:	Rounding = 0; break;
+	  case FE_UPWARD:	Rounding = 2; break;
+	  case FE_DOWNWARD:	Rounding = 3;
+	  }
+#endif /*}}*/
+#endif /*}*/
+
+#ifndef MULTIPLE_THREADS
+	if (dtoa_result) {
+		freedtoa(dtoa_result);
+		dtoa_result = 0;
+		}
+#endif
+	d.d = d0;
+	if (word0(&d) & Sign_bit) {
+		/* set sign for everything, including 0's and NaNs */
+		*sign = 1;
+		word0(&d) &= ~Sign_bit;	/* clear sign bit */
+		}
+	else
+		*sign = 0;
+
+#if defined(IEEE_Arith) + defined(VAX)
+#ifdef IEEE_Arith
+	if ((word0(&d) & Exp_mask) == Exp_mask)
+#else
+	if (word0(&d)  == 0x8000)
+#endif
+		{
+		/* Infinity or NaN */
+		*decpt = 9999;
+#ifdef IEEE_Arith
+		if (!word1(&d) && !(word0(&d) & 0xfffff))
+			return nrv_alloc("Infinity", rve, 8);
+#endif
+		return nrv_alloc("NaN", rve, 3);
+		}
+#endif
+#ifdef IBM
+	dval(&d) += 0; /* normalize */
+#endif
+	if (!dval(&d)) {
+		*decpt = 1;
+		return nrv_alloc("0", rve, 1);
+		}
+
+#ifdef SET_INEXACT
+	try_quick = oldinexact = get_inexact();
+	inexact = 1;
+#endif
+#ifdef Honor_FLT_ROUNDS
+	if (Rounding >= 2) {
+		if (*sign)
+			Rounding = Rounding == 2 ? 0 : 2;
+		else
+			if (Rounding != 2)
+				Rounding = 0;
+		}
+#endif
+
+	b = d2b(dval(&d), &be, &bbits);
+	if (b == NULL)
+		return (NULL);
+#ifdef Sudden_Underflow
+	i = (int)(word0(&d) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
+#else
+	if (( i = (int)(word0(&d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)) )!=0) {
+#endif
+		dval(&d2) = dval(&d);
+		word0(&d2) &= Frac_mask1;
+		word0(&d2) |= Exp_11;
+#ifdef IBM
+		if (( j = 11 - hi0bits(word0(&d2) & Frac_mask) )!=0)
+			dval(&d2) /= 1 << j;
+#endif
+
+		/* log(x)	~=~ log(1.5) + (x-1.5)/1.5
+		 * log10(x)	 =  log(x) / log(10)
+		 *		~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+		 * log10(&d) = (i-Bias)*log(2)/log(10) + log10(&d2)
+		 *
+		 * This suggests computing an approximation k to log10(&d) by
+		 *
+		 * k = (i - Bias)*0.301029995663981
+		 *	+ ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+		 *
+		 * We want k to be too large rather than too small.
+		 * The error in the first-order Taylor series approximation
+		 * is in our favor, so we just round up the constant enough
+		 * to compensate for any error in the multiplication of
+		 * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+		 * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+		 * adding 1e-13 to the constant term more than suffices.
+		 * Hence we adjust the constant term to 0.1760912590558.
+		 * (We could get a more accurate k by invoking log10,
+		 *  but this is probably not worthwhile.)
+		 */
+
+		i -= Bias;
+#ifdef IBM
+		i <<= 2;
+		i += j;
+#endif
+#ifndef Sudden_Underflow
+		denorm = 0;
+		}
+	else {
+		/* d is denormalized */
+
+		i = bbits + be + (Bias + (P-1) - 1);
+		x = i > 32  ? word0(&d) << (64 - i) | word1(&d) >> (i - 32)
+			    : word1(&d) << (32 - i);
+		dval(&d2) = x;
+		word0(&d2) -= 31*Exp_msk1; /* adjust exponent */
+		i -= (Bias + (P-1) - 1) + 1;
+		denorm = 1;
+		}
+#endif
+	ds = (dval(&d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
+	k = (int)ds;
+	if (ds < 0. && ds != k)
+		k--;	/* want k = floor(ds) */
+	k_check = 1;
+	if (k >= 0 && k <= Ten_pmax) {
+		if (dval(&d) < tens[k])
+			k--;
+		k_check = 0;
+		}
+	j = bbits - i - 1;
+	if (j >= 0) {
+		b2 = 0;
+		s2 = j;
+		}
+	else {
+		b2 = -j;
+		s2 = 0;
+		}
+	if (k >= 0) {
+		b5 = 0;
+		s5 = k;
+		s2 += k;
+		}
+	else {
+		b2 -= k;
+		b5 = -k;
+		s5 = 0;
+		}
+	if (mode < 0 || mode > 9)
+		mode = 0;
+
+#ifndef SET_INEXACT
+#ifdef Check_FLT_ROUNDS
+	try_quick = Rounding == 1;
+#else
+	try_quick = 1;
+#endif
+#endif /*SET_INEXACT*/
+
+	if (mode > 5) {
+		mode -= 4;
+		try_quick = 0;
+		}
+	leftright = 1;
+	ilim = ilim1 = -1;	/* Values for cases 0 and 1; done here to */
+				/* silence erroneous "gcc -Wall" warning. */
+	switch(mode) {
+		case 0:
+		case 1:
+			i = 18;
+			ndigits = 0;
+			break;
+		case 2:
+			leftright = 0;
+			/* no break */
+		case 4:
+			if (ndigits <= 0)
+				ndigits = 1;
+			ilim = ilim1 = i = ndigits;
+			break;
+		case 3:
+			leftright = 0;
+			/* no break */
+		case 5:
+			i = ndigits + k + 1;
+			ilim = i;
+			ilim1 = i - 1;
+			if (i <= 0)
+				i = 1;
+		}
+	s = s0 = rv_alloc(i);
+	if (s == NULL)
+		return (NULL);
+
+#ifdef Honor_FLT_ROUNDS
+	if (mode > 1 && Rounding != 1)
+		leftright = 0;
+#endif
+
+	if (ilim >= 0 && ilim <= Quick_max && try_quick) {
+
+		/* Try to get by with floating-point arithmetic. */
+
+		i = 0;
+		dval(&d2) = dval(&d);
+		k0 = k;
+		ilim0 = ilim;
+		ieps = 2; /* conservative */
+		if (k > 0) {
+			ds = tens[k&0xf];
+			j = k >> 4;
+			if (j & Bletch) {
+				/* prevent overflows */
+				j &= Bletch - 1;
+				dval(&d) /= bigtens[n_bigtens-1];
+				ieps++;
+				}
+			for(; j; j >>= 1, i++)
+				if (j & 1) {
+					ieps++;
+					ds *= bigtens[i];
+					}
+			dval(&d) /= ds;
+			}
+		else if (( j1 = -k )!=0) {
+			dval(&d) *= tens[j1 & 0xf];
+			for(j = j1 >> 4; j; j >>= 1, i++)
+				if (j & 1) {
+					ieps++;
+					dval(&d) *= bigtens[i];
+					}
+			}
+		if (k_check && dval(&d) < 1. && ilim > 0) {
+			if (ilim1 <= 0)
+				goto fast_failed;
+			ilim = ilim1;
+			k--;
+			dval(&d) *= 10.;
+			ieps++;
+			}
+		dval(&eps) = ieps*dval(&d) + 7.;
+		word0(&eps) -= (P-1)*Exp_msk1;
+		if (ilim == 0) {
+			S = mhi = 0;
+			dval(&d) -= 5.;
+			if (dval(&d) > dval(&eps))
+				goto one_digit;
+			if (dval(&d) < -dval(&eps))
+				goto no_digits;
+			goto fast_failed;
+			}
+#ifndef No_leftright
+		if (leftright) {
+			/* Use Steele & White method of only
+			 * generating digits needed.
+			 */
+			dval(&eps) = 0.5/tens[ilim-1] - dval(&eps);
+			for(i = 0;;) {
+				L = dval(&d);
+				dval(&d) -= L;
+				*s++ = '0' + (int)L;
+				if (dval(&d) < dval(&eps))
+					goto ret1;
+				if (1. - dval(&d) < dval(&eps))
+					goto bump_up;
+				if (++i >= ilim)
+					break;
+				dval(&eps) *= 10.;
+				dval(&d) *= 10.;
+				}
+			}
+		else {
+#endif
+			/* Generate ilim digits, then fix them up. */
+			dval(&eps) *= tens[ilim-1];
+			for(i = 1;; i++, dval(&d) *= 10.) {
+				L = (Long)(dval(&d));
+				if (!(dval(&d) -= L))
+					ilim = i;
+				*s++ = '0' + (int)L;
+				if (i == ilim) {
+					if (dval(&d) > 0.5 + dval(&eps))
+						goto bump_up;
+					else if (dval(&d) < 0.5 - dval(&eps)) {
+						while(*--s == '0');
+						s++;
+						goto ret1;
+						}
+					break;
+					}
+				}
+#ifndef No_leftright
+			}
+#endif
+ fast_failed:
+		s = s0;
+		dval(&d) = dval(&d2);
+		k = k0;
+		ilim = ilim0;
+		}
+
+	/* Do we have a "small" integer? */
+
+	if (be >= 0 && k <= Int_max) {
+		/* Yes. */
+		ds = tens[k];
+		if (ndigits < 0 && ilim <= 0) {
+			S = mhi = 0;
+			if (ilim < 0 || dval(&d) <= 5*ds)
+				goto no_digits;
+			goto one_digit;
+			}
+		for(i = 1;; i++, dval(&d) *= 10.) {
+			L = (Long)(dval(&d) / ds);
+			dval(&d) -= L*ds;
+#ifdef Check_FLT_ROUNDS
+			/* If FLT_ROUNDS == 2, L will usually be high by 1 */
+			if (dval(&d) < 0) {
+				L--;
+				dval(&d) += ds;
+				}
+#endif
+			*s++ = '0' + (int)L;
+			if (!dval(&d)) {
+#ifdef SET_INEXACT
+				inexact = 0;
+#endif
+				break;
+				}
+			if (i == ilim) {
+#ifdef Honor_FLT_ROUNDS
+				if (mode > 1)
+				switch(Rounding) {
+				  case 0: goto ret1;
+				  case 2: goto bump_up;
+				  }
+#endif
+				dval(&d) += dval(&d);
+#ifdef ROUND_BIASED
+				if (dval(&d) >= ds)
+#else
+				if (dval(&d) > ds || (dval(&d) == ds && L & 1))
+#endif
+					{
+ bump_up:
+					while(*--s == '9')
+						if (s == s0) {
+							k++;
+							*s = '0';
+							break;
+							}
+					++*s++;
+					}
+				break;
+				}
+			}
+		goto ret1;
+		}
+
+	m2 = b2;
+	m5 = b5;
+	mhi = mlo = 0;
+	if (leftright) {
+		i =
+#ifndef Sudden_Underflow
+			denorm ? be + (Bias + (P-1) - 1 + 1) :
+#endif
+#ifdef IBM
+			1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3);
+#else
+			1 + P - bbits;
+#endif
+		b2 += i;
+		s2 += i;
+		mhi = i2b(1);
+		if (mhi == NULL)
+			return (NULL);
+		}
+	if (m2 > 0 && s2 > 0) {
+		i = m2 < s2 ? m2 : s2;
+		b2 -= i;
+		m2 -= i;
+		s2 -= i;
+		}
+	if (b5 > 0) {
+		if (leftright) {
+			if (m5 > 0) {
+				mhi = pow5mult(mhi, m5);
+				if (mhi == NULL)
+					return (NULL);
+				b1 = mult(mhi, b);
+				if (b1 == NULL)
+					return (NULL);
+				Bfree(b);
+				b = b1;
+				}
+			if (( j = b5 - m5 )!=0) {
+				b = pow5mult(b, j);
+				if (b == NULL)
+					return (NULL);
+				}
+			}
+		else {
+			b = pow5mult(b, b5);
+			if (b == NULL)
+				return (NULL);
+			}
+		}
+	S = i2b(1);
+	if (S == NULL)
+		return (NULL);
+	if (s5 > 0) {
+		S = pow5mult(S, s5);
+		if (S == NULL)
+			return (NULL);
+		}
+
+	/* Check for special case that d is a normalized power of 2. */
+
+	spec_case = 0;
+	if ((mode < 2 || leftright)
+#ifdef Honor_FLT_ROUNDS
+			&& Rounding == 1
+#endif
+				) {
+		if (!word1(&d) && !(word0(&d) & Bndry_mask)
+#ifndef Sudden_Underflow
+		 && word0(&d) & (Exp_mask & ~Exp_msk1)
+#endif
+				) {
+			/* The special case */
+			b2 += Log2P;
+			s2 += Log2P;
+			spec_case = 1;
+			}
+		}
+
+	/* Arrange for convenient computation of quotients:
+	 * shift left if necessary so divisor has 4 leading 0 bits.
+	 *
+	 * Perhaps we should just compute leading 28 bits of S once
+	 * and for all and pass them and a shift to quorem, so it
+	 * can do shifts and ors to compute the numerator for q.
+	 */
+#ifdef Pack_32
+	if (( i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f )!=0)
+		i = 32 - i;
+#else
+	if (( i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf )!=0)
+		i = 16 - i;
+#endif
+	if (i > 4) {
+		i -= 4;
+		b2 += i;
+		m2 += i;
+		s2 += i;
+		}
+	else if (i < 4) {
+		i += 28;
+		b2 += i;
+		m2 += i;
+		s2 += i;
+		}
+	if (b2 > 0) {
+		b = lshift(b, b2);
+		if (b == NULL)
+			return (NULL);
+		}
+	if (s2 > 0) {
+		S = lshift(S, s2);
+		if (S == NULL)
+			return (NULL);
+		}
+	if (k_check) {
+		if (cmp(b,S) < 0) {
+			k--;
+			b = multadd(b, 10, 0);	/* we botched the k estimate */
+			if (b == NULL)
+				return (NULL);
+			if (leftright) {
+				mhi = multadd(mhi, 10, 0);
+				if (mhi == NULL)
+					return (NULL);
+				}
+			ilim = ilim1;
+			}
+		}
+	if (ilim <= 0 && (mode == 3 || mode == 5)) {
+		S = multadd(S,5,0);
+		if (S == NULL)
+			return (NULL);
+		if (ilim < 0 || cmp(b,S) <= 0) {
+			/* no digits, fcvt style */
+ no_digits:
+			k = -1 - ndigits;
+			goto ret;
+			}
+ one_digit:
+		*s++ = '1';
+		k++;
+		goto ret;
+		}
+	if (leftright) {
+		if (m2 > 0) {
+			mhi = lshift(mhi, m2);
+			if (mhi == NULL)
+				return (NULL);
+			}
+
+		/* Compute mlo -- check for special case
+		 * that d is a normalized power of 2.
+		 */
+
+		mlo = mhi;
+		if (spec_case) {
+			mhi = Balloc(mhi->k);
+			if (mhi == NULL)
+				return (NULL);
+			Bcopy(mhi, mlo);
+			mhi = lshift(mhi, Log2P);
+			if (mhi == NULL)
+				return (NULL);
+			}
+
+		for(i = 1;;i++) {
+			dig = quorem(b,S) + '0';
+			/* Do we yet have the shortest decimal string
+			 * that will round to d?
+			 */
+			j = cmp(b, mlo);
+			delta = diff(S, mhi);
+			if (delta == NULL)
+				return (NULL);
+			j1 = delta->sign ? 1 : cmp(b, delta);
+			Bfree(delta);
+#ifndef ROUND_BIASED
+			if (j1 == 0 && mode != 1 && !(word1(&d) & 1)
+#ifdef Honor_FLT_ROUNDS
+				&& Rounding >= 1
+#endif
+								   ) {
+				if (dig == '9')
+					goto round_9_up;
+				if (j > 0)
+					dig++;
+#ifdef SET_INEXACT
+				else if (!b->x[0] && b->wds <= 1)
+					inexact = 0;
+#endif
+				*s++ = dig;
+				goto ret;
+				}
+#endif
+			if (j < 0 || (j == 0 && mode != 1
+#ifndef ROUND_BIASED
+							&& !(word1(&d) & 1)
+#endif
+					)) {
+				if (!b->x[0] && b->wds <= 1) {
+#ifdef SET_INEXACT
+					inexact = 0;
+#endif
+					goto accept_dig;
+					}
+#ifdef Honor_FLT_ROUNDS
+				if (mode > 1)
+				 switch(Rounding) {
+				  case 0: goto accept_dig;
+				  case 2: goto keep_dig;
+				  }
+#endif /*Honor_FLT_ROUNDS*/
+				if (j1 > 0) {
+					b = lshift(b, 1);
+					if (b == NULL)
+						return (NULL);
+					j1 = cmp(b, S);
+#ifdef ROUND_BIASED
+					if (j1 >= 0 /*)*/
+#else
+					if ((j1 > 0 || (j1 == 0 && dig & 1))
+#endif
+					&& dig++ == '9')
+						goto round_9_up;
+					}
+ accept_dig:
+				*s++ = dig;
+				goto ret;
+				}
+			if (j1 > 0) {
+#ifdef Honor_FLT_ROUNDS
+				if (!Rounding)
+					goto accept_dig;
+#endif
+				if (dig == '9') { /* possible if i == 1 */
+ round_9_up:
+					*s++ = '9';
+					goto roundoff;
+					}
+				*s++ = dig + 1;
+				goto ret;
+				}
+#ifdef Honor_FLT_ROUNDS
+ keep_dig:
+#endif
+			*s++ = dig;
+			if (i == ilim)
+				break;
+			b = multadd(b, 10, 0);
+			if (b == NULL)
+				return (NULL);
+			if (mlo == mhi) {
+				mlo = mhi = multadd(mhi, 10, 0);
+				if (mlo == NULL)
+					return (NULL);
+				}
+			else {
+				mlo = multadd(mlo, 10, 0);
+				if (mlo == NULL)
+					return (NULL);
+				mhi = multadd(mhi, 10, 0);
+				if (mhi == NULL)
+					return (NULL);
+				}
+			}
+		}
+	else
+		for(i = 1;; i++) {
+			*s++ = dig = quorem(b,S) + '0';
+			if (!b->x[0] && b->wds <= 1) {
+#ifdef SET_INEXACT
+				inexact = 0;
+#endif
+				goto ret;
+				}
+			if (i >= ilim)
+				break;
+			b = multadd(b, 10, 0);
+			if (b == NULL)
+				return (NULL);
+			}
+
+	/* Round off last digit */
+
+#ifdef Honor_FLT_ROUNDS
+	switch(Rounding) {
+	  case 0: goto trimzeros;
+	  case 2: goto roundoff;
+	  }
+#endif
+	b = lshift(b, 1);
+	if (b == NULL)
+		return (NULL);
+	j = cmp(b, S);
+#ifdef ROUND_BIASED
+	if (j >= 0)
+#else
+	if (j > 0 || (j == 0 && dig & 1))
+#endif
+		{
+ roundoff:
+		while(*--s == '9')
+			if (s == s0) {
+				k++;
+				*s++ = '1';
+				goto ret;
+				}
+		++*s++;
+		}
+	else {
+#ifdef Honor_FLT_ROUNDS
+ trimzeros:
+#endif
+		while(*--s == '0');
+		s++;
+		}
+ ret:
+	Bfree(S);
+	if (mhi) {
+		if (mlo && mlo != mhi)
+			Bfree(mlo);
+		Bfree(mhi);
+		}
+ ret1:
+#ifdef SET_INEXACT
+	if (inexact) {
+		if (!oldinexact) {
+			word0(&d) = Exp_1 + (70 << Exp_shift);
+			word1(&d) = 0;
+			dval(&d) += 1.;
+			}
+		}
+	else if (!oldinexact)
+		clear_inexact();
+#endif
+	Bfree(b);
+	*s = 0;
+	*decpt = k + 1;
+	if (rve)
+		*rve = s;
+	return s0;
+}
diff --git a/newlib/libc/stdlib/gdtoa-gdtoa.c b/newlib/libc/stdlib/gdtoa-gdtoa.c
new file mode 100644
index 000000000..feae5afa3
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-gdtoa.c
@@ -0,0 +1,830 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998, 1999 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include "gdtoaimp.h"
+
+ static Bigint *
+#ifdef KR_headers
+bitstob(bits, nbits, bbits) ULong *bits; int nbits; int *bbits;
+#else
+bitstob(ULong *bits, int nbits, int *bbits)
+#endif
+{
+	int i, k;
+	Bigint *b;
+	ULong *be, *x, *x0;
+
+	i = ULbits;
+	k = 0;
+	while(i < nbits) {
+		i <<= 1;
+		k++;
+		}
+#ifndef Pack_32
+	if (!k)
+		k = 1;
+#endif
+	b = Balloc(k);
+	if (b == NULL)
+		return (NULL);
+	be = bits + ((nbits - 1) >> kshift);
+	x = x0 = b->x;
+	do {
+		*x++ = *bits & ALL_ON;
+#ifdef Pack_16
+		*x++ = (*bits >> 16) & ALL_ON;
+#endif
+		} while(++bits <= be);
+	i = x - x0;
+	while(!x0[--i])
+		if (!i) {
+			b->wds = 0;
+			*bbits = 0;
+			goto ret;
+			}
+	b->wds = i + 1;
+	*bbits = i*ULbits + 32 - hi0bits(b->x[i]);
+ ret:
+	return b;
+	}
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ *	1. Rather than iterating, we use a simple numeric overestimate
+ *	   to determine k = floor(log10(d)).  We scale relevant
+ *	   quantities using O(log2(k)) rather than O(k) multiplications.
+ *	2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ *	   try to generate digits strictly left to right.  Instead, we
+ *	   compute with fewer bits and propagate the carry if necessary
+ *	   when rounding the final digit up.  This is often faster.
+ *	3. Under the assumption that input will be rounded nearest,
+ *	   mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ *	   That is, we allow equality in stopping tests when the
+ *	   round-nearest rule will give the same floating-point value
+ *	   as would satisfaction of the stopping test with strict
+ *	   inequality.
+ *	4. We remove common factors of powers of 2 from relevant
+ *	   quantities.
+ *	5. When converting floating-point integers less than 1e16,
+ *	   we use floating-point arithmetic rather than resorting
+ *	   to multiple-precision integers.
+ *	6. When asked to produce fewer than 15 digits, we first try
+ *	   to get by with floating-point arithmetic; we resort to
+ *	   multiple-precision integer arithmetic only if we cannot
+ *	   guarantee that the floating-point calculation has given
+ *	   the correctly rounded result.  For k requested digits and
+ *	   "uniformly" distributed input, the probability is
+ *	   something like 10^(k-15) that we must resort to the Long
+ *	   calculation.
+ */
+
+ char *
+gdtoa
+#ifdef KR_headers
+	(fpi, be, bits, kindp, mode, ndigits, decpt, rve)
+	FPI *fpi; int be; ULong *bits;
+	int *kindp, mode, ndigits, *decpt; char **rve;
+#else
+	(FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, int *decpt, char **rve)
+#endif
+{
+ /*	Arguments ndigits and decpt are similar to the second and third
+	arguments of ecvt and fcvt; trailing zeros are suppressed from
+	the returned string.  If not null, *rve is set to point
+	to the end of the return value.  If d is +-Infinity or NaN,
+	then *decpt is set to 9999.
+	be = exponent: value = (integer represented by bits) * (2 to the power of be).
+
+	mode:
+		0 ==> shortest string that yields d when read in
+			and rounded to nearest.
+		1 ==> like 0, but with Steele & White stopping rule;
+			e.g. with IEEE P754 arithmetic , mode 0 gives
+			1e23 whereas mode 1 gives 9.999999999999999e22.
+		2 ==> max(1,ndigits) significant digits.  This gives a
+			return value similar to that of ecvt, except
+			that trailing zeros are suppressed.
+		3 ==> through ndigits past the decimal point.  This
+			gives a return value similar to that from fcvt,
+			except that trailing zeros are suppressed, and
+			ndigits can be negative.
+		4-9 should give the same return values as 2-3, i.e.,
+			4 <= mode <= 9 ==> same return as mode
+			2 + (mode & 1).  These modes are mainly for
+			debugging; often they run slower but sometimes
+			faster than modes 2-3.
+		4,5,8,9 ==> left-to-right digit generation.
+		6-9 ==> don't try fast floating-point estimate
+			(if applicable).
+
+		Values of mode other than 0-9 are treated as mode 0.
+
+		Sufficient space is allocated to the return value
+		to hold the suppressed trailing zeros.
+	*/
+
+	int bbits, b2, b5, be0, dig, i, ieps, ilim, ilim0, ilim1, inex;
+	int j, j1, k, k0, k_check, kind, leftright, m2, m5, nbits;
+	int rdir, s2, s5, spec_case, try_quick;
+	Long L;
+	Bigint *b, *b1, *delta, *mlo, *mhi, *mhi1, *S;
+	double d2, ds;
+	char *s, *s0;
+	U d, eps;
+
+#ifndef MULTIPLE_THREADS
+	if (dtoa_result) {
+		freedtoa(dtoa_result);
+		dtoa_result = 0;
+		}
+#endif
+	inex = 0;
+	kind = *kindp &= ~STRTOG_Inexact;
+	switch(kind & STRTOG_Retmask) {
+	  case STRTOG_Zero:
+		goto ret_zero;
+	  case STRTOG_Normal:
+	  case STRTOG_Denormal:
+		break;
+	  case STRTOG_Infinite:
+		*decpt = -32768;
+		return nrv_alloc("Infinity", rve, 8);
+	  case STRTOG_NaN:
+		*decpt = -32768;
+		return nrv_alloc("NaN", rve, 3);
+	  default:
+		return 0;
+	  }
+	b = bitstob(bits, nbits = fpi->nbits, &bbits);
+	if (b == NULL)
+		return (NULL);
+	be0 = be;
+	if ( (i = trailz(b)) !=0) {
+		rshift(b, i);
+		be += i;
+		bbits -= i;
+		}
+	if (!b->wds) {
+		Bfree(b);
+ ret_zero:
+		*decpt = 1;
+		return nrv_alloc("0", rve, 1);
+		}
+
+	dval(&d) = b2d(b, &i);
+	i = be + bbits - 1;
+	word0(&d) &= Frac_mask1;
+	word0(&d) |= Exp_11;
+#ifdef IBM
+	if ( (j = 11 - hi0bits(word0(&d) & Frac_mask)) !=0)
+		dval(&d) /= 1 << j;
+#endif
+
+	/* log(x)	~=~ log(1.5) + (x-1.5)/1.5
+	 * log10(x)	 =  log(x) / log(10)
+	 *		~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+	 * log10(&d) = (i-Bias)*log(2)/log(10) + log10(d2)
+	 *
+	 * This suggests computing an approximation k to log10(&d) by
+	 *
+	 * k = (i - Bias)*0.301029995663981
+	 *	+ ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+	 *
+	 * We want k to be too large rather than too small.
+	 * The error in the first-order Taylor series approximation
+	 * is in our favor, so we just round up the constant enough
+	 * to compensate for any error in the multiplication of
+	 * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+	 * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+	 * adding 1e-13 to the constant term more than suffices.
+	 * Hence we adjust the constant term to 0.1760912590558.
+	 * (We could get a more accurate k by invoking log10,
+	 *  but this is probably not worthwhile.)
+	 */
+#ifdef IBM
+	i <<= 2;
+	i += j;
+#endif
+	ds = (dval(&d)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
+
+	/* correct assumption about exponent range */
+	if ((j = i) < 0)
+		j = -j;
+	if ((j -= 1077) > 0)
+		ds += j * 7e-17;
+
+	k = (int)ds;
+	if (ds < 0. && ds != k)
+		k--;	/* want k = floor(ds) */
+	k_check = 1;
+#ifdef IBM
+	j = be + bbits - 1;
+	if ( (j1 = j & 3) !=0)
+		dval(&d) *= 1 << j1;
+	word0(&d) += j << Exp_shift - 2 & Exp_mask;
+#else
+	word0(&d) += (be + bbits - 1) << Exp_shift;
+#endif
+	if (k >= 0 && k <= Ten_pmax) {
+		if (dval(&d) < tens[k])
+			k--;
+		k_check = 0;
+		}
+	j = bbits - i - 1;
+	if (j >= 0) {
+		b2 = 0;
+		s2 = j;
+		}
+	else {
+		b2 = -j;
+		s2 = 0;
+		}
+	if (k >= 0) {
+		b5 = 0;
+		s5 = k;
+		s2 += k;
+		}
+	else {
+		b2 -= k;
+		b5 = -k;
+		s5 = 0;
+		}
+	if (mode < 0 || mode > 9)
+		mode = 0;
+	try_quick = 1;
+	if (mode > 5) {
+		mode -= 4;
+		try_quick = 0;
+		}
+	else if (i >= -4 - Emin || i < Emin)
+		try_quick = 0;
+	leftright = 1;
+	ilim = ilim1 = -1;	/* Values for cases 0 and 1; done here to */
+				/* silence erroneous "gcc -Wall" warning. */
+	switch(mode) {
+		case 0:
+		case 1:
+			i = (int)(nbits * .30103) + 3;
+			ndigits = 0;
+			break;
+		case 2:
+			leftright = 0;
+			/* no break */
+		case 4:
+			if (ndigits <= 0)
+				ndigits = 1;
+			ilim = ilim1 = i = ndigits;
+			break;
+		case 3:
+			leftright = 0;
+			/* no break */
+		case 5:
+			i = ndigits + k + 1;
+			ilim = i;
+			ilim1 = i - 1;
+			if (i <= 0)
+				i = 1;
+		}
+	s = s0 = rv_alloc(i);
+	if (s == NULL)
+		return (NULL);
+
+	if ( (rdir = fpi->rounding - 1) !=0) {
+		if (rdir < 0)
+			rdir = 2;
+		if (kind & STRTOG_Neg)
+			rdir = 3 - rdir;
+		}
+
+	/* Now rdir = 0 ==> round near, 1 ==> round up, 2 ==> round down. */
+
+	if (ilim >= 0 && ilim <= Quick_max && try_quick && !rdir
+#ifndef IMPRECISE_INEXACT
+		&& k == 0
+#endif
+								) {
+
+		/* Try to get by with floating-point arithmetic. */
+
+		i = 0;
+		d2 = dval(&d);
+#ifdef IBM
+		if ( (j = 11 - hi0bits(word0(&d) & Frac_mask)) !=0)
+			dval(&d) /= 1 << j;
+#endif
+		k0 = k;
+		ilim0 = ilim;
+		ieps = 2; /* conservative */
+		if (k > 0) {
+			ds = tens[k&0xf];
+			j = k >> 4;
+			if (j & Bletch) {
+				/* prevent overflows */
+				j &= Bletch - 1;
+				dval(&d) /= bigtens[n_bigtens-1];
+				ieps++;
+				}
+			for(; j; j >>= 1, i++)
+				if (j & 1) {
+					ieps++;
+					ds *= bigtens[i];
+					}
+			}
+		else  {
+			ds = 1.;
+			if ( (j1 = -k) !=0) {
+				dval(&d) *= tens[j1 & 0xf];
+				for(j = j1 >> 4; j; j >>= 1, i++)
+					if (j & 1) {
+						ieps++;
+						dval(&d) *= bigtens[i];
+						}
+				}
+			}
+		if (k_check && dval(&d) < 1. && ilim > 0) {
+			if (ilim1 <= 0)
+				goto fast_failed;
+			ilim = ilim1;
+			k--;
+			dval(&d) *= 10.;
+			ieps++;
+			}
+		dval(&eps) = ieps*dval(&d) + 7.;
+		word0(&eps) -= (P-1)*Exp_msk1;
+		if (ilim == 0) {
+			S = mhi = 0;
+			dval(&d) -= 5.;
+			if (dval(&d) > dval(&eps))
+				goto one_digit;
+			if (dval(&d) < -dval(&eps))
+				goto no_digits;
+			goto fast_failed;
+			}
+#ifndef No_leftright
+		if (leftright) {
+			/* Use Steele & White method of only
+			 * generating digits needed.
+			 */
+			dval(&eps) = ds*0.5/tens[ilim-1] - dval(&eps);
+			for(i = 0;;) {
+				L = (Long)(dval(&d)/ds);
+				dval(&d) -= L*ds;
+				*s++ = '0' + (int)L;
+				if (dval(&d) < dval(&eps)) {
+					if (dval(&d))
+						inex = STRTOG_Inexlo;
+					goto ret1;
+					}
+				if (ds - dval(&d) < dval(&eps))
+					goto bump_up;
+				if (++i >= ilim)
+					break;
+				dval(&eps) *= 10.;
+				dval(&d) *= 10.;
+				}
+			}
+		else {
+#endif
+			/* Generate ilim digits, then fix them up. */
+			dval(&eps) *= tens[ilim-1];
+			for(i = 1;; i++, dval(&d) *= 10.) {
+				if ( (L = (Long)(dval(&d)/ds)) !=0)
+					dval(&d) -= L*ds;
+				*s++ = '0' + (int)L;
+				if (i == ilim) {
+					ds *= 0.5;
+					if (dval(&d) > ds + dval(&eps))
+						goto bump_up;
+					else if (dval(&d) < ds - dval(&eps)) {
+						if (dval(&d))
+							inex = STRTOG_Inexlo;
+						goto clear_trailing0;
+						}
+					break;
+					}
+				}
+#ifndef No_leftright
+			}
+#endif
+ fast_failed:
+		s = s0;
+		dval(&d) = d2;
+		k = k0;
+		ilim = ilim0;
+		}
+
+	/* Do we have a "small" integer? */
+
+	if (be >= 0 && k <= Int_max) {
+		/* Yes. */
+		ds = tens[k];
+		if (ndigits < 0 && ilim <= 0) {
+			S = mhi = 0;
+			if (ilim < 0 || dval(&d) <= 5*ds)
+				goto no_digits;
+			goto one_digit;
+			}
+		for(i = 1;; i++, dval(&d) *= 10.) {
+			L = dval(&d) / ds;
+			dval(&d) -= L*ds;
+#ifdef Check_FLT_ROUNDS
+			/* If FLT_ROUNDS == 2, L will usually be high by 1 */
+			if (dval(&d) < 0) {
+				L--;
+				dval(&d) += ds;
+				}
+#endif
+			*s++ = '0' + (int)L;
+			if (dval(&d) == 0.)
+				break;
+			if (i == ilim) {
+				if (rdir) {
+					if (rdir == 1)
+						goto bump_up;
+					inex = STRTOG_Inexlo;
+					goto ret1;
+					}
+				dval(&d) += dval(&d);
+#ifdef ROUND_BIASED
+				if (dval(&d) >= ds)
+#else
+				if (dval(&d) > ds || (dval(&d) == ds && L & 1))
+#endif
+					{
+ bump_up:
+					inex = STRTOG_Inexhi;
+					while(*--s == '9')
+						if (s == s0) {
+							k++;
+							*s = '0';
+							break;
+							}
+					++*s++;
+					}
+				else {
+					inex = STRTOG_Inexlo;
+ clear_trailing0:
+					while(*--s == '0'){}
+					++s;
+					}
+				break;
+				}
+			}
+		goto ret1;
+		}
+
+	m2 = b2;
+	m5 = b5;
+	mhi = mlo = 0;
+	if (leftright) {
+		i = nbits - bbits;
+		if (be - i++ < fpi->emin && mode != 3 && mode != 5) {
+			/* denormal */
+			i = be - fpi->emin + 1;
+			if (mode >= 2 && ilim > 0 && ilim < i)
+				goto small_ilim;
+			}
+		else if (mode >= 2) {
+ small_ilim:
+			j = ilim - 1;
+			if (m5 >= j)
+				m5 -= j;
+			else {
+				s5 += j -= m5;
+				b5 += j;
+				m5 = 0;
+				}
+			if ((i = ilim) < 0) {
+				m2 -= i;
+				i = 0;
+				}
+			}
+		b2 += i;
+		s2 += i;
+		mhi = i2b(1);
+		if (mhi == NULL)
+			return (NULL);
+		}
+	if (m2 > 0 && s2 > 0) {
+		i = m2 < s2 ? m2 : s2;
+		b2 -= i;
+		m2 -= i;
+		s2 -= i;
+		}
+	if (b5 > 0) {
+		if (leftright) {
+			if (m5 > 0) {
+				mhi = pow5mult(mhi, m5);
+				if (mhi == NULL)
+					return (NULL);
+				b1 = mult(mhi, b);
+				if (b1 == NULL)
+					return (NULL);
+				Bfree(b);
+				b = b1;
+				}
+			if ( (j = b5 - m5) !=0) {
+				b = pow5mult(b, j);
+				if (b == NULL)
+					return (NULL);
+				}
+			}
+		else {
+			b = pow5mult(b, b5);
+			if (b == NULL)
+				return (NULL);
+			}
+		}
+	S = i2b(1);
+	if (S == NULL)
+		return (NULL);
+	if (s5 > 0) {
+		S = pow5mult(S, s5);
+		if (S == NULL)
+			return (NULL);
+		}
+
+	/* Check for special case that d is a normalized power of 2. */
+
+	spec_case = 0;
+	if (mode < 2) {
+		if (bbits == 1 && be0 > fpi->emin + 1) {
+			/* The special case */
+			b2++;
+			s2++;
+			spec_case = 1;
+			}
+		}
+
+	/* Arrange for convenient computation of quotients:
+	 * shift left if necessary so divisor has 4 leading 0 bits.
+	 *
+	 * Perhaps we should just compute leading 28 bits of S once
+	 * and for all and pass them and a shift to quorem, so it
+	 * can do shifts and ors to compute the numerator for q.
+	 */
+	i = ((s5 ? hi0bits(S->x[S->wds-1]) : ULbits - 1) - s2 - 4) & kmask;
+	m2 += i;
+	if ((b2 += i) > 0) {
+		b = lshift(b, b2);
+		if (b == NULL)
+			return (NULL);
+		}
+	if ((s2 += i) > 0) {
+		S = lshift(S, s2);
+		if (S == NULL)
+			return (NULL);
+		}
+	if (k_check) {
+		if (cmp(b,S) < 0) {
+			k--;
+			b = multadd(b, 10, 0);	/* we botched the k estimate */
+			if (b == NULL)
+				return (NULL);
+			if (leftright) {
+				mhi = multadd(mhi, 10, 0);
+				if (mhi == NULL)
+					return (NULL);
+				}
+			ilim = ilim1;
+			}
+		}
+	if (ilim <= 0 && mode > 2) {
+		S = multadd(S,5,0);
+		if (S == NULL)
+			return (NULL);
+		if (ilim < 0 || cmp(b,S) <= 0) {
+			/* no digits, fcvt style */
+ no_digits:
+			k = -1 - ndigits;
+			inex = STRTOG_Inexlo;
+			goto ret;
+			}
+ one_digit:
+		inex = STRTOG_Inexhi;
+		*s++ = '1';
+		k++;
+		goto ret;
+		}
+	if (leftright) {
+		if (m2 > 0) {
+			mhi = lshift(mhi, m2);
+			if (mhi == NULL)
+				return (NULL);
+			}
+
+		/* Compute mlo -- check for special case
+		 * that d is a normalized power of 2.
+		 */
+
+		mlo = mhi;
+		if (spec_case) {
+			mhi = Balloc(mhi->k);
+			if (mhi == NULL)
+				return (NULL);
+			Bcopy(mhi, mlo);
+			mhi = lshift(mhi, 1);
+			if (mhi == NULL)
+				return (NULL);
+			}
+
+		for(i = 1;;i++) {
+			dig = quorem(b,S) + '0';
+			/* Do we yet have the shortest decimal string
+			 * that will round to d?
+			 */
+			j = cmp(b, mlo);
+			delta = diff(S, mhi);
+			if (delta == NULL)
+				return (NULL);
+			j1 = delta->sign ? 1 : cmp(b, delta);
+			Bfree(delta);
+#ifndef ROUND_BIASED
+			if (j1 == 0 && !mode && !(bits[0] & 1) && !rdir) {
+				if (dig == '9')
+					goto round_9_up;
+				if (j <= 0) {
+					if (b->wds > 1 || b->x[0])
+						inex = STRTOG_Inexlo;
+					}
+				else {
+					dig++;
+					inex = STRTOG_Inexhi;
+					}
+				*s++ = dig;
+				goto ret;
+				}
+#endif
+			if (j < 0 || (j == 0 && !mode
+#ifndef ROUND_BIASED
+							&& !(bits[0] & 1)
+#endif
+					)) {
+				if (rdir && (b->wds > 1 || b->x[0])) {
+					if (rdir == 2) {
+						inex = STRTOG_Inexlo;
+						goto accept;
+						}
+					while (cmp(S,mhi) > 0) {
+						*s++ = dig;
+						mhi1 = multadd(mhi, 10, 0);
+						if (mhi1 == NULL)
+							return (NULL);
+						if (mlo == mhi)
+							mlo = mhi1;
+						mhi = mhi1;
+						b = multadd(b, 10, 0);
+						if (b == NULL)
+							return (NULL);
+						dig = quorem(b,S) + '0';
+						}
+					if (dig++ == '9')
+						goto round_9_up;
+					inex = STRTOG_Inexhi;
+					goto accept;
+					}
+				if (j1 > 0) {
+					b = lshift(b, 1);
+					if (b == NULL)
+						return (NULL);
+					j1 = cmp(b, S);
+#ifdef ROUND_BIASED
+					if (j1 >= 0 /*)*/
+#else
+					if ((j1 > 0 || (j1 == 0 && dig & 1))
+#endif
+					&& dig++ == '9')
+						goto round_9_up;
+					inex = STRTOG_Inexhi;
+					}
+				if (b->wds > 1 || b->x[0])
+					inex = STRTOG_Inexlo;
+ accept:
+				*s++ = dig;
+				goto ret;
+				}
+			if (j1 > 0 && rdir != 2) {
+				if (dig == '9') { /* possible if i == 1 */
+ round_9_up:
+					*s++ = '9';
+					inex = STRTOG_Inexhi;
+					goto roundoff;
+					}
+				inex = STRTOG_Inexhi;
+				*s++ = dig + 1;
+				goto ret;
+				}
+			*s++ = dig;
+			if (i == ilim)
+				break;
+			b = multadd(b, 10, 0);
+			if (b == NULL)
+				return (NULL);
+			if (mlo == mhi) {
+				mlo = mhi = multadd(mhi, 10, 0);
+				if (mlo == NULL)
+					return (NULL);
+				}
+			else {
+				mlo = multadd(mlo, 10, 0);
+				if (mlo == NULL)
+					return (NULL);
+				mhi = multadd(mhi, 10, 0);
+				if (mhi == NULL)
+					return (NULL);
+				}
+			}
+		}
+	else
+		for(i = 1;; i++) {
+			*s++ = dig = quorem(b,S) + '0';
+			if (i >= ilim)
+				break;
+			b = multadd(b, 10, 0);
+			if (b == NULL)
+				return (NULL);
+			}
+
+	/* Round off last digit */
+
+	if (rdir) {
+		if (rdir == 2 || (b->wds <= 1 && !b->x[0]))
+			goto chopzeros;
+		goto roundoff;
+		}
+	b = lshift(b, 1);
+	if (b == NULL)
+		return (NULL);
+	j = cmp(b, S);
+#ifdef ROUND_BIASED
+	if (j >= 0)
+#else
+	if (j > 0 || (j == 0 && dig & 1))
+#endif
+		{
+ roundoff:
+		inex = STRTOG_Inexhi;
+		while(*--s == '9')
+			if (s == s0) {
+				k++;
+				*s++ = '1';
+				goto ret;
+				}
+		++*s++;
+		}
+	else {
+ chopzeros:
+		if (b->wds > 1 || b->x[0])
+			inex = STRTOG_Inexlo;
+		while(*--s == '0'){}
+		++s;
+		}
+ ret:
+	Bfree(S);
+	if (mhi) {
+		if (mlo && mlo != mhi)
+			Bfree(mlo);
+		Bfree(mhi);
+		}
+ ret1:
+	Bfree(b);
+	*s = 0;
+	*decpt = k + 1;
+	if (rve)
+		*rve = s;
+	*kindp |= inex;
+	return s0;
+	}
+DEF_STRONG(gdtoa);
diff --git a/newlib/libc/stdlib/gdtoa-gmisc.c b/newlib/libc/stdlib/gdtoa-gmisc.c
new file mode 100644
index 000000000..8270ef944
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-gmisc.c
@@ -0,0 +1,86 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include "gdtoaimp.h"
+
+ void
+#ifdef KR_headers
+rshift(b, k) Bigint *b; int k;
+#else
+rshift(Bigint *b, int k)
+#endif
+{
+	ULong *x, *x1, *xe, y;
+	int n;
+
+	x = x1 = b->x;
+	n = k >> kshift;
+	if (n < b->wds) {
+		xe = x + b->wds;
+		x += n;
+		if (k &= kmask) {
+			n = ULbits - k;
+			y = *x++ >> k;
+			while(x < xe) {
+				*x1++ = (y | (*x << n)) & ALL_ON;
+				y = *x++ >> k;
+				}
+			if ((*x1 = y) !=0)
+				x1++;
+			}
+		else
+			while(x < xe)
+				*x1++ = *x++;
+		}
+	if ((b->wds = x1 - b->x) == 0)
+		b->x[0] = 0;
+	}
+
+ int
+#ifdef KR_headers
+trailz(b) Bigint *b;
+#else
+trailz(Bigint *b)
+#endif
+{
+	ULong L, *x, *xe;
+	int n = 0;
+
+	x = b->x;
+	xe = x + b->wds;
+	for(n = 0; x < xe && !*x; x++)
+		n += ULbits;
+	if (x < xe) {
+		L = *x;
+		n += lo0bits(&L);
+		}
+	return n;
+	}
diff --git a/newlib/libc/stdlib/gdtoa-ldtoa.c b/newlib/libc/stdlib/gdtoa-ldtoa.c
new file mode 100644
index 000000000..7282e7a39
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-ldtoa.c
@@ -0,0 +1,124 @@
+/*	$OpenBSD: ldtoa.c,v 1.4 2016/03/09 16:28:47 deraadt Exp $	*/
+/*-
+ * Copyright (c) 2003 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <machine/ieee.h>
+#include <float.h>
+#include <stdint.h>
+#include <limits.h>
+#include <math.h>
+#include <stdlib.h>
+#include "gdtoaimp.h"
+
+#if (LDBL_MANT_DIG > DBL_MANT_DIG)
+
+/*
+ * ldtoa() is a wrapper for gdtoa() that makes it smell like dtoa(),
+ * except that the floating point argument is passed by reference.
+ * When dtoa() is passed a NaN or infinity, it sets expt to 9999.
+ * However, a long double could have a valid exponent of 9999, so we
+ * use INT_MAX in ldtoa() instead.
+ */
+char *
+__ldtoa(long double *ld, int mode, int ndigits, int *decpt, int *sign,
+    char **rve)
+{
+	FPI fpi = {
+		LDBL_MANT_DIG,			/* nbits */
+		LDBL_MIN_EXP - LDBL_MANT_DIG,	/* emin */
+		LDBL_MAX_EXP - LDBL_MANT_DIG,	/* emax */
+		FLT_ROUNDS,	       		/* rounding */
+#ifdef Sudden_Underflow	/* unused, but correct anyway */
+		1
+#else
+		0
+#endif
+	};
+	int be, kind;
+	char *ret;
+	struct ieee_ext *p = (struct ieee_ext *)ld;
+	uint32_t bits[(LDBL_MANT_DIG + 31) / 32];
+	void *vbits = bits;
+
+	/*
+	 * gdtoa doesn't know anything about the sign of the number, so
+	 * if the number is negative, we need to swap rounding modes of
+	 * 2 (upwards) and 3 (downwards).
+	 */
+	*sign = p->ext_sign;
+	fpi.rounding ^= (fpi.rounding >> 1) & p->ext_sign;
+
+	be = p->ext_exp - (LDBL_MAX_EXP - 1) - (LDBL_MANT_DIG - 1);
+	EXT_TO_ARRAY32(p, bits);
+
+	switch (fpclassify(*ld)) {
+	case FP_NORMAL:
+		kind = STRTOG_Normal;
+#ifdef EXT_IMPLICIT_NBIT
+		bits[LDBL_MANT_DIG / 32] |= 1 << ((LDBL_MANT_DIG - 1) % 32);
+#endif /* EXT_IMPLICIT_NBIT */
+		break;
+	case FP_ZERO:
+		kind = STRTOG_Zero;
+		break;
+	case FP_SUBNORMAL:
+		kind = STRTOG_Denormal;
+		be++;
+		break;
+	case FP_INFINITE:
+		kind = STRTOG_Infinite;
+		break;
+	case FP_NAN:
+		kind = STRTOG_NaN;
+		break;
+	default:
+		abort();
+	}
+
+	ret = gdtoa(&fpi, be, vbits, &kind, mode, ndigits, decpt, rve);
+	if (*decpt == -32768)
+		*decpt = INT_MAX;
+	return ret;
+}
+DEF_STRONG(__ldtoa);
+
+#else   /* (LDBL_MANT_DIG == DBL_MANT_DIG) */
+
+char *
+__ldtoa(long double *ld, int mode, int ndigits, int *decpt, int *sign,
+    char **rve)
+{
+	char *ret;
+
+	ret = dtoa((double)*ld, mode, ndigits, decpt, sign, rve);
+	if (*decpt == 9999)
+		*decpt = INT_MAX;
+	return ret;
+}
+DEF_STRONG(__ldtoa);
+
+#endif  /* (LDBL_MANT_DIG == DBL_MANT_DIG) */
diff --git a/newlib/libc/stdlib/gdtoa-misc.c b/newlib/libc/stdlib/gdtoa-misc.c
new file mode 100644
index 000000000..5d1e0ad69
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-misc.c
@@ -0,0 +1,912 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998, 1999 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include "gdtoaimp.h"
+
+ static Bigint *freelist[Kmax+1];
+#ifndef Omit_Private_Memory
+#ifndef PRIVATE_MEM
+#define PRIVATE_MEM 2304
+#endif
+#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double))
+static double private_mem[PRIVATE_mem], *pmem_next = private_mem;
+#endif
+
+#ifdef MULTIPLE_THREADS
+__LOCK_INIT(static, __dtoa_lock0);
+__LOCK_INIT(static, __dtoa_lock1);
+#endif
+
+ Bigint *
+Balloc
+#ifdef KR_headers
+	(k) int k;
+#else
+	(int k)
+#endif
+{
+	int x;
+	Bigint *rv;
+#ifndef Omit_Private_Memory
+	unsigned int len;
+#endif
+
+	ACQUIRE_DTOA_LOCK(0);
+	/* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */
+	/* but this case seems very unlikely. */
+	if (k <= Kmax && (rv = freelist[k]) !=0) {
+		freelist[k] = rv->next;
+		}
+	else {
+		x = 1 << k;
+#ifdef Omit_Private_Memory
+		rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong));
+		if (rv == NULL)
+			return (NULL);
+#else
+		len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1)
+			/sizeof(double);
+		if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem) {
+			rv = (Bigint*)pmem_next;
+			pmem_next += len;
+			}
+		else {
+			rv = (Bigint*)MALLOC(len*sizeof(double));
+			if (rv == NULL)
+				return (NULL);
+		}
+#endif
+		rv->k = k;
+		rv->maxwds = x;
+		}
+	FREE_DTOA_LOCK(0);
+	rv->sign = rv->wds = 0;
+	return rv;
+	}
+
+ void
+Bfree
+#ifdef KR_headers
+	(v) Bigint *v;
+#else
+	(Bigint *v)
+#endif
+{
+	if (v) {
+		if (v->k > Kmax)
+#ifdef FREE
+			FREE(v);
+#else
+			free(v);
+#endif
+		else {
+			ACQUIRE_DTOA_LOCK(0);
+			v->next = freelist[v->k];
+			freelist[v->k] = v;
+			FREE_DTOA_LOCK(0);
+			}
+		}
+	}
+
+ int
+lo0bits
+#ifdef KR_headers
+	(y) ULong *y;
+#else
+	(ULong *y)
+#endif
+{
+	int k;
+	ULong x = *y;
+
+	if (x & 7) {
+		if (x & 1)
+			return 0;
+		if (x & 2) {
+			*y = x >> 1;
+			return 1;
+			}
+		*y = x >> 2;
+		return 2;
+		}
+	k = 0;
+	if (!(x & 0xffff)) {
+		k = 16;
+		x >>= 16;
+		}
+	if (!(x & 0xff)) {
+		k += 8;
+		x >>= 8;
+		}
+	if (!(x & 0xf)) {
+		k += 4;
+		x >>= 4;
+		}
+	if (!(x & 0x3)) {
+		k += 2;
+		x >>= 2;
+		}
+	if (!(x & 1)) {
+		k++;
+		x >>= 1;
+		if (!x)
+			return 32;
+		}
+	*y = x;
+	return k;
+	}
+
+ Bigint *
+multadd
+#ifdef KR_headers
+	(b, m, a) Bigint *b; int m, a;
+#else
+	(Bigint *b, int m, int a)	/* multiply by m and add a */
+#endif
+{
+	int i, wds;
+#ifdef ULLong
+	ULong *x;
+	ULLong carry, y;
+#else
+	ULong carry, *x, y;
+#ifdef Pack_32
+	ULong xi, z;
+#endif
+#endif
+	Bigint *b1;
+
+	wds = b->wds;
+	x = b->x;
+	i = 0;
+	carry = a;
+	do {
+#ifdef ULLong
+		y = *x * (ULLong)m + carry;
+		carry = y >> 32;
+		*x++ = y & 0xffffffffUL;
+#else
+#ifdef Pack_32
+		xi = *x;
+		y = (xi & 0xffff) * m + carry;
+		z = (xi >> 16) * m + (y >> 16);
+		carry = z >> 16;
+		*x++ = (z << 16) + (y & 0xffff);
+#else
+		y = *x * m + carry;
+		carry = y >> 16;
+		*x++ = y & 0xffff;
+#endif
+#endif
+		}
+		while(++i < wds);
+	if (carry) {
+		if (wds >= b->maxwds) {
+			b1 = Balloc(b->k+1);
+			if (b1 == NULL)
+				return (NULL);
+			Bcopy(b1, b);
+			Bfree(b);
+			b = b1;
+			}
+		b->x[wds++] = carry;
+		b->wds = wds;
+		}
+	return b;
+	}
+
+ int
+hi0bits_D2A
+#ifdef KR_headers
+	(x) ULong x;
+#else
+	(ULong x)
+#endif
+{
+	int k = 0;
+
+	if (!(x & 0xffff0000)) {
+		k = 16;
+		x <<= 16;
+		}
+	if (!(x & 0xff000000)) {
+		k += 8;
+		x <<= 8;
+		}
+	if (!(x & 0xf0000000)) {
+		k += 4;
+		x <<= 4;
+		}
+	if (!(x & 0xc0000000)) {
+		k += 2;
+		x <<= 2;
+		}
+	if (!(x & 0x80000000)) {
+		k++;
+		if (!(x & 0x40000000))
+			return 32;
+		}
+	return k;
+	}
+
+ Bigint *
+i2b
+#ifdef KR_headers
+	(i) int i;
+#else
+	(int i)
+#endif
+{
+	Bigint *b;
+
+	b = Balloc(1);
+	if (b == NULL)
+		return (NULL);
+	b->x[0] = i;
+	b->wds = 1;
+	return b;
+	}
+
+ Bigint *
+mult
+#ifdef KR_headers
+	(a, b) Bigint *a, *b;
+#else
+	(Bigint *a, Bigint *b)
+#endif
+{
+	Bigint *c;
+	int k, wa, wb, wc;
+	ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0;
+	ULong y;
+#ifdef ULLong
+	ULLong carry, z;
+#else
+	ULong carry, z;
+#ifdef Pack_32
+	ULong z2;
+#endif
+#endif
+
+	if (a->wds < b->wds) {
+		c = a;
+		a = b;
+		b = c;
+		}
+	k = a->k;
+	wa = a->wds;
+	wb = b->wds;
+	wc = wa + wb;
+	if (wc > a->maxwds)
+		k++;
+	c = Balloc(k);
+	if (c == NULL)
+		return (NULL);
+	for(x = c->x, xa = x + wc; x < xa; x++)
+		*x = 0;
+	xa = a->x;
+	xae = xa + wa;
+	xb = b->x;
+	xbe = xb + wb;
+	xc0 = c->x;
+#ifdef ULLong
+	for(; xb < xbe; xc0++) {
+		if ( (y = *xb++) !=0) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			do {
+				z = *x++ * (ULLong)y + *xc + carry;
+				carry = z >> 32;
+				*xc++ = z & 0xffffffffUL;
+				}
+				while(x < xae);
+			*xc = carry;
+			}
+		}
+#else
+#ifdef Pack_32
+	for(; xb < xbe; xb++, xc0++) {
+		if ( (y = *xb & 0xffff) !=0) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			do {
+				z = (*x & 0xffff) * y + (*xc & 0xffff) + carry;
+				carry = z >> 16;
+				z2 = (*x++ >> 16) * y + (*xc >> 16) + carry;
+				carry = z2 >> 16;
+				Storeinc(xc, z2, z);
+				}
+				while(x < xae);
+			*xc = carry;
+			}
+		if ( (y = *xb >> 16) !=0) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			z2 = *xc;
+			do {
+				z = (*x & 0xffff) * y + (*xc >> 16) + carry;
+				carry = z >> 16;
+				Storeinc(xc, z, z2);
+				z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry;
+				carry = z2 >> 16;
+				}
+				while(x < xae);
+			*xc = z2;
+			}
+		}
+#else
+	for(; xb < xbe; xc0++) {
+		if ( (y = *xb++) !=0) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			do {
+				z = *x++ * y + *xc + carry;
+				carry = z >> 16;
+				*xc++ = z & 0xffff;
+				}
+				while(x < xae);
+			*xc = carry;
+			}
+		}
+#endif
+#endif
+	for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ;
+	c->wds = wc;
+	return c;
+	}
+
+ static Bigint *p5s;
+
+ Bigint *
+pow5mult
+#ifdef KR_headers
+	(b, k) Bigint *b; int k;
+#else
+	(Bigint *b, int k)
+#endif
+{
+	Bigint *b1, *p5, *p51;
+	int i;
+	static int p05[3] = { 5, 25, 125 };
+
+	if ( (i = k & 3) !=0) {
+		b = multadd(b, p05[i-1], 0);
+		if (b == NULL)
+			return (NULL);
+		}
+
+	if (!(k >>= 2))
+		return b;
+	if ((p5 = p5s) == 0) {
+		/* first time */
+#ifdef MULTIPLE_THREADS
+		ACQUIRE_DTOA_LOCK(1);
+		if (!(p5 = p5s)) {
+			p5 = p5s = i2b(625);
+			if (p5 == NULL)
+				return (NULL);
+			p5->next = 0;
+			}
+		FREE_DTOA_LOCK(1);
+#else
+		p5 = p5s = i2b(625);
+		if (p5 == NULL)
+			return (NULL);
+		p5->next = 0;
+#endif
+		}
+	for(;;) {
+		if (k & 1) {
+			b1 = mult(b, p5);
+			if (b1 == NULL)
+				return (NULL);
+			Bfree(b);
+			b = b1;
+			}
+		if (!(k >>= 1))
+			break;
+		if ((p51 = p5->next) == 0) {
+#ifdef MULTIPLE_THREADS
+			ACQUIRE_DTOA_LOCK(1);
+			if (!(p51 = p5->next)) {
+				p51 = p5->next = mult(p5,p5);
+				if (p51 == NULL)
+					return (NULL);
+				p51->next = 0;
+				}
+			FREE_DTOA_LOCK(1);
+#else
+			p51 = p5->next = mult(p5,p5);
+			if (p51 == NULL)
+				return (NULL);
+			p51->next = 0;
+#endif
+			}
+		p5 = p51;
+		}
+	return b;
+	}
+
+ Bigint *
+lshift
+#ifdef KR_headers
+	(b, k) Bigint *b; int k;
+#else
+	(Bigint *b, int k)
+#endif
+{
+	int i, k1, n, n1;
+	Bigint *b1;
+	ULong *x, *x1, *xe, z;
+
+	n = k >> kshift;
+	k1 = b->k;
+	n1 = n + b->wds + 1;
+	for(i = b->maxwds; n1 > i; i <<= 1)
+		k1++;
+	b1 = Balloc(k1);
+	if (b1 == NULL)
+		return (NULL);
+	x1 = b1->x;
+	for(i = 0; i < n; i++)
+		*x1++ = 0;
+	x = b->x;
+	xe = x + b->wds;
+	if (k &= kmask) {
+#ifdef Pack_32
+		k1 = 32 - k;
+		z = 0;
+		do {
+			*x1++ = *x << k | z;
+			z = *x++ >> k1;
+			}
+			while(x < xe);
+		if ((*x1 = z) !=0)
+			++n1;
+#else
+		k1 = 16 - k;
+		z = 0;
+		do {
+			*x1++ = *x << k  & 0xffff | z;
+			z = *x++ >> k1;
+			}
+			while(x < xe);
+		if (*x1 = z)
+			++n1;
+#endif
+		}
+	else do
+		*x1++ = *x++;
+		while(x < xe);
+	b1->wds = n1 - 1;
+	Bfree(b);
+	return b1;
+	}
+
+ int
+cmp
+#ifdef KR_headers
+	(a, b) Bigint *a, *b;
+#else
+	(Bigint *a, Bigint *b)
+#endif
+{
+	ULong *xa, *xa0, *xb, *xb0;
+	int i, j;
+
+	i = a->wds;
+	j = b->wds;
+#ifdef DEBUG
+	if (i > 1 && !a->x[i-1])
+		Bug("cmp called with a->x[a->wds-1] == 0");
+	if (j > 1 && !b->x[j-1])
+		Bug("cmp called with b->x[b->wds-1] == 0");
+#endif
+	if (i -= j)
+		return i;
+	xa0 = a->x;
+	xa = xa0 + j;
+	xb0 = b->x;
+	xb = xb0 + j;
+	for(;;) {
+		if (*--xa != *--xb)
+			return *xa < *xb ? -1 : 1;
+		if (xa <= xa0)
+			break;
+		}
+	return 0;
+	}
+
+ Bigint *
+diff
+#ifdef KR_headers
+	(a, b) Bigint *a, *b;
+#else
+	(Bigint *a, Bigint *b)
+#endif
+{
+	Bigint *c;
+	int i, wa, wb;
+	ULong *xa, *xae, *xb, *xbe, *xc;
+#ifdef ULLong
+	ULLong borrow, y;
+#else
+	ULong borrow, y;
+#ifdef Pack_32
+	ULong z;
+#endif
+#endif
+
+	i = cmp(a,b);
+	if (!i) {
+		c = Balloc(0);
+		if (c == NULL)
+			return (NULL);
+		c->wds = 1;
+		c->x[0] = 0;
+		return c;
+		}
+	if (i < 0) {
+		c = a;
+		a = b;
+		b = c;
+		i = 1;
+		}
+	else
+		i = 0;
+	c = Balloc(a->k);
+	if (c == NULL)
+		return (NULL);
+	c->sign = i;
+	wa = a->wds;
+	xa = a->x;
+	xae = xa + wa;
+	wb = b->wds;
+	xb = b->x;
+	xbe = xb + wb;
+	xc = c->x;
+	borrow = 0;
+#ifdef ULLong
+	do {
+		y = (ULLong)*xa++ - *xb++ - borrow;
+		borrow = y >> 32 & 1UL;
+		*xc++ = y & 0xffffffffUL;
+		}
+		while(xb < xbe);
+	while(xa < xae) {
+		y = *xa++ - borrow;
+		borrow = y >> 32 & 1UL;
+		*xc++ = y & 0xffffffffUL;
+		}
+#else
+#ifdef Pack_32
+	do {
+		y = (*xa & 0xffff) - (*xb & 0xffff) - borrow;
+		borrow = (y & 0x10000) >> 16;
+		z = (*xa++ >> 16) - (*xb++ >> 16) - borrow;
+		borrow = (z & 0x10000) >> 16;
+		Storeinc(xc, z, y);
+		}
+		while(xb < xbe);
+	while(xa < xae) {
+		y = (*xa & 0xffff) - borrow;
+		borrow = (y & 0x10000) >> 16;
+		z = (*xa++ >> 16) - borrow;
+		borrow = (z & 0x10000) >> 16;
+		Storeinc(xc, z, y);
+		}
+#else
+	do {
+		y = *xa++ - *xb++ - borrow;
+		borrow = (y & 0x10000) >> 16;
+		*xc++ = y & 0xffff;
+		}
+		while(xb < xbe);
+	while(xa < xae) {
+		y = *xa++ - borrow;
+		borrow = (y & 0x10000) >> 16;
+		*xc++ = y & 0xffff;
+		}
+#endif
+#endif
+	while(!*--xc)
+		wa--;
+	c->wds = wa;
+	return c;
+	}
+
+ double
+b2d
+#ifdef KR_headers
+	(a, e) Bigint *a; int *e;
+#else
+	(Bigint *a, int *e)
+#endif
+{
+	ULong *xa, *xa0, w, y, z;
+	int k;
+	U d;
+#ifdef VAX
+	ULong d0, d1;
+#else
+#define d0 word0(&d)
+#define d1 word1(&d)
+#endif
+
+	xa0 = a->x;
+	xa = xa0 + a->wds;
+	y = *--xa;
+#ifdef DEBUG
+	if (!y) Bug("zero y in b2d");
+#endif
+	k = hi0bits(y);
+	*e = 32 - k;
+#ifdef Pack_32
+	if (k < Ebits) {
+		d0 = Exp_1 | y >> (Ebits - k);
+		w = xa > xa0 ? *--xa : 0;
+		d1 = y << ((32-Ebits) + k) | w >> (Ebits - k);
+		goto ret_d;
+		}
+	z = xa > xa0 ? *--xa : 0;
+	if (k -= Ebits) {
+		d0 = Exp_1 | y << k | z >> (32 - k);
+		y = xa > xa0 ? *--xa : 0;
+		d1 = z << k | y >> (32 - k);
+		}
+	else {
+		d0 = Exp_1 | y;
+		d1 = z;
+		}
+#else
+	if (k < Ebits + 16) {
+		z = xa > xa0 ? *--xa : 0;
+		d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k;
+		w = xa > xa0 ? *--xa : 0;
+		y = xa > xa0 ? *--xa : 0;
+		d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k;
+		goto ret_d;
+		}
+	z = xa > xa0 ? *--xa : 0;
+	w = xa > xa0 ? *--xa : 0;
+	k -= Ebits + 16;
+	d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k;
+	y = xa > xa0 ? *--xa : 0;
+	d1 = w << k + 16 | y << k;
+#endif
+ ret_d:
+#ifdef VAX
+	word0(&d) = d0 >> 16 | d0 << 16;
+	word1(&d) = d1 >> 16 | d1 << 16;
+#endif
+	return dval(&d);
+	}
+#undef d0
+#undef d1
+
+ Bigint *
+d2b
+#ifdef KR_headers
+	(dd, e, bits) double dd; int *e, *bits;
+#else
+	(double dd, int *e, int *bits)
+#endif
+{
+	Bigint *b;
+	U d;
+#ifndef Sudden_Underflow
+	int i;
+#endif
+	int de, k;
+	ULong *x, y, z;
+#ifdef VAX
+	ULong d0, d1;
+#else
+#define d0 word0(&d)
+#define d1 word1(&d)
+#endif
+	d.d = dd;
+#ifdef VAX
+	d0 = word0(&d) >> 16 | word0(&d) << 16;
+	d1 = word1(&d) >> 16 | word1(&d) << 16;
+#endif
+
+#ifdef Pack_32
+	b = Balloc(1);
+#else
+	b = Balloc(2);
+#endif
+	if (b == NULL)
+		return (NULL);
+	x = b->x;
+
+	z = d0 & Frac_mask;
+	d0 &= 0x7fffffff;	/* clear sign bit, which we ignore */
+#ifdef Sudden_Underflow
+	de = (int)(d0 >> Exp_shift);
+#ifndef IBM
+	z |= Exp_msk11;
+#endif
+#else
+	if ( (de = (int)(d0 >> Exp_shift)) !=0)
+		z |= Exp_msk1;
+#endif
+#ifdef Pack_32
+	if ( (y = d1) !=0) {
+		if ( (k = lo0bits(&y)) !=0) {
+			x[0] = y | z << (32 - k);
+			z >>= k;
+			}
+		else
+			x[0] = y;
+#ifndef Sudden_Underflow
+		i =
+#endif
+		     b->wds = (x[1] = z) !=0 ? 2 : 1;
+		}
+	else {
+		k = lo0bits(&z);
+		x[0] = z;
+#ifndef Sudden_Underflow
+		i =
+#endif
+		    b->wds = 1;
+		k += 32;
+		}
+#else
+	if ( (y = d1) !=0) {
+		if ( (k = lo0bits(&y)) !=0)
+			if (k >= 16) {
+				x[0] = y | z << 32 - k & 0xffff;
+				x[1] = z >> k - 16 & 0xffff;
+				x[2] = z >> k;
+				i = 2;
+				}
+			else {
+				x[0] = y & 0xffff;
+				x[1] = y >> 16 | z << 16 - k & 0xffff;
+				x[2] = z >> k & 0xffff;
+				x[3] = z >> k+16;
+				i = 3;
+				}
+		else {
+			x[0] = y & 0xffff;
+			x[1] = y >> 16;
+			x[2] = z & 0xffff;
+			x[3] = z >> 16;
+			i = 3;
+			}
+		}
+	else {
+#ifdef DEBUG
+		if (!z)
+			Bug("Zero passed to d2b");
+#endif
+		k = lo0bits(&z);
+		if (k >= 16) {
+			x[0] = z;
+			i = 0;
+			}
+		else {
+			x[0] = z & 0xffff;
+			x[1] = z >> 16;
+			i = 1;
+			}
+		k += 32;
+		}
+	while(!x[i])
+		--i;
+	b->wds = i + 1;
+#endif
+#ifndef Sudden_Underflow
+	if (de) {
+#endif
+#ifdef IBM
+		*e = (de - Bias - (P-1) << 2) + k;
+		*bits = 4*P + 8 - k - hi0bits(word0(&d) & Frac_mask);
+#else
+		*e = de - Bias - (P-1) + k;
+		*bits = P - k;
+#endif
+#ifndef Sudden_Underflow
+		}
+	else {
+		*e = de - Bias - (P-1) + 1 + k;
+#ifdef Pack_32
+		*bits = 32*i - hi0bits(x[i-1]);
+#else
+		*bits = (i+2)*16 - hi0bits(x[i]);
+#endif
+		}
+#endif
+	return b;
+	}
+#undef d0
+#undef d1
+
+ CONST double
+#ifdef IEEE_Arith
+bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };
+CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, 1e-256
+		};
+#else
+#ifdef IBM
+bigtens[] = { 1e16, 1e32, 1e64 };
+CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 };
+#else
+bigtens[] = { 1e16, 1e32 };
+CONST double tinytens[] = { 1e-16, 1e-32 };
+#endif
+#endif
+
+ CONST double
+tens[] = {
+		1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+		1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+		1e20, 1e21, 1e22
+#ifdef VAX
+		, 1e23, 1e24
+#endif
+		};
+
+#ifdef NO_STRING_H
+
+ char *
+#ifdef KR_headers
+strcp_D2A(a, b) char *a; char *b;
+#else
+strcp_D2A(char *a, CONST char *b)
+#endif
+{
+	while((*a = *b++))
+		a++;
+	return a;
+	}
+
+ Char *
+#ifdef KR_headers
+memcpy_D2A(a, b, len) Char *a; Char *b; size_t len;
+#else
+memcpy_D2A(void *a1, void *b1, size_t len)
+#endif
+{
+	char *a = (char*)a1, *ae = a + len;
+	char *b = (char*)b1, *a0 = a;
+	while(a < ae)
+		*a++ = *b++;
+	return a0;
+	}
+
+#endif /* NO_STRING_H */
diff --git a/newlib/libc/stdlib/gdtoa.h b/newlib/libc/stdlib/gdtoa.h
index 07506aac1..4f26d8857 100644
--- a/newlib/libc/stdlib/gdtoa.h
+++ b/newlib/libc/stdlib/gdtoa.h
@@ -32,25 +32,61 @@ THIS SOFTWARE.
 #ifndef GDTOA_H_INCLUDED
 #define GDTOA_H_INCLUDED
 
+#include "arith.h"
+#include <stddef.h> /* for size_t */
+
+#define PROTO_NORMAL(x)
+#define __BEGIN_HIDDEN_DECLS
+#define __END_HIDDEN_DECLS
+#define DEF_STRONG(x)
+
+#ifndef Long
+#define Long int
+#endif
+#ifndef ULong
+typedef unsigned Long ULong;
+#endif
+#ifndef UShort
+typedef unsigned short UShort;
+#endif
+
+#ifndef ANSI
+#ifdef KR_headers
+#define ANSI(x) ()
+#define Void /*nothing*/
+#else
+#define ANSI(x) x
+#define Void void
+#endif
+#endif /* ANSI */
+
+#ifndef CONST
+#ifdef KR_headers
+#define CONST /* blank */
+#else
+#define CONST const
+#endif
+#endif /* CONST */
 
  enum {	/* return values from strtodg */
-	STRTOG_Zero	= 0,
-	STRTOG_Normal	= 1,
-	STRTOG_Denormal	= 2,
-	STRTOG_Infinite	= 3,
-	STRTOG_NaN	= 4,
-	STRTOG_NaNbits	= 5,
-	STRTOG_NoNumber	= 6,
-	STRTOG_Retmask	= 7,
+	STRTOG_Zero	= 0x000,
+	STRTOG_Normal	= 0x001,
+	STRTOG_Denormal	= 0x002,
+	STRTOG_Infinite	= 0x003,
+	STRTOG_NaN	= 0x004,
+	STRTOG_NaNbits	= 0x005,
+	STRTOG_NoNumber	= 0x006,
+	STRTOG_NoMemory = 0x007,
+	STRTOG_Retmask	= 0x00f,
 
 	/* The following may be or-ed into one of the above values. */
 
-	STRTOG_Neg	= 0x08,
-	STRTOG_Inexlo	= 0x10,
-	STRTOG_Inexhi	= 0x20,
-	STRTOG_Inexact	= 0x30,
-	STRTOG_Underflow= 0x40,
-	STRTOG_Overflow	= 0x80
+	STRTOG_Inexlo	= 0x010, /* returned result rounded toward zero */
+	STRTOG_Inexhi	= 0x020, /* returned result rounded away from zero */
+	STRTOG_Inexact	= 0x030,
+	STRTOG_Underflow= 0x040,
+	STRTOG_Overflow	= 0x080,
+	STRTOG_Neg	= 0x100 /* does not affect STRTOG_Inexlo or STRTOG_Inexhi */
 	};
 
  typedef struct
@@ -69,6 +105,70 @@ enum {	/* FPI.rounding values: same as FLT_ROUNDS */
 	FPI_Round_down = 3
 	};
 
-#endif /* GDTOA_H_INCLUDED */
-
 typedef unsigned short __UShort;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char* __dtoa  ANSI((double d, int mode, int ndigits, int *decpt,
+			int *sign, char **rve));
+extern char* __gdtoa ANSI((FPI *fpi, int be, ULong *bits, int *kindp,
+			int mode, int ndigits, int *decpt, char **rve));
+extern void __freedtoa ANSI((char*));
+extern float  strtof ANSI((CONST char *, char **));
+extern double strtod ANSI((CONST char *, char **));
+extern int __strtodg ANSI((CONST char*, char**, FPI*, Long*, ULong*));
+char	*__hdtoa(double, const char *, int, int *, int *, char **);
+char	*__hldtoa(long double, const char *, int, int *, int *, char **);
+char	*__ldtoa(long double *, int, int, int *, int *, char **);
+
+PROTO_NORMAL(__dtoa);
+PROTO_NORMAL(__gdtoa);
+PROTO_NORMAL(__freedtoa);
+PROTO_NORMAL(__hdtoa);
+PROTO_NORMAL(__hldtoa);
+PROTO_NORMAL(__ldtoa);
+
+__BEGIN_HIDDEN_DECLS
+extern char*	__g_ddfmt  ANSI((char*, double*, int, size_t));
+extern char*	__g_dfmt   ANSI((char*, double*, int, size_t));
+extern char*	__g_ffmt   ANSI((char*, float*,  int, size_t));
+extern char*	__g_Qfmt   ANSI((char*, void*,   int, size_t));
+extern char*	__g_xfmt   ANSI((char*, void*,   int, size_t));
+extern char*	__g_xLfmt  ANSI((char*, void*,   int, size_t));
+
+extern int	__strtoId  ANSI((CONST char*, char**, double*, double*));
+extern int	__strtoIdd ANSI((CONST char*, char**, double*, double*));
+extern int	__strtoIf  ANSI((CONST char*, char**, float*, float*));
+extern int	__strtoIQ  ANSI((CONST char*, char**, void*, void*));
+extern int	__strtoIx  ANSI((CONST char*, char**, void*, void*));
+extern int	__strtoIxL ANSI((CONST char*, char**, void*, void*));
+extern int	__strtord  ANSI((CONST char*, char**, int, double*));
+extern int	__strtordd ANSI((CONST char*, char**, int, double*));
+extern int	__strtorf  ANSI((CONST char*, char**, int, float*));
+extern int	__strtorQ  ANSI((CONST char*, char**, int, void*));
+extern int	__strtorx  ANSI((CONST char*, char**, int, void*));
+extern int	__strtorxL ANSI((CONST char*, char**, int, void*));
+#if 1
+extern int	__strtodI  ANSI((CONST char*, char**, double*));
+extern int	__strtopd  ANSI((CONST char*, char**, double*));
+extern int	__strtopdd ANSI((CONST char*, char**, double*));
+extern int	__strtopf  ANSI((CONST char*, char**, float*));
+extern int	__strtopQ  ANSI((CONST char*, char**, void*));
+extern int	__strtopx  ANSI((CONST char*, char**, void*));
+extern int	__strtopxL ANSI((CONST char*, char**, void*));
+#else
+#define __strtopd(s,se,x) strtord(s,se,1,x)
+#define __strtopdd(s,se,x) strtordd(s,se,1,x)
+#define __strtopf(s,se,x) strtorf(s,se,1,x)
+#define __strtopQ(s,se,x) strtorQ(s,se,1,x)
+#define __strtopx(s,se,x) strtorx(s,se,1,x)
+#define __strtopxL(s,se,x) strtorxL(s,se,1,x)
+#endif
+__END_HIDDEN_DECLS
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* GDTOA_H_INCLUDED */
diff --git a/newlib/libc/stdlib/gdtoaimp.h b/newlib/libc/stdlib/gdtoaimp.h
new file mode 100644
index 000000000..bf9770955
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoaimp.h
@@ -0,0 +1,672 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998-2000 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* This is a variation on dtoa.c that converts arbitary binary
+   floating-point formats to and from decimal notation.  It uses
+   double-precision arithmetic internally, so there are still
+   various #ifdefs that adapt the calculations to the native
+   double-precision arithmetic (any of IEEE, VAX D_floating,
+   or IBM mainframe arithmetic).
+
+   Please send bug reports to David M. Gay (dmg at acm dot org,
+   with " at " changed at "@" and " dot " changed to ".").
+ */
+
+/* On a machine with IEEE extended-precision registers, it is
+ * necessary to specify double-precision (53-bit) rounding precision
+ * before invoking strtod or dtoa.  If the machine uses (the equivalent
+ * of) Intel 80x87 arithmetic, the call
+ *	_control87(PC_53, MCW_PC);
+ * does this with many compilers.  Whether this or another call is
+ * appropriate depends on the compiler; for this to work, it may be
+ * necessary to #include "float.h" or another system-dependent header
+ * file.
+ */
+
+/* strtod for IEEE-, VAX-, and IBM-arithmetic machines.
+ *
+ * This strtod returns a nearest machine number to the input decimal
+ * string (or sets errno to ERANGE).  With IEEE arithmetic, ties are
+ * broken by the IEEE round-even rule.  Otherwise ties are broken by
+ * biased rounding (add half and chop).
+ *
+ * Inspired loosely by William D. Clinger's paper "How to Read Floating
+ * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ *
+ *	1. We only require IEEE, IBM, or VAX double-precision
+ *		arithmetic (not IEEE double-extended).
+ *	2. We get by with floating-point arithmetic in a case that
+ *		Clinger missed -- when we're computing d * 10^n
+ *		for a small integer d and the integer n is not too
+ *		much larger than 22 (the maximum integer k for which
+ *		we can represent 10^k exactly), we may be able to
+ *		compute (d*10^k) * 10^(e-k) with just one roundoff.
+ *	3. Rather than a bit-at-a-time adjustment of the binary
+ *		result in the hard case, we use floating-point
+ *		arithmetic to determine the adjustment to within
+ *		one bit; only in really hard cases do we need to
+ *		compute a second residual.
+ *	4. Because of 3., we don't need a large table of powers of 10
+ *		for ten-to-e (just some small tables, e.g. of 10^k
+ *		for 0 <= k <= 22).
+ */
+
+/*
+ * #define IEEE_8087 for IEEE-arithmetic machines where the least
+ *	significant byte has the lowest address.
+ * #define IEEE_MC68k for IEEE-arithmetic machines where the most
+ *	significant byte has the lowest address.
+ * #define Long int on machines with 32-bit ints and 64-bit longs.
+ * #define Sudden_Underflow for IEEE-format machines without gradual
+ *	underflow (i.e., that flush to zero on underflow).
+ * #define IBM for IBM mainframe-style floating-point arithmetic.
+ * #define VAX for VAX-style floating-point arithmetic (D_floating).
+ * #define No_leftright to omit left-right logic in fast floating-point
+ *	computation of dtoa and gdtoa.  This will cause modes 4 and 5 to be
+ *	treated the same as modes 2 and 3 for some inputs.
+ * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3.
+ * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines
+ *	that use extended-precision instructions to compute rounded
+ *	products and quotients) with IBM.
+ * #define ROUND_BIASED for IEEE-format with biased rounding and arithmetic
+ *	that rounds toward +Infinity.
+ * #define ROUND_BIASED_without_Round_Up for IEEE-format with biased
+ *	rounding when the underlying floating-point arithmetic uses
+ *	unbiased rounding.  This prevent using ordinary floating-point
+ *	arithmetic when the result could be computed with one rounding error.
+ * #define Inaccurate_Divide for IEEE-format with correctly rounded
+ *	products but inaccurate quotients, e.g., for Intel i860.
+ * #define NO_LONG_LONG on machines that do not have a "long long"
+ *	integer type (of >= 64 bits).  On such machines, you can
+ *	#define Just_16 to store 16 bits per 32-bit Long when doing
+ *	high-precision integer arithmetic.  Whether this speeds things
+ *	up or slows things down depends on the machine and the number
+ *	being converted.  If long long is available and the name is
+ *	something other than "long long", #define Llong to be the name,
+ *	and if "unsigned Llong" does not work as an unsigned version of
+ *	Llong, #define #ULLong to be the corresponding unsigned type.
+ * #define KR_headers for old-style C function headers.
+ * #define Bad_float_h if your system lacks a float.h or if it does not
+ *	define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP,
+ *	FLT_RADIX, FLT_ROUNDS, and DBL_MAX.
+ * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n)
+ *	if memory is available and otherwise does something you deem
+ *	appropriate.  If MALLOC is undefined, malloc will be invoked
+ *	directly -- and assumed always to succeed.  Similarly, if you
+ *	want something other than the system's free() to be called to
+ *	recycle memory acquired from MALLOC, #define FREE to be the
+ *	name of the alternate routine.  (FREE or free is only called in
+ *	pathological cases, e.g., in a gdtoa call after a gdtoa return in
+ *	mode 3 with thousands of digits requested.)
+ * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making
+ *	memory allocations from a private pool of memory when possible.
+ *	When used, the private pool is PRIVATE_MEM bytes long:  2304 bytes,
+ *	unless #defined to be a different length.  This default length
+ *	suffices to get rid of MALLOC calls except for unusual cases,
+ *	such as decimal-to-binary conversion of a very long string of
+ *	digits.  When converting IEEE double precision values, the
+ *	longest string gdtoa can return is about 751 bytes long.  For
+ *	conversions by strtod of strings of 800 digits and all gdtoa
+ *	conversions of IEEE doubles in single-threaded executions with
+ *	8-byte pointers, PRIVATE_MEM >= 7400 appears to suffice; with
+ *	4-byte pointers, PRIVATE_MEM >= 7112 appears adequate.
+ * #define NO_INFNAN_CHECK if you do not wish to have INFNAN_CHECK
+ *	#defined automatically on IEEE systems.  On such systems,
+ *	when INFNAN_CHECK is #defined, strtod checks
+ *	for Infinity and NaN (case insensitively).
+ *	When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined,
+ *	strtodg also accepts (case insensitively) strings of the form
+ *	NaN(x), where x is a string of hexadecimal digits (optionally
+ *	preceded by 0x or 0X) and spaces; if there is only one string
+ *	of hexadecimal digits, it is taken for the fraction bits of the
+ *	resulting NaN; if there are two or more strings of hexadecimal
+ *	digits, each string is assigned to the next available sequence
+ *	of 32-bit words of fractions bits (starting with the most
+ *	significant), right-aligned in each sequence.
+ *	Unless GDTOA_NON_PEDANTIC_NANCHECK is #defined, input "NaN(...)"
+ *	is consumed even when ... has the wrong form (in which case the
+ *	"(...)" is consumed but ignored).
+ * #define MULTIPLE_THREADS if the system offers preemptively scheduled
+ *	multiple threads.  In this case, you must provide (or suitably
+ *	#define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed
+ *	by FREE_DTOA_LOCK(n) for n = 0 or 1.  (The second lock, accessed
+ *	in pow5mult, ensures lazy evaluation of only one copy of high
+ *	powers of 5; omitting this lock would introduce a small
+ *	probability of wasting memory, but would otherwise be harmless.)
+ *	You must also invoke freedtoa(s) to free the value s returned by
+ *	dtoa.  You may do so whether or not MULTIPLE_THREADS is #defined.
+ * #define IMPRECISE_INEXACT if you do not care about the setting of
+ *	the STRTOG_Inexact bits in the special case of doing IEEE double
+ *	precision conversions (which could also be done by the strtod in
+ *	dtoa.c).
+ * #define NO_HEX_FP to disable recognition of C9x's hexadecimal
+ *	floating-point constants.
+ * #define -DNO_ERRNO to suppress setting errno (in strtod.c and
+ *	strtodg.c).
+ * #define NO_STRING_H to use private versions of memcpy.
+ *	On some K&R systems, it may also be necessary to
+ *	#define DECLARE_SIZE_T in this case.
+ * #define USE_LOCALE to use the current locale's decimal_point value.
+ */
+
+#ifndef GDTOAIMP_H_INCLUDED
+#define GDTOAIMP_H_INCLUDED
+#include "gdtoa.h"
+#if 0
+#include "gd_qnan.h"
+#endif
+#ifdef Honor_FLT_ROUNDS
+#include <fenv.h>
+#endif
+
+#ifdef DEBUG
+#include "stdio.h"
+#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);}
+#endif
+
+#include "stdlib.h"
+#include "string.h"
+
+#ifdef KR_headers
+#define Char char
+#else
+#define Char void
+#endif
+
+#ifdef MALLOC
+extern Char *MALLOC ANSI((size_t));
+#else
+#define MALLOC(x) _malloc_r(_REENT, x)
+#endif
+#define FREE(x) _free_r(_REENT, x)
+
+#undef IEEE_Arith
+#undef Avoid_Underflow
+#ifdef IEEE_MC68k
+#define IEEE_Arith
+#endif
+#ifdef IEEE_8087
+#define IEEE_Arith
+#endif
+
+#include "errno.h"
+#ifdef Bad_float_h
+
+#ifdef IEEE_Arith
+#define DBL_DIG 15
+#define DBL_MAX_10_EXP 308
+#define DBL_MAX_EXP 1024
+#define FLT_RADIX 2
+#define DBL_MAX 1.7976931348623157e+308
+#endif
+
+#ifdef IBM
+#define DBL_DIG 16
+#define DBL_MAX_10_EXP 75
+#define DBL_MAX_EXP 63
+#define FLT_RADIX 16
+#define DBL_MAX 7.2370055773322621e+75
+#endif
+
+#ifdef VAX
+#define DBL_DIG 16
+#define DBL_MAX_10_EXP 38
+#define DBL_MAX_EXP 127
+#define FLT_RADIX 2
+#define DBL_MAX 1.7014118346046923e+38
+#define n_bigtens 2
+#endif
+
+#ifndef LONG_MAX
+#define LONG_MAX 2147483647
+#endif
+
+#else /* ifndef Bad_float_h */
+#include "float.h"
+#endif /* Bad_float_h */
+
+#ifdef IEEE_Arith
+#define Scale_Bit 0x10
+#define n_bigtens 5
+#endif
+
+#ifdef IBM
+#define n_bigtens 3
+#endif
+
+#ifdef VAX
+#define n_bigtens 2
+#endif
+
+#ifndef __MATH_H__
+#include "math.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1
+Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined.
+#endif
+
+typedef union { double d; ULong L[2]; } U;
+
+#ifdef IEEE_8087
+#define word0(x) (x)->L[1]
+#define word1(x) (x)->L[0]
+#else
+#define word0(x) (x)->L[0]
+#define word1(x) (x)->L[1]
+#endif
+#define dval(x) (x)->d
+
+/* The following definition of Storeinc is appropriate for MIPS processors.
+ * An alternative that might be better on some machines is
+ * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff)
+ */
+#if defined(IEEE_8087) + defined(VAX)
+#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \
+((unsigned short *)a)[0] = (unsigned short)c, a++)
+#else
+#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \
+((unsigned short *)a)[1] = (unsigned short)c, a++)
+#endif
+
+/* #define P DBL_MANT_DIG */
+/* Ten_pmax = floor(P*log(2)/log(5)) */
+/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */
+/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */
+/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */
+
+#ifdef IEEE_Arith
+#define Exp_shift  20
+#define Exp_shift1 20
+#define Exp_msk1    0x100000
+#define Exp_msk11   0x100000
+#define Exp_mask  0x7ff00000
+#define P 53
+#define Bias 1023
+#define Emin (-1022)
+#define Exp_1  0x3ff00000
+#define Exp_11 0x3ff00000
+#define Ebits 11
+#define Frac_mask  0xfffff
+#define Frac_mask1 0xfffff
+#define Ten_pmax 22
+#define Bletch 0x10
+#define Bndry_mask  0xfffff
+#define Bndry_mask1 0xfffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 1
+#define Tiny0 0
+#define Tiny1 1
+#define Quick_max 14
+#define Int_max 14
+
+#ifndef Flt_Rounds
+#ifdef FLT_ROUNDS
+#define Flt_Rounds FLT_ROUNDS
+#else
+#define Flt_Rounds 1
+#endif
+#endif /*Flt_Rounds*/
+
+#else /* ifndef IEEE_Arith */
+#undef  Sudden_Underflow
+#define Sudden_Underflow
+#ifdef IBM
+#undef Flt_Rounds
+#define Flt_Rounds 0
+#define Exp_shift  24
+#define Exp_shift1 24
+#define Exp_msk1   0x1000000
+#define Exp_msk11  0x1000000
+#define Exp_mask  0x7f000000
+#define P 14
+#define Bias 65
+#define Exp_1  0x41000000
+#define Exp_11 0x41000000
+#define Ebits 8	/* exponent has 7 bits, but 8 is the right value in b2d */
+#define Frac_mask  0xffffff
+#define Frac_mask1 0xffffff
+#define Bletch 4
+#define Ten_pmax 22
+#define Bndry_mask  0xefffff
+#define Bndry_mask1 0xffffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 4
+#define Tiny0 0x100000
+#define Tiny1 0
+#define Quick_max 14
+#define Int_max 15
+#else /* VAX */
+#undef Flt_Rounds
+#define Flt_Rounds 1
+#define Exp_shift  23
+#define Exp_shift1 7
+#define Exp_msk1    0x80
+#define Exp_msk11   0x800000
+#define Exp_mask  0x7f80
+#define P 56
+#define Bias 129
+#define Emin (-127)
+#define Exp_1  0x40800000
+#define Exp_11 0x4080
+#define Ebits 8
+#define Frac_mask  0x7fffff
+#define Frac_mask1 0xffff007f
+#define Ten_pmax 24
+#define Bletch 2
+#define Bndry_mask  0xffff007f
+#define Bndry_mask1 0xffff007f
+#define LSB 0x10000
+#define Sign_bit 0x8000
+#define Log2P 1
+#define Tiny0 0x80
+#define Tiny1 0
+#define Quick_max 15
+#define Int_max 15
+#endif /* IBM, VAX */
+#endif /* IEEE_Arith */
+
+#ifndef IEEE_Arith
+#define ROUND_BIASED
+#else
+#ifdef ROUND_BIASED_without_Round_Up
+#undef  ROUND_BIASED
+#define ROUND_BIASED
+#endif
+#endif
+
+#ifdef RND_PRODQUOT
+#define rounded_product(a,b) a = rnd_prod(a, b)
+#define rounded_quotient(a,b) a = rnd_quot(a, b)
+#ifdef KR_headers
+extern double rnd_prod(), rnd_quot();
+#else
+extern double rnd_prod(double, double), rnd_quot(double, double);
+#endif
+#else
+#define rounded_product(a,b) a *= b
+#define rounded_quotient(a,b) a /= b
+#endif
+
+#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1))
+#define Big1 0xffffffff
+
+#undef  Pack_16
+#ifndef Pack_32
+#define Pack_32
+#endif
+
+#ifdef NO_LONG_LONG
+#undef ULLong
+#ifdef Just_16
+#undef Pack_32
+#define Pack_16
+/* When Pack_32 is not defined, we store 16 bits per 32-bit Long.
+ * This makes some inner loops simpler and sometimes saves work
+ * during multiplications, but it often seems to make things slightly
+ * slower.  Hence the default is now to store 32 bits per Long.
+ */
+#endif
+#else	/* long long available */
+#ifndef Llong
+#define Llong long long
+#endif
+#ifndef ULLong
+#define ULLong unsigned Llong
+#endif
+#endif /* NO_LONG_LONG */
+
+#ifdef Pack_32
+#define ULbits 32
+#define kshift 5
+#define kmask 31
+#define ALL_ON 0xffffffff
+#else
+#define ULbits 16
+#define kshift 4
+#define kmask 15
+#define ALL_ON 0xffff
+#endif
+
+#ifndef __SINGLE_THREAD__
+#define MULTIPLE_THREADS
+#endif
+
+#ifndef MULTIPLE_THREADS
+#define ACQUIRE_DTOA_LOCK(n)	/*nothing*/
+#define FREE_DTOA_LOCK(n)	/*nothing*/
+#else
+#include <sys/lock.h>
+#define ACQUIRE_DTOA_LOCK(n) \
+	n ? __lock_acquire(__dtoa_lock1) : __lock_acquire(__dtoa_lock0)
+#define FREE_DTOA_LOCK(n) \
+	n ? __lock_release(__dtoa_lock1) : __lock_release(__dtoa_lock0)
+#endif
+
+#define Kmax 9
+
+ struct
+Bigint {
+	struct Bigint *next;
+	int k, maxwds, sign, wds;
+	ULong x[1];
+	};
+
+ typedef struct Bigint Bigint;
+
+#ifdef NO_STRING_H
+#ifdef DECLARE_SIZE_T
+typedef unsigned int size_t;
+#endif
+extern void memcpy_D2A ANSI((void*, const void*, size_t));
+#define Bcopy(x,y) memcpy_D2A(&x->sign,&y->sign,y->wds*sizeof(ULong) + 2*sizeof(int))
+#else /* !NO_STRING_H */
+#define Bcopy(x,y) memcpy(&x->sign,&y->sign,y->wds*sizeof(ULong) + 2*sizeof(int))
+#endif /* NO_STRING_H */
+
+#define dtoa __dtoa
+#define gdtoa __gdtoa
+#define freedtoa __freedtoa
+#define strtodg __strtodg
+#define g_ddfmt __g_ddfmt
+#define g_dfmt __g_dfmt
+#define g_ffmt __g_ffmt
+#define g_Qfmt __g_Qfmt
+#define g_xfmt __g_xfmt
+#define g_xLfmt __g_xLfmt
+#define strtoId __strtoId
+#define strtoIdd __strtoIdd
+#define strtoIf __strtoIf
+#define strtoIQ __strtoIQ
+#define strtoIx __strtoIx
+#define strtoIxL __strtoIxL
+#define strtord __strtord
+#define strtordd __strtordd
+#define strtorf __strtorf
+#define strtorQ __strtorQ
+#define strtorx __strtorx
+#define strtorxL __strtorxL
+#define strtodI __strtodI
+#define strtopd __strtopd
+#define strtopdd __strtopdd
+#define strtopf __strtopf
+#define strtopQ __strtopQ
+#define strtopx __strtopx
+#define strtopxL __strtopxL
+
+#define Balloc __Balloc_D2A
+#define Bfree __Bfree_D2A
+#define ULtoQ __ULtoQ_D2A
+#define ULtof __ULtof_D2A
+#define ULtod __ULtod_D2A
+#define ULtodd __ULtodd_D2A
+#define ULtox __ULtox_D2A
+#define ULtoxL __ULtoxL_D2A
+#define any_on __any_on_D2A
+#define b2d __b2d_D2A
+#define bigtens __bigtens_D2A
+#define cmp __cmp_D2A
+#define copybits __copybits_D2A
+#define d2b __d2b_D2A
+#define decrement __decrement_D2A
+#define diff __diff_D2A
+#define dtoa_result __dtoa_result_D2A
+#define g__fmt __g__fmt_D2A
+#define gethex __gethex_D2A
+#define hexdig __hexdig_D2A
+#define hexnan __hexnan_D2A
+#define hi0bits(x) __hi0bits_D2A((ULong)(x))
+#define hi0bits_D2A __hi0bits_D2A
+#define i2b __i2b_D2A
+#define increment __increment_D2A
+#define lo0bits __lo0bits_D2A
+#define lshift __lshift_D2A
+#define match __match_D2A
+#define mult __mult_D2A
+#define multadd __multadd_D2A
+#define nrv_alloc __nrv_alloc_D2A
+#define pow5mult __pow5mult_D2A
+#define quorem __quorem_D2A
+#define ratio __ratio_D2A
+#define rshift __rshift_D2A
+#define rv_alloc __rv_alloc_D2A
+#define s2b __s2b_D2A
+#define set_ones __set_ones_D2A
+#define strcp __strcp_D2A
+#define strtoIg __strtoIg_D2A
+#define sulp __sulp_D2A
+#define sum __sum_D2A
+#define tens __tens_D2A
+#define tinytens __tinytens_D2A
+#define tinytens __tinytens_D2A
+#define trailz __trailz_D2A
+#define ulp __ulp_D2A
+
+__BEGIN_HIDDEN_DECLS
+ extern char *dtoa_result;
+ extern CONST double bigtens[], tens[], tinytens[];
+ extern unsigned char hexdig[];
+
+ extern Bigint *Balloc ANSI((int));
+ extern void Bfree ANSI((Bigint*));
+ extern void ULtof ANSI((ULong*, ULong*, Long, int));
+ extern void ULtod ANSI((ULong*, ULong*, Long, int));
+ extern void ULtodd ANSI((ULong*, ULong*, Long, int));
+ extern void ULtoQ ANSI((ULong*, ULong*, Long, int));
+ extern void ULtox ANSI((UShort*, ULong*, Long, int));
+ extern void ULtoxL ANSI((ULong*, ULong*, Long, int));
+ extern ULong any_on ANSI((Bigint*, int));
+ extern double b2d ANSI((Bigint*, int*));
+ extern int cmp ANSI((Bigint*, Bigint*));
+ extern void copybits ANSI((ULong*, int, Bigint*));
+ extern Bigint *d2b ANSI((double, int*, int*));
+ extern void decrement ANSI((Bigint*));
+ extern Bigint *diff ANSI((Bigint*, Bigint*));
+ extern char *g__fmt ANSI((char*, char*, char*, int, ULong, size_t));
+ extern int gethex ANSI((CONST char**, FPI*, Long*, Bigint**, int));
+ extern void __hexdig_init_D2A(Void);
+ extern int hexnan ANSI((CONST char**, FPI*, ULong*));
+ extern int hi0bits_D2A ANSI((ULong));
+ extern Bigint *i2b ANSI((int));
+ extern Bigint *increment ANSI((Bigint*));
+ extern int lo0bits ANSI((ULong*));
+ extern Bigint *lshift ANSI((Bigint*, int));
+ extern int match ANSI((CONST char**, char*));
+ extern Bigint *mult ANSI((Bigint*, Bigint*));
+ extern Bigint *multadd ANSI((Bigint*, int, int));
+ extern char *nrv_alloc ANSI((char*, char **, int));
+ extern Bigint *pow5mult ANSI((Bigint*, int));
+ extern int quorem ANSI((Bigint*, Bigint*));
+ extern double ratio ANSI((Bigint*, Bigint*));
+ extern void rshift ANSI((Bigint*, int));
+ extern char *rv_alloc ANSI((int));
+ extern Bigint *s2b ANSI((CONST char*, int, int, ULong, int));
+ extern Bigint *set_ones ANSI((Bigint*, int));
+ extern char *strcp ANSI((char*, const char*));
+ extern int strtoIg ANSI((CONST char*, char**, FPI*, Long*, Bigint**, int*));
+ extern Bigint *sum ANSI((Bigint*, Bigint*));
+ extern int trailz ANSI((Bigint*));
+ extern double ulp ANSI((U*));
+__END_HIDDEN_DECLS
+
+#ifdef __cplusplus
+}
+#endif
+/*
+ * NAN_WORD0 and NAN_WORD1 are only referenced in strtod.c.  Prior to
+ * 20050115, they used to be hard-wired here (to 0x7ff80000 and 0,
+ * respectively), but now are determined by compiling and running
+ * qnan.c to generate gd_qnan.h, which specifies d_QNAN0 and d_QNAN1.
+ * Formerly gdtoaimp.h recommended supplying suitable -DNAN_WORD0=...
+ * and -DNAN_WORD1=...  values if necessary.  This should still work.
+ * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.)
+ */
+#ifdef IEEE_Arith
+#ifndef NO_INFNAN_CHECK
+#undef INFNAN_CHECK
+#define INFNAN_CHECK
+#endif
+#ifdef IEEE_MC68k
+#define _0 0
+#define _1 1
+#ifndef NAN_WORD0
+#define NAN_WORD0 d_QNAN0
+#endif
+#ifndef NAN_WORD1
+#define NAN_WORD1 d_QNAN1
+#endif
+#else
+#define _0 1
+#define _1 0
+#ifndef NAN_WORD0
+#define NAN_WORD0 d_QNAN1
+#endif
+#ifndef NAN_WORD1
+#define NAN_WORD1 d_QNAN0
+#endif
+#endif
+#else
+#undef INFNAN_CHECK
+#endif
+
+#undef SI
+#ifdef Sudden_Underflow
+#define SI 1
+#else
+#define SI 0
+#endif
+
+#endif /* GDTOAIMP_H_INCLUDED */
diff --git a/newlib/libc/stdlib/ldtoa.c b/newlib/libc/stdlib/ldtoa.c
index 26c61948b..fbbd3d0b1 100644
--- a/newlib/libc/stdlib/ldtoa.c
+++ b/newlib/libc/stdlib/ldtoa.c
@@ -7,6 +7,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include "mprec.h"
+#include "gdtoa.h"
 
 /* These are the externally visible entries. */
 /* linux name:  long double _IO_strtold (char *, char **); */
@@ -2814,6 +2815,12 @@ _ldtoa_r (struct _reent *ptr, long double d, int mode, int ndigits,
       _REENT_MP_RESULT (ptr) = 0;
     }
 
+  /* Use the result of gdtoa if successfull. */
+  outstr = __ldtoa (&d, mode, ndigits, decpt, sign, rve);
+  /* If it fails, fallback to legacy ldtoa. */
+  if (outstr)
+    return outstr;
+
 #if LDBL_MANT_DIG == 24
   e24toe (&du.pe, e, ldp);
 #elif LDBL_MANT_DIG == 53
-- 
2.33.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed value is incorrectly rounded
  2021-11-29 14:24             ` Takashi Yano
@ 2021-11-29 15:55               ` Corinna Vinschen
  2021-11-30 10:51                 ` Takashi Yano
  0 siblings, 1 reply; 25+ messages in thread
From: Corinna Vinschen @ 2021-11-29 15:55 UTC (permalink / raw)
  To: newlib

Hi Takashi,

On Nov 29 23:24, Takashi Yano wrote:
> On Mon, 29 Nov 2021 19:56:46 +0900
> Takashi Yano wrote:
> > On Sun, 28 Nov 2021 22:16:46 +0900
> > Takashi Yano wrote:
> > > On Sun, 28 Nov 2021 21:38:39 +0900
> > > Takashi Yano wrote:
> > > > On Sun, 28 Nov 2021 16:43:11 +0900
> > > > Takashi Yano wrote:
> > > > > On Thu, 4 Nov 2021 13:24:42 +0100
> > > > > Corinna Vinschen wrote:
> > > > > > However, a much better fix would be to switch to gdtoa, as the BSDs and
> > > > > > Mingw64 do.
> > > > > 
> > > > > I have tried to import gdtoa into newlib from OpenBSD.
> > > > > 
> > > > > gdtoa seems to use malloc much, so it may not work in some of
> > > > > platforms due to insufficient heap. Therefore, new ldtoa.c tries
> > > > > gdtoa first and fallbacks to legacy ldtoa if gdtoa fails.
> > > > > 
> > > > > To import gdtoa to newlib, I did:
> > > > > 1) Create "machine/ieee.h" which conditionally defines ieee_ext
> > > > >    structure and EXT_TO_ARRAY32() macro depend on architecture.
> > > > > 2) Create arith.h which reflects endian of architecture.
> > > > > 3) Merge gdtoa.h with OpenBSD's gdtoa.h. __BEGIN_HIDDEN_DECLS,
> > > > >    __END_HIDDEN_DECLS, PROTO_NORMAL() and DEF_STRONG() are
> > > > >    defined as dummy in this header.
> > > > > 4) Replace malloc()/free() with _malloc_r()/_free_r().
> > > > > 5) Implement ACQUIRE_DTOA_LOCK() and FREE_DTOA_LOCK() macros
> > > > >    using "sys/lock.h" for multi-threading environment.
> > > > > 6) Remove inclusion of "gd_qnan.h" which is not used.
> > > > > 
> > > > > Please see attached patch for more details.
> > > > > 
> > > > > I confirmed this works nicely with cygwin. Moreover, it is much
> > > > > faster than legacy ldtoa (more than 4 times faster).
> > > > > 
> > > > > However, this may break some other supported platforms.
> > > > > 
> > > > > Could anyone please check this?

Thanks for looking into that and the patch...

> > > > 
> > > > Ah, in "machine/ieee.h", struct ieee_ext definition for
> > > > LDBL_MANT_DIG==64 and __IEEE_BIG_ENDIAN case, is obviously
> > > > wrong. 
> > > 
> > > Fixed.
> > 
> > Bit order for ARMEL without __VFP_FP__ is fixed.
> 
> Add support for ARM FPA10 math coprocessor extended precision format.

...and thanks for subsequent patches.

As far as I can see, there are some more generic changes required in the
gdtoa code.  At a first glance I see these problems in terms of reentrancy:

- __ldtoa should take an additional parameter `struct __reent *',
  per the convention as first parameter.

- Balloc/Bfree are already implemented in newlib as reentrent functions,
  taking an additional reent pointer.  Those should be used, rather than
  getting implemented again as non-reentrant functions.

- MALLOC/FREE should be defined as taking the reent pointer given to
  __ldtoa, rather than _REENT.

As for the allocations, how big are those?  If they are comparable with
the allocation we now perform in _ldtoa_r, it might not be worth to keep
both functions.  Some users of smaller targets might also complain that
using printf now always pulls in both variants of ldtoa, thus raising
code size unnecessarily.  It might be better to keep the calls separate
and only use one or the other, per target or per code size constraints,
perhaps as a configure option.


Thanks,
Corinna


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed value is incorrectly rounded
  2021-11-29 15:55               ` Corinna Vinschen
@ 2021-11-30 10:51                 ` Takashi Yano
  2021-11-30 15:09                   ` Corinna Vinschen
  0 siblings, 1 reply; 25+ messages in thread
From: Takashi Yano @ 2021-11-30 10:51 UTC (permalink / raw)
  To: newlib

[-- Attachment #1: Type: text/plain, Size: 3735 bytes --]

On Mon, 29 Nov 2021 16:55:32 +0100
Corinna Vinschen wrote:
> On Nov 29 23:24, Takashi Yano wrote:
> > On Mon, 29 Nov 2021 19:56:46 +0900
> > Takashi Yano wrote:
> > > On Sun, 28 Nov 2021 22:16:46 +0900
> > > Takashi Yano wrote:
> > > > On Sun, 28 Nov 2021 21:38:39 +0900
> > > > Takashi Yano wrote:
> > > > > On Sun, 28 Nov 2021 16:43:11 +0900
> > > > > Takashi Yano wrote:
> > > > > > On Thu, 4 Nov 2021 13:24:42 +0100
> > > > > > Corinna Vinschen wrote:
> > > > > > > However, a much better fix would be to switch to gdtoa, as the BSDs and
> > > > > > > Mingw64 do.
> > > > > > 
> > > > > > I have tried to import gdtoa into newlib from OpenBSD.
> > > > > > 
> > > > > > gdtoa seems to use malloc much, so it may not work in some of
> > > > > > platforms due to insufficient heap. Therefore, new ldtoa.c tries
> > > > > > gdtoa first and fallbacks to legacy ldtoa if gdtoa fails.
> > > > > > 
> > > > > > To import gdtoa to newlib, I did:
> > > > > > 1) Create "machine/ieee.h" which conditionally defines ieee_ext
> > > > > >    structure and EXT_TO_ARRAY32() macro depend on architecture.
> > > > > > 2) Create arith.h which reflects endian of architecture.
> > > > > > 3) Merge gdtoa.h with OpenBSD's gdtoa.h. __BEGIN_HIDDEN_DECLS,
> > > > > >    __END_HIDDEN_DECLS, PROTO_NORMAL() and DEF_STRONG() are
> > > > > >    defined as dummy in this header.
> > > > > > 4) Replace malloc()/free() with _malloc_r()/_free_r().
> > > > > > 5) Implement ACQUIRE_DTOA_LOCK() and FREE_DTOA_LOCK() macros
> > > > > >    using "sys/lock.h" for multi-threading environment.
> > > > > > 6) Remove inclusion of "gd_qnan.h" which is not used.
> > > > > > 
> > > > > > Please see attached patch for more details.
> > > > > > 
> > > > > > I confirmed this works nicely with cygwin. Moreover, it is much
> > > > > > faster than legacy ldtoa (more than 4 times faster).
> > > > > > 
> > > > > > However, this may break some other supported platforms.
> > > > > > 
> > > > > > Could anyone please check this?
> 
> Thanks for looking into that and the patch...
> 
> > > > > 
> > > > > Ah, in "machine/ieee.h", struct ieee_ext definition for
> > > > > LDBL_MANT_DIG==64 and __IEEE_BIG_ENDIAN case, is obviously
> > > > > wrong. 
> > > > 
> > > > Fixed.
> > > 
> > > Bit order for ARMEL without __VFP_FP__ is fixed.
> > 
> > Add support for ARM FPA10 math coprocessor extended precision format.
> 
> ...and thanks for subsequent patches.
> 
> As far as I can see, there are some more generic changes required in the
> gdtoa code.  At a first glance I see these problems in terms of reentrancy:
> 
> - __ldtoa should take an additional parameter `struct __reent *',
>   per the convention as first parameter.
> 
> - Balloc/Bfree are already implemented in newlib as reentrent functions,
>   taking an additional reent pointer.  Those should be used, rather than
>   getting implemented again as non-reentrant functions.
> 
> - MALLOC/FREE should be defined as taking the reent pointer given to
>   __ldtoa, rather than _REENT.

Thanks for checking and advice. I have done these.

> As for the allocations, how big are those?  If they are comparable with
> the allocation we now perform in _ldtoa_r, it might not be worth to keep
> both functions.  Some users of smaller targets might also complain that

I saw max 16404 byte malloc().

> using printf now always pulls in both variants of ldtoa, thus raising
> code size unnecessarily.  It might be better to keep the calls separate
> and only use one or the other, per target or per code size constraints,
> perhaps as a configure option.

I have added --enable-newlib-use-gdtoa option, which defaults
to 'yes', into newlib/configure.ac. Is this the right thing?

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: v2-0001-ldtoa-Import-gdtoa-from-OpenBSD.patch --]
[-- Type: application/octet-stream, Size: 124845 bytes --]

From 00559b2f222927d9a259fe7d54bb91565ddcdb9c Mon Sep 17 00:00:00 2001
From: Takashi Yano <takashi.yano@nifty.ne.jp>
Date: Tue, 30 Nov 2021 18:29:06 +0900
Subject: [PATCH v2] ldtoa: Import gdtoa from OpenBSD.

- This patch uses gdtoa imported from OpenBSD if newlib configure
  option "--enable-newlib-use-gdtoa=no" is NOT specified.  gdtoa
  provides more accurate output and faster conversion than legacy
  ldtoa, while it requires more heap memory.
---
 newlib/README                      |  10 +
 newlib/configure                   | 317 ++++++-----
 newlib/configure.ac                |  15 +
 newlib/libc/include/machine/ieee.h | 127 +++++
 newlib/libc/include/sys/config.h   |   6 +
 newlib/libc/stdlib/Makefile.am     |  12 +-
 newlib/libc/stdlib/Makefile.in     | 109 ++--
 newlib/libc/stdlib/gdtoa-dmisc.c   | 230 ++++++++
 newlib/libc/stdlib/gdtoa-dtoa.c    | 846 +++++++++++++++++++++++++++++
 newlib/libc/stdlib/gdtoa-gdtoa.c   | 837 ++++++++++++++++++++++++++++
 newlib/libc/stdlib/gdtoa-gmisc.c   |  91 ++++
 newlib/libc/stdlib/gdtoa-ldtoa.c   | 130 +++++
 newlib/libc/stdlib/gdtoa.h         | 130 ++++-
 newlib/libc/stdlib/gdtoaimp.h      | 206 +++++++
 newlib/libc/stdlib/ldtoa.c         |  19 +
 newlib/libc/stdlib/mprec.h         |   2 +-
 newlib/newlib.hin                  |   3 +
 17 files changed, 2899 insertions(+), 191 deletions(-)
 create mode 100644 newlib/libc/include/machine/ieee.h
 create mode 100644 newlib/libc/stdlib/gdtoa-dmisc.c
 create mode 100644 newlib/libc/stdlib/gdtoa-dtoa.c
 create mode 100644 newlib/libc/stdlib/gdtoa-gdtoa.c
 create mode 100644 newlib/libc/stdlib/gdtoa-gmisc.c
 create mode 100644 newlib/libc/stdlib/gdtoa-ldtoa.c
 create mode 100644 newlib/libc/stdlib/gdtoaimp.h

diff --git a/newlib/README b/newlib/README
index 064c5784c..c82bf8b8c 100644
--- a/newlib/README
+++ b/newlib/README
@@ -352,6 +352,16 @@ One feature can be enabled by specifying `--enable-FEATURE=yes' or
      64-bit integer on most systems.
      Disabled by default.
 
+`--enable-newlib-use-gdtoa'
+     Use gdtoa rather than legacy ldtoa.  gdtoa privides more accurate
+     output and faster conversion than legacy ldtoa, while it requires
+     more heap memory.  gdtoa sometimes requires 16KB heap memory, so
+     if the platform does not have enough heap memory, consider disabling
+     this option. Legacy ldtoa also use heap, however, only 1KB memory
+     is malloc'ed.  In addition, if malloc fails, it still works, with
+     less conversion accuracy.
+     Enabled by default.
+
 `--enable-multilib'
      Build many library versions.
      Enabled by default.
diff --git a/newlib/configure b/newlib/configure
index ce2fb55d2..7ab6e3423 100755
--- a/newlib/configure
+++ b/newlib/configure
@@ -1,11 +1,9 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.68 for newlib 4.1.0.
+# Generated by GNU Autoconf 2.69 for newlib 4.1.0.
 #
 #
-# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
-# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
-# Foundation, Inc.
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
 #
 #
 # This configure script is free software; the Free Software Foundation
@@ -134,6 +132,31 @@ export LANGUAGE
 # CDPATH.
 (unset CDPATH) >/dev/null 2>&1 && unset CDPATH
 
+# Use a proper internal environment variable to ensure we don't fall
+  # into an infinite loop, continuously re-executing ourselves.
+  if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+    _as_can_reexec=no; export _as_can_reexec;
+    # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+  fi
+  # We don't want this to propagate to other subprocesses.
+          { _as_can_reexec=; unset _as_can_reexec;}
 if test "x$CONFIG_SHELL" = x; then
   as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
   emulate sh
@@ -167,7 +190,8 @@ if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
 else
   exitcode=1; echo positional parameters were not saved.
 fi
-test x\$exitcode = x0 || exit 1"
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
   as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
   as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
   eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
@@ -220,21 +244,25 @@ IFS=$as_save_IFS
 
 
       if test "x$CONFIG_SHELL" != x; then :
-  # We cannot yet assume a decent shell, so we have to provide a
-	# neutralization value for shells without unset; and this also
-	# works around shells that cannot unset nonexistent variables.
-	# Preserve -v and -x to the replacement shell.
-	BASH_ENV=/dev/null
-	ENV=/dev/null
-	(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
-	export CONFIG_SHELL
-	case $- in # ((((
-	  *v*x* | *x*v* ) as_opts=-vx ;;
-	  *v* ) as_opts=-v ;;
-	  *x* ) as_opts=-x ;;
-	  * ) as_opts= ;;
-	esac
-	exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"}
+  export CONFIG_SHELL
+             # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
 fi
 
     if test x$as_have_required = xno; then :
@@ -336,6 +364,14 @@ $as_echo X"$as_dir" |
 
 
 } # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
 # as_fn_append VAR VALUE
 # ----------------------
 # Append the text in VALUE to the end of the definition contained in VAR. Take
@@ -457,6 +493,10 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits
   chmod +x "$as_me.lineno" ||
     { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
 
+  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+  # already done that, so ensure we don't try to do so again and fall
+  # in an infinite loop.  This has already happened in practice.
+  _as_can_reexec=no; export _as_can_reexec
   # Don't try to exec as it changes $[0], causing all sort of problems
   # (the dirname of $[0] is not the place where we might find the
   # original and so on.  Autoconf is especially sensitive to this).
@@ -491,16 +531,16 @@ if (echo >conf$$.file) 2>/dev/null; then
     # ... but there are two gotchas:
     # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
     # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
-    # In both cases, we have to default to `cp -p'.
+    # In both cases, we have to default to `cp -pR'.
     ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
-      as_ln_s='cp -p'
+      as_ln_s='cp -pR'
   elif ln conf$$.file conf$$ 2>/dev/null; then
     as_ln_s=ln
   else
-    as_ln_s='cp -p'
+    as_ln_s='cp -pR'
   fi
 else
-  as_ln_s='cp -p'
+  as_ln_s='cp -pR'
 fi
 rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
 rmdir conf$$.dir 2>/dev/null
@@ -512,28 +552,8 @@ else
   as_mkdir_p=false
 fi
 
-if test -x / >/dev/null 2>&1; then
-  as_test_x='test -x'
-else
-  if ls -dL / >/dev/null 2>&1; then
-    as_ls_L_option=L
-  else
-    as_ls_L_option=
-  fi
-  as_test_x='
-    eval sh -c '\''
-      if test -d "$1"; then
-	test -d "$1/.";
-      else
-	case $1 in #(
-	-*)set "./$1";;
-	esac;
-	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
-	???[sx]*):;;*)false;;esac;fi
-    '\'' sh
-  '
-fi
-as_executable_p=$as_test_x
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
 
 # Sed expression to map a string onto a valid CPP name.
 as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
@@ -762,6 +782,7 @@ infodir
 docdir
 oldincludedir
 includedir
+runstatedir
 localstatedir
 sharedstatedir
 sysconfdir
@@ -808,6 +829,7 @@ enable_lite_exit
 enable_newlib_nano_formatted_io
 enable_newlib_retargetable_locking
 enable_newlib_long_time_t
+enable_newlib_use_gdtoa
 enable_multilib
 enable_target_optspace
 enable_malloc_debugging
@@ -877,6 +899,7 @@ datadir='${datarootdir}'
 sysconfdir='${prefix}/etc'
 sharedstatedir='${prefix}/com'
 localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
 includedir='${prefix}/include'
 oldincludedir='/usr/include'
 docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@@ -1129,6 +1152,15 @@ do
   | -silent | --silent | --silen | --sile | --sil)
     silent=yes ;;
 
+  -runstatedir | --runstatedir | --runstatedi | --runstated \
+  | --runstate | --runstat | --runsta | --runst | --runs \
+  | --run | --ru | --r)
+    ac_prev=runstatedir ;;
+  -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+  | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+  | --run=* | --ru=* | --r=*)
+    runstatedir=$ac_optarg ;;
+
   -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
     ac_prev=sbindir ;;
   -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1266,7 +1298,7 @@ fi
 for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
 		datadir sysconfdir sharedstatedir localstatedir includedir \
 		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
-		libdir localedir mandir
+		libdir localedir mandir runstatedir
 do
   eval ac_val=\$$ac_var
   # Remove trailing slashes.
@@ -1294,8 +1326,6 @@ target=$target_alias
 if test "x$host_alias" != x; then
   if test "x$build_alias" = x; then
     cross_compiling=maybe
-    $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.
-    If a cross compiler is detected then cross compile mode will be used" >&2
   elif test "x$build_alias" != "x$host_alias"; then
     cross_compiling=yes
   fi
@@ -1421,6 +1451,7 @@ Fine tuning of the installation directories:
   --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
   --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
   --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --runstatedir=DIR       modifiable per-process data [LOCALSTATEDIR/run]
   --libdir=DIR            object code libraries [EPREFIX/lib]
   --includedir=DIR        C header files [PREFIX/include]
   --oldincludedir=DIR     C header files for non-gcc [/usr/include]
@@ -1483,6 +1514,7 @@ Optional Features:
   --enable-newlib-nano-formatted-io    Use nano version formatted IO
   --enable-newlib-retargetable-locking    Allow locking routines to be retargeted at link time
   --enable-newlib-long-time_t   define time_t to long
+  --enable-newlib-use-gdtoa   Use gdtoa rather than legacy ldtoa
   --enable-multilib         build many library versions (default)
   --enable-target-optspace  optimize for space
   --enable-malloc-debugging indicate malloc debugging requested
@@ -1588,9 +1620,9 @@ test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
 newlib configure 4.1.0
-generated by GNU Autoconf 2.68
+generated by GNU Autoconf 2.69
 
-Copyright (C) 2010 Free Software Foundation, Inc.
+Copyright (C) 2012 Free Software Foundation, Inc.
 This configure script is free software; the Free Software Foundation
 gives unlimited permission to copy, distribute and modify it.
 _ACEOF
@@ -1666,7 +1698,7 @@ $as_echo "$ac_try_echo"; } >&5
 	 test ! -s conftest.err
        } && test -s conftest$ac_exeext && {
 	 test "$cross_compiling" = yes ||
-	 $as_test_x conftest$ac_exeext
+	 test -x conftest$ac_exeext
        }; then :
   ac_retval=0
 else
@@ -1866,7 +1898,7 @@ This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
 It was created by newlib $as_me 4.1.0, which was
-generated by GNU Autoconf 2.68.  Invocation command line was
+generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
 
@@ -2532,6 +2564,19 @@ else
   newlib_long_time_t=no
 fi
 
+# Check whether --enable-newlib-use-gdtoa was given.
+if test "${enable_newlib_use_gdtoa+set}" = set; then :
+  enableval=$enable_newlib_use_gdtoa; if test "${newlib_use_gdtoa+set}" != set; then
+  case "${enableval}" in
+    yes) newlib_use_gdtoa=yes ;;
+    no)  newlib_use_gdtoa=no  ;;
+    *)   as_fn_error $? "bad value ${enableval} for newlib-use-gdtoa option" "$LINENO" 5 ;;
+  esac
+ fi
+else
+  newlib_use_gdtoa=yes
+fi
+
 
 # Make sure we can run config.sub.
 $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
@@ -2643,7 +2688,7 @@ case $as_dir/ in #((
     # by default.
     for ac_prog in ginstall scoinst install; do
       for ac_exec_ext in '' $ac_executable_extensions; do
-	if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+	if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
 	  if test $ac_prog = install &&
 	    grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
 	    # AIX install.  It has an incompatible calling convention.
@@ -2812,7 +2857,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_STRIP="${ac_tool_prefix}strip"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -2852,7 +2897,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_STRIP="strip"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -2903,7 +2948,7 @@ do
   test -z "$as_dir" && as_dir=.
     for ac_prog in mkdir gmkdir; do
 	 for ac_exec_ext in '' $ac_executable_extensions; do
-	   { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue
+	   as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue
 	   case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
 	     'mkdir (GNU coreutils) '* | \
 	     'mkdir (coreutils) '* | \
@@ -2956,7 +3001,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_AWK="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3296,7 +3341,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_CC="gcc"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3464,7 +3509,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
        ac_prog_rejected=yes
        continue
@@ -3642,7 +3687,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_AS="${ac_tool_prefix}as"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3682,7 +3727,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_AS="as"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3734,7 +3779,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_AR="${ac_tool_prefix}ar"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3774,7 +3819,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_AR="ar"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3826,7 +3871,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3866,7 +3911,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_RANLIB="ranlib"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3918,7 +3963,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_READELF="${ac_tool_prefix}readelf"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3958,7 +4003,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_READELF="readelf"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4146,7 +4191,7 @@ do
     for ac_prog in sed gsed; do
     for ac_exec_ext in '' $ac_executable_extensions; do
       ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
-      { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue
+      as_fn_executable_p "$ac_path_SED" || continue
 # Check for GNU ac_path_SED and select it if it is found.
   # Check for GNU $ac_path_SED
 case `"$ac_path_SED" --version 2>&1` in
@@ -4276,7 +4321,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_AWK="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4322,7 +4367,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_AS="${ac_tool_prefix}as"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4362,7 +4407,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_AS="as"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4414,7 +4459,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4454,7 +4499,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_DLLTOOL="dlltool"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4506,7 +4551,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4546,7 +4591,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_OBJDUMP="objdump"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4668,7 +4713,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_CC="${ac_tool_prefix}gcc"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4708,7 +4753,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_CC="gcc"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4761,7 +4806,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_CC="${ac_tool_prefix}cc"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4802,7 +4847,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
        ac_prog_rejected=yes
        continue
@@ -4860,7 +4905,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4904,7 +4949,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_CC="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -5350,8 +5395,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #include <stdarg.h>
 #include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
+struct stat;
 /* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
 struct buf { int x; };
 FILE * (*rcsopen) (struct buf *, struct stat *, int);
@@ -5580,7 +5624,7 @@ do
     for ac_prog in grep ggrep; do
     for ac_exec_ext in '' $ac_executable_extensions; do
       ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
-      { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+      as_fn_executable_p "$ac_path_GREP" || continue
 # Check for GNU ac_path_GREP and select it if it is found.
   # Check for GNU $ac_path_GREP
 case `"$ac_path_GREP" --version 2>&1` in
@@ -5646,7 +5690,7 @@ do
     for ac_prog in egrep; do
     for ac_exec_ext in '' $ac_executable_extensions; do
       ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
-      { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+      as_fn_executable_p "$ac_path_EGREP" || continue
 # Check for GNU ac_path_EGREP and select it if it is found.
   # Check for GNU $ac_path_EGREP
 case `"$ac_path_EGREP" --version 2>&1` in
@@ -5713,7 +5757,7 @@ do
     for ac_prog in fgrep; do
     for ac_exec_ext in '' $ac_executable_extensions; do
       ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
-      { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue
+      as_fn_executable_p "$ac_path_FGREP" || continue
 # Check for GNU ac_path_FGREP and select it if it is found.
   # Check for GNU $ac_path_FGREP
 case `"$ac_path_FGREP" --version 2>&1` in
@@ -5969,7 +6013,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6013,7 +6057,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6353,7 +6397,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6393,7 +6437,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_OBJDUMP="objdump"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6670,7 +6714,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_AR="${ac_tool_prefix}ar"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6710,7 +6754,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_AR="ar"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6775,7 +6819,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_STRIP="${ac_tool_prefix}strip"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6815,7 +6859,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_STRIP="strip"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6874,7 +6918,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6914,7 +6958,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_RANLIB="ranlib"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7504,7 +7548,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7544,7 +7588,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7596,7 +7640,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7636,7 +7680,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_NMEDIT="nmedit"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7688,7 +7732,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7728,7 +7772,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_LIPO="lipo"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7780,7 +7824,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7820,7 +7864,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_OTOOL="otool"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7872,7 +7916,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7912,7 +7956,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_OTOOL64="otool64"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -11855,7 +11899,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11858 "configure"
+#line 11902 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11961,7 +12005,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11964 "configure"
+#line 12008 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12586,6 +12630,13 @@ _ACEOF
 
 fi
 
+if test "${newlib_use_gdtoa}" = "yes"; then
+cat >>confdefs.h <<_ACEOF
+#define _WANT_USE_GDTOA 1
+_ACEOF
+
+fi
+
 
 if test "x${iconv_encodings}" != "x" \
    || test "x${iconv_to_encodings}" != "x" \
@@ -13302,16 +13353,16 @@ if (echo >conf$$.file) 2>/dev/null; then
     # ... but there are two gotchas:
     # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
     # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
-    # In both cases, we have to default to `cp -p'.
+    # In both cases, we have to default to `cp -pR'.
     ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
-      as_ln_s='cp -p'
+      as_ln_s='cp -pR'
   elif ln conf$$.file conf$$ 2>/dev/null; then
     as_ln_s=ln
   else
-    as_ln_s='cp -p'
+    as_ln_s='cp -pR'
   fi
 else
-  as_ln_s='cp -p'
+  as_ln_s='cp -pR'
 fi
 rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
 rmdir conf$$.dir 2>/dev/null
@@ -13371,28 +13422,16 @@ else
   as_mkdir_p=false
 fi
 
-if test -x / >/dev/null 2>&1; then
-  as_test_x='test -x'
-else
-  if ls -dL / >/dev/null 2>&1; then
-    as_ls_L_option=L
-  else
-    as_ls_L_option=
-  fi
-  as_test_x='
-    eval sh -c '\''
-      if test -d "$1"; then
-	test -d "$1/.";
-      else
-	case $1 in #(
-	-*)set "./$1";;
-	esac;
-	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
-	???[sx]*):;;*)false;;esac;fi
-    '\'' sh
-  '
-fi
-as_executable_p=$as_test_x
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
 
 # Sed expression to map a string onto a valid CPP name.
 as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
@@ -13414,7 +13453,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # values after options handling.
 ac_log="
 This file was extended by newlib $as_me 4.1.0, which was
-generated by GNU Autoconf 2.68.  Invocation command line was
+generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
   CONFIG_HEADERS  = $CONFIG_HEADERS
@@ -13480,10 +13519,10 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
 newlib config.status 4.1.0
-configured by $0, generated by GNU Autoconf 2.68,
+configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
-Copyright (C) 2010 Free Software Foundation, Inc.
+Copyright (C) 2012 Free Software Foundation, Inc.
 This config.status script is free software; the Free Software Foundation
 gives unlimited permission to copy, distribute and modify it."
 
@@ -13574,7 +13613,7 @@ fi
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 if \$ac_cs_recheck; then
-  set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
   shift
   \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
   CONFIG_SHELL='$SHELL'
diff --git a/newlib/configure.ac b/newlib/configure.ac
index 49a1b5fdd..25f6d07ed 100644
--- a/newlib/configure.ac
+++ b/newlib/configure.ac
@@ -259,6 +259,17 @@ AC_ARG_ENABLE(newlib-long-time_t,
   esac
  fi], [newlib_long_time_t=no])dnl
 
+dnl Support --enable-newlib-use-gdtoa
+AC_ARG_ENABLE(newlib-use-gdtoa,
+[  --enable-newlib-use-gdtoa   Use gdtoa rather than legacy ldtoa],
+[if test "${newlib_use_gdtoa+set}" != set; then
+  case "${enableval}" in
+    yes) newlib_use_gdtoa=yes ;;
+    no)  newlib_use_gdtoa=no  ;;
+    *)   AC_MSG_ERROR(bad value ${enableval} for newlib-use-gdtoa option) ;;
+  esac
+ fi], [newlib_use_gdtoa=yes])dnl
+
 NEWLIB_CONFIGURE(.)
 
 dnl We have to enable libtool after NEWLIB_CONFIGURE because if we try and
@@ -537,6 +548,10 @@ if test "${newlib_long_time_t}" = "yes"; then
 AC_DEFINE_UNQUOTED(_WANT_USE_LONG_TIME_T)
 fi
 
+if test "${newlib_use_gdtoa}" = "yes"; then
+AC_DEFINE_UNQUOTED(_WANT_USE_GDTOA)
+fi
+
 dnl
 dnl Parse --enable-newlib-iconv-encodings option argument
 dnl
diff --git a/newlib/libc/include/machine/ieee.h b/newlib/libc/include/machine/ieee.h
new file mode 100644
index 000000000..0656909ab
--- /dev/null
+++ b/newlib/libc/include/machine/ieee.h
@@ -0,0 +1,127 @@
+#ifndef _MACHINE_IEEE_H_
+#define _MACHINE_IEEE_H_
+#include <sys/types.h>
+#include <sys/cdefs.h>
+#include <machine/ieeefp.h>
+#include <float.h>
+
+#if LDBL_MANT_DIG == 24
+#define EXT_IMPLICIT_NBIT
+#define EXT_TO_ARRAY32(p, a) do {      \
+    (a)[0] = (p)->ext_frac;  \
+} while (0)
+#ifdef __IEEE_LITTLE_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_frac:23;
+    uint32_t   ext_exp:8;
+    uint32_t   ext_sign:1;
+};
+#endif
+#ifdef __IEEE_BIG_ENDIAN
+struct ieee_ext {
+#ifndef ___IEEE_BYTES_LITTLE_ENDIAN
+    uint32_t   ext_sign:1;
+    uint32_t   ext_exp:8;
+    uint32_t   ext_frac:23;
+#else /* ARMEL without __VFP_FP__ */
+    uint32_t   ext_frac:23;
+    uint32_t   ext_exp:8;
+    uint32_t   ext_sign:1;
+#endif
+};
+#endif
+#elif LDBL_MANT_DIG == 53
+#define EXT_IMPLICIT_NBIT
+#define EXT_TO_ARRAY32(p, a) do {       \
+    (a)[0] = (p)->ext_fracl;  \
+    (a)[1] = (p)->ext_frach;  \
+} while (0)
+#ifdef __IEEE_LITTLE_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_fracl;
+    uint32_t   ext_frach:20;
+    uint32_t   ext_exp:11;
+    uint32_t   ext_sign:1;
+};
+#endif
+#ifdef __IEEE_BIG_ENDIAN
+struct ieee_ext {
+#ifndef ___IEEE_BYTES_LITTLE_ENDIAN
+    uint32_t   ext_sign:1;
+    uint32_t   ext_exp:11;
+    uint32_t   ext_frach:20;
+#else /* ARMEL without __VFP_FP__ */
+    uint32_t   ext_frach:20;
+    uint32_t   ext_exp:11;
+    uint32_t   ext_sign:1;
+#endif
+    uint32_t   ext_fracl;
+};
+#endif
+#elif LDBL_MANT_DIG == 64
+#define EXT_TO_ARRAY32(p, a) do {       \
+    (a)[0] = (p)->ext_fracl;  \
+    (a)[1] = (p)->ext_frach;  \
+} while (0)
+#ifdef __IEEE_LITTLE_ENDIAN /* for Intel CPU */
+struct ieee_ext {
+    uint32_t   ext_fracl;
+    uint32_t   ext_frach;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_sign:1;
+    uint32_t   ext_padl:16;
+    uint32_t   ext_padh;
+};
+#endif
+#ifdef __IEEE_BIG_ENDIAN
+struct ieee_ext {
+#ifndef ___IEEE_BYTES_LITTLE_ENDIAN /* for m68k */
+    uint32_t   ext_sign:1;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_pad:16;
+#else /* ARM FPA10 math coprocessor */
+    uint32_t   ext_exp:15;
+    uint32_t   ext_pad:16;
+    uint32_t   ext_sign:1;
+#endif
+    uint32_t   ext_frach;
+    uint32_t   ext_fracl;
+};
+#endif
+#elif LDBL_MANT_DIG == 113
+#define EXT_IMPLICIT_NBIT
+#define EXT_TO_ARRAY32(p, a) do {        \
+    (a)[0] = (p)->ext_fracl;   \
+    (a)[1] = (p)->ext_fraclm;  \
+    (a)[2] = (p)->ext_frachm;  \
+    (a)[3] = (p)->ext_frach;   \
+} while (0)
+#ifdef __IEEE_LITTLE_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_fracl;
+    uint32_t   ext_fraclm;
+    uint32_t   ext_frachm;
+    uint32_t   ext_frach:16;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_sign:1;
+};
+#endif
+#ifdef __IEEE_BIG_ENDIAN
+struct ieee_ext {
+#ifndef ___IEEE_BYTES_LITTLE_ENDIAN
+    uint32_t   ext_sign:1;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_frach:16;
+#else /* ARMEL without __VFP_FP__ */
+    uint32_t   ext_frach:16;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_sign:1;
+#endif
+    uint32_t   ext_frachm;
+    uint32_t   ext_fraclm;
+    uint32_t   ext_fracl;
+};
+#endif
+#endif
+
+#endif /* _MACHINE_IEEE_H_ */
diff --git a/newlib/libc/include/sys/config.h b/newlib/libc/include/sys/config.h
index b9dff88ff..61a6f95d8 100644
--- a/newlib/libc/include/sys/config.h
+++ b/newlib/libc/include/sys/config.h
@@ -293,6 +293,12 @@
 #endif
 #endif
 
+#ifdef _WANT_USE_GDTOA
+#ifndef _USE_GDTOA
+#define _USE_GDTOA
+#endif
+#endif
+
 /* If _MB_EXTENDED_CHARSETS_ALL is set, we want all of the extended
    charsets.  The extended charsets add a few functions and a couple
    of tables of a few K each. */
diff --git a/newlib/libc/stdlib/Makefile.am b/newlib/libc/stdlib/Makefile.am
index 357e37beb..e353c8d29 100644
--- a/newlib/libc/stdlib/Makefile.am
+++ b/newlib/libc/stdlib/Makefile.am
@@ -38,6 +38,11 @@ GENERAL_SOURCES = \
 	labs.c 		\
 	ldiv.c  	\
 	ldtoa.c		\
+	gdtoa-ldtoa.c	\
+	gdtoa-gdtoa.c	\
+	gdtoa-dtoa.c	\
+	gdtoa-dmisc.c	\
+	gdtoa-gmisc.c	\
 	malloc.c  	\
 	mblen.c		\
 	mblen_r.c	\
@@ -311,7 +316,12 @@ CHEWOUT_FILES= \
 CHAPTERS = stdlib.tex
 
 $(lpfx)dtoa.$(oext): dtoa.c mprec.h
-$(lpfx)ldtoa.$(oext): ldtoa.c mprec.h
+$(lpfx)ldtoa.$(oext): ldtoa.c mprec.h gdtoa.h
+$(lpfx)gdtoa-ldtoa.$(oext): gdtoa-ldtoa.c mprec.h gdtoaimp.h gdtoa.h
+$(lpfx)gdtoa-gdtoa.$(oext): gdtoa-gdtoa.c mprec.h gdtoaimp.h gdtoa.h
+$(lpfx)gdtoa-dtoa.$(oext): gdtoa-dtoa.c mprec.h gdtoaimp.h gdtoa.h
+$(lpfx)gdtoa-dmisc.$(oext): gdtoa-dmisc.c mprec.h gdtoaimp.h gdtoa.h
+$(lpfx)gdtoa-gmisc.$(oext): gdtoa-gmisc.c mprec.h gdtoaimp.h gdtoa.h
 $(lpfx)ecvtbuf.$(oext): ecvtbuf.c mprec.h
 $(lpfx)mbtowc_r.$(oext): mbtowc_r.c mbctype.h
 $(lpfx)mprec.$(oext): mprec.c mprec.h
diff --git a/newlib/libc/stdlib/Makefile.in b/newlib/libc/stdlib/Makefile.in
index a812b6a95..d87334306 100644
--- a/newlib/libc/stdlib/Makefile.in
+++ b/newlib/libc/stdlib/Makefile.in
@@ -101,24 +101,27 @@ am__objects_2 = lib_a-__adjust.$(OBJEXT) lib_a-__atexit.$(OBJEXT) \
 	lib_a-getenv_r.$(OBJEXT) lib_a-imaxabs.$(OBJEXT) \
 	lib_a-imaxdiv.$(OBJEXT) lib_a-itoa.$(OBJEXT) \
 	lib_a-labs.$(OBJEXT) lib_a-ldiv.$(OBJEXT) \
-	lib_a-ldtoa.$(OBJEXT) lib_a-malloc.$(OBJEXT) \
-	lib_a-mblen.$(OBJEXT) lib_a-mblen_r.$(OBJEXT) \
-	lib_a-mbstowcs.$(OBJEXT) lib_a-mbstowcs_r.$(OBJEXT) \
-	lib_a-mbtowc.$(OBJEXT) lib_a-mbtowc_r.$(OBJEXT) \
-	lib_a-mlock.$(OBJEXT) lib_a-mprec.$(OBJEXT) \
-	lib_a-mstats.$(OBJEXT) lib_a-on_exit_args.$(OBJEXT) \
-	lib_a-quick_exit.$(OBJEXT) lib_a-rand.$(OBJEXT) \
-	lib_a-rand_r.$(OBJEXT) lib_a-random.$(OBJEXT) \
-	lib_a-realloc.$(OBJEXT) lib_a-reallocarray.$(OBJEXT) \
-	lib_a-reallocf.$(OBJEXT) lib_a-sb_charsets.$(OBJEXT) \
-	lib_a-strtod.$(OBJEXT) lib_a-strtoimax.$(OBJEXT) \
-	lib_a-strtol.$(OBJEXT) lib_a-strtoul.$(OBJEXT) \
-	lib_a-strtoumax.$(OBJEXT) lib_a-utoa.$(OBJEXT) \
-	lib_a-wcstod.$(OBJEXT) lib_a-wcstoimax.$(OBJEXT) \
-	lib_a-wcstol.$(OBJEXT) lib_a-wcstoul.$(OBJEXT) \
-	lib_a-wcstoumax.$(OBJEXT) lib_a-wcstombs.$(OBJEXT) \
-	lib_a-wcstombs_r.$(OBJEXT) lib_a-wctomb.$(OBJEXT) \
-	lib_a-wctomb_r.$(OBJEXT) $(am__objects_1)
+	lib_a-ldtoa.$(OBJEXT) lib_a-gdtoa-ldtoa.$(OBJEXT) \
+	lib_a-gdtoa-gdtoa.$(OBJEXT) lib_a-gdtoa-dtoa.$(OBJEXT) \
+	lib_a-gdtoa-dmisc.$(OBJEXT) lib_a-gdtoa-gmisc.$(OBJEXT) \
+	lib_a-malloc.$(OBJEXT) lib_a-mblen.$(OBJEXT) \
+	lib_a-mblen_r.$(OBJEXT) lib_a-mbstowcs.$(OBJEXT) \
+	lib_a-mbstowcs_r.$(OBJEXT) lib_a-mbtowc.$(OBJEXT) \
+	lib_a-mbtowc_r.$(OBJEXT) lib_a-mlock.$(OBJEXT) \
+	lib_a-mprec.$(OBJEXT) lib_a-mstats.$(OBJEXT) \
+	lib_a-on_exit_args.$(OBJEXT) lib_a-quick_exit.$(OBJEXT) \
+	lib_a-rand.$(OBJEXT) lib_a-rand_r.$(OBJEXT) \
+	lib_a-random.$(OBJEXT) lib_a-realloc.$(OBJEXT) \
+	lib_a-reallocarray.$(OBJEXT) lib_a-reallocf.$(OBJEXT) \
+	lib_a-sb_charsets.$(OBJEXT) lib_a-strtod.$(OBJEXT) \
+	lib_a-strtoimax.$(OBJEXT) lib_a-strtol.$(OBJEXT) \
+	lib_a-strtoul.$(OBJEXT) lib_a-strtoumax.$(OBJEXT) \
+	lib_a-utoa.$(OBJEXT) lib_a-wcstod.$(OBJEXT) \
+	lib_a-wcstoimax.$(OBJEXT) lib_a-wcstol.$(OBJEXT) \
+	lib_a-wcstoul.$(OBJEXT) lib_a-wcstoumax.$(OBJEXT) \
+	lib_a-wcstombs.$(OBJEXT) lib_a-wcstombs_r.$(OBJEXT) \
+	lib_a-wctomb.$(OBJEXT) lib_a-wctomb_r.$(OBJEXT) \
+	$(am__objects_1)
 am__objects_3 = lib_a-arc4random.$(OBJEXT) \
 	lib_a-arc4random_uniform.$(OBJEXT) lib_a-cxa_atexit.$(OBJEXT) \
 	lib_a-cxa_finalize.$(OBJEXT) lib_a-drand48.$(OBJEXT) \
@@ -165,14 +168,15 @@ am__objects_9 = __adjust.lo __atexit.lo __call_atexit.lo __exp10.lo \
 	div.lo dtoa.lo dtoastub.lo environ.lo envlock.lo eprintf.lo \
 	exit.lo gdtoa-gethex.lo gdtoa-hexnan.lo getenv.lo getenv_r.lo \
 	imaxabs.lo imaxdiv.lo itoa.lo labs.lo ldiv.lo ldtoa.lo \
-	malloc.lo mblen.lo mblen_r.lo mbstowcs.lo mbstowcs_r.lo \
-	mbtowc.lo mbtowc_r.lo mlock.lo mprec.lo mstats.lo \
-	on_exit_args.lo quick_exit.lo rand.lo rand_r.lo random.lo \
-	realloc.lo reallocarray.lo reallocf.lo sb_charsets.lo \
-	strtod.lo strtoimax.lo strtol.lo strtoul.lo strtoumax.lo \
-	utoa.lo wcstod.lo wcstoimax.lo wcstol.lo wcstoul.lo \
-	wcstoumax.lo wcstombs.lo wcstombs_r.lo wctomb.lo wctomb_r.lo \
-	$(am__objects_8)
+	gdtoa-ldtoa.lo gdtoa-gdtoa.lo gdtoa-dtoa.lo gdtoa-dmisc.lo \
+	gdtoa-gmisc.lo malloc.lo mblen.lo mblen_r.lo mbstowcs.lo \
+	mbstowcs_r.lo mbtowc.lo mbtowc_r.lo mlock.lo mprec.lo \
+	mstats.lo on_exit_args.lo quick_exit.lo rand.lo rand_r.lo \
+	random.lo realloc.lo reallocarray.lo reallocf.lo \
+	sb_charsets.lo strtod.lo strtoimax.lo strtol.lo strtoul.lo \
+	strtoumax.lo utoa.lo wcstod.lo wcstoimax.lo wcstol.lo \
+	wcstoul.lo wcstoumax.lo wcstombs.lo wcstombs_r.lo wctomb.lo \
+	wctomb_r.lo $(am__objects_8)
 am__objects_10 = arc4random.lo arc4random_uniform.lo cxa_atexit.lo \
 	cxa_finalize.lo drand48.lo ecvtbuf.lo efgcvt.lo erand48.lo \
 	jrand48.lo lcong48.lo lrand48.lo mrand48.lo msize.lo mtrim.lo \
@@ -354,6 +358,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 shared_machine_dir = @shared_machine_dir@
 sharedstatedir = @sharedstatedir@
@@ -372,13 +377,14 @@ GENERAL_SOURCES = __adjust.c __atexit.c __call_atexit.c __exp10.c \
 	atexit.c atof.c atoff.c atoi.c atol.c calloc.c div.c dtoa.c \
 	dtoastub.c environ.c envlock.c eprintf.c exit.c gdtoa-gethex.c \
 	gdtoa-hexnan.c getenv.c getenv_r.c imaxabs.c imaxdiv.c itoa.c \
-	labs.c ldiv.c ldtoa.c malloc.c mblen.c mblen_r.c mbstowcs.c \
-	mbstowcs_r.c mbtowc.c mbtowc_r.c mlock.c mprec.c mstats.c \
-	on_exit_args.c quick_exit.c rand.c rand_r.c random.c realloc.c \
-	reallocarray.c reallocf.c sb_charsets.c strtod.c strtoimax.c \
-	strtol.c strtoul.c strtoumax.c utoa.c wcstod.c wcstoimax.c \
-	wcstol.c wcstoul.c wcstoumax.c wcstombs.c wcstombs_r.c \
-	wctomb.c wctomb_r.c $(am__append_1)
+	labs.c ldiv.c ldtoa.c gdtoa-ldtoa.c gdtoa-gdtoa.c gdtoa-dtoa.c \
+	gdtoa-dmisc.c gdtoa-gmisc.c malloc.c mblen.c mblen_r.c \
+	mbstowcs.c mbstowcs_r.c mbtowc.c mbtowc_r.c mlock.c mprec.c \
+	mstats.c on_exit_args.c quick_exit.c rand.c rand_r.c random.c \
+	realloc.c reallocarray.c reallocf.c sb_charsets.c strtod.c \
+	strtoimax.c strtol.c strtoul.c strtoumax.c utoa.c wcstod.c \
+	wcstoimax.c wcstol.c wcstoul.c wcstoumax.c wcstombs.c \
+	wcstombs_r.c wctomb.c wctomb_r.c $(am__append_1)
 @NEWLIB_NANO_MALLOC_FALSE@MALIGNR = malignr
 @NEWLIB_NANO_MALLOC_TRUE@MALIGNR = nano-malignr
 @NEWLIB_NANO_MALLOC_FALSE@MALLOPTR = malloptr
@@ -827,6 +833,36 @@ lib_a-ldtoa.o: ldtoa.c
 lib_a-ldtoa.obj: ldtoa.c
 	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-ldtoa.obj `if test -f 'ldtoa.c'; then $(CYGPATH_W) 'ldtoa.c'; else $(CYGPATH_W) '$(srcdir)/ldtoa.c'; fi`
 
+lib_a-gdtoa-ldtoa.o: gdtoa-ldtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-ldtoa.o `test -f 'gdtoa-ldtoa.c' || echo '$(srcdir)/'`gdtoa-ldtoa.c
+
+lib_a-gdtoa-ldtoa.obj: gdtoa-ldtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-ldtoa.obj `if test -f 'gdtoa-ldtoa.c'; then $(CYGPATH_W) 'gdtoa-ldtoa.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-ldtoa.c'; fi`
+
+lib_a-gdtoa-gdtoa.o: gdtoa-gdtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-gdtoa.o `test -f 'gdtoa-gdtoa.c' || echo '$(srcdir)/'`gdtoa-gdtoa.c
+
+lib_a-gdtoa-gdtoa.obj: gdtoa-gdtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-gdtoa.obj `if test -f 'gdtoa-gdtoa.c'; then $(CYGPATH_W) 'gdtoa-gdtoa.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-gdtoa.c'; fi`
+
+lib_a-gdtoa-dtoa.o: gdtoa-dtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-dtoa.o `test -f 'gdtoa-dtoa.c' || echo '$(srcdir)/'`gdtoa-dtoa.c
+
+lib_a-gdtoa-dtoa.obj: gdtoa-dtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-dtoa.obj `if test -f 'gdtoa-dtoa.c'; then $(CYGPATH_W) 'gdtoa-dtoa.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-dtoa.c'; fi`
+
+lib_a-gdtoa-dmisc.o: gdtoa-dmisc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-dmisc.o `test -f 'gdtoa-dmisc.c' || echo '$(srcdir)/'`gdtoa-dmisc.c
+
+lib_a-gdtoa-dmisc.obj: gdtoa-dmisc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-dmisc.obj `if test -f 'gdtoa-dmisc.c'; then $(CYGPATH_W) 'gdtoa-dmisc.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-dmisc.c'; fi`
+
+lib_a-gdtoa-gmisc.o: gdtoa-gmisc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-gmisc.o `test -f 'gdtoa-gmisc.c' || echo '$(srcdir)/'`gdtoa-gmisc.c
+
+lib_a-gdtoa-gmisc.obj: gdtoa-gmisc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-gmisc.obj `if test -f 'gdtoa-gmisc.c'; then $(CYGPATH_W) 'gdtoa-gmisc.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-gmisc.c'; fi`
+
 lib_a-malloc.o: malloc.c
 	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-malloc.o `test -f 'malloc.c' || echo '$(srcdir)/'`malloc.c
 
@@ -1610,7 +1646,12 @@ $(lpfx)$(MALLOPTR).$(oext): $(MALLOCR).c
 	$(MALLOC_COMPILE) -DDEFINE_MALLOPT -c $(srcdir)/$(MALLOCR).c -o $@
 
 $(lpfx)dtoa.$(oext): dtoa.c mprec.h
-$(lpfx)ldtoa.$(oext): ldtoa.c mprec.h
+$(lpfx)ldtoa.$(oext): ldtoa.c mprec.h gdtoa.h
+$(lpfx)gdtoa-ldtoa.$(oext): gdtoa-ldtoa.c mprec.h gdtoaimp.h gdtoa.h
+$(lpfx)gdtoa-gdtoa.$(oext): gdtoa-gdtoa.c mprec.h gdtoaimp.h gdtoa.h
+$(lpfx)gdtoa-dtoa.$(oext): gdtoa-dtoa.c mprec.h gdtoaimp.h gdtoa.h
+$(lpfx)gdtoa-dmisc.$(oext): gdtoa-dmisc.c mprec.h gdtoaimp.h gdtoa.h
+$(lpfx)gdtoa-gmisc.$(oext): gdtoa-gmisc.c mprec.h gdtoaimp.h gdtoa.h
 $(lpfx)ecvtbuf.$(oext): ecvtbuf.c mprec.h
 $(lpfx)mbtowc_r.$(oext): mbtowc_r.c mbctype.h
 $(lpfx)mprec.$(oext): mprec.c mprec.h
diff --git a/newlib/libc/stdlib/gdtoa-dmisc.c b/newlib/libc/stdlib/gdtoa-dmisc.c
new file mode 100644
index 000000000..332023dae
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-dmisc.c
@@ -0,0 +1,230 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include <newlib.h>
+#include <sys/config.h>
+
+#ifdef _USE_GDTOA
+#include "gdtoaimp.h"
+
+#ifndef MULTIPLE_THREADS
+ char *dtoa_result;
+#endif
+
+ char *
+#ifdef KR_headers
+rv_alloc(ptr, i) struct _reent *ptr, int i;
+#else
+rv_alloc(struct _reent *ptr, int i)
+#endif
+{
+	int j, k, *r;
+
+	j = sizeof(ULong);
+	for(k = 0;
+		sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i;
+		j <<= 1)
+			k++;
+	r = (int*)Balloc(ptr, k);
+	if (r == NULL)
+		return (
+#ifndef MULTIPLE_THREADS
+		dtoa_result =
+#endif
+			NULL);
+	*r = k;
+	return
+#ifndef MULTIPLE_THREADS
+	dtoa_result =
+#endif
+		(char *)(r+1);
+	}
+
+ char *
+#ifdef KR_headers
+nrv_alloc(ptr, s, rve, n) struct _reent *ptr, char *s, **rve; int n;
+#else
+nrv_alloc(struct _reent *ptr, char *s, char **rve, int n)
+#endif
+{
+	char *rv, *t;
+
+	t = rv = rv_alloc(ptr, n);
+	if (t == NULL)
+		return (NULL);
+	while((*t = *s++) !=0)
+		t++;
+	if (rve)
+		*rve = t;
+	return rv;
+	}
+
+/* freedtoa(s) must be used to free values s returned by dtoa
+ * when MULTIPLE_THREADS is #defined.  It should be used in all cases,
+ * but for consistency with earlier versions of dtoa, it is optional
+ * when MULTIPLE_THREADS is not defined.
+ */
+
+ void
+#ifdef KR_headers
+freedtoa(ptr, s) struct _reent *ptr, char *s;
+#else
+freedtoa(struct _reent *ptr, char *s)
+#endif
+{
+	Bigint *b = (Bigint *)((int *)s - 1);
+	b->_maxwds = 1 << (b->_k = *(int*)b);
+	Bfree(ptr, b);
+#ifndef MULTIPLE_THREADS
+	if (s == dtoa_result)
+		dtoa_result = 0;
+#endif
+	}
+DEF_STRONG(freedtoa);
+
+ int
+quorem
+#ifdef KR_headers
+	(b, S) Bigint *b, *S;
+#else
+	(Bigint *b, Bigint *S)
+#endif
+{
+	int n;
+	ULong *bx, *bxe, q, *sx, *sxe;
+#ifdef ULLong
+	ULLong borrow, carry, y, ys;
+#else
+	ULong borrow, carry, y, ys;
+#ifdef Pack_32
+	ULong si, z, zs;
+#endif
+#endif
+
+	n = S->_wds;
+#ifdef DEBUG
+	/*debug*/ if (b->_wds > n)
+	/*debug*/	Bug("oversize b in quorem");
+#endif
+	if (b->_wds < n)
+		return 0;
+	sx = S->_x;
+	sxe = sx + --n;
+	bx = b->_x;
+	bxe = bx + n;
+	q = *bxe / (*sxe + 1);	/* ensure q <= true quotient */
+#ifdef DEBUG
+	/*debug*/ if (q > 9)
+	/*debug*/	Bug("oversized quotient in quorem");
+#endif
+	if (q) {
+		borrow = 0;
+		carry = 0;
+		do {
+#ifdef ULLong
+			ys = *sx++ * (ULLong)q + carry;
+			carry = ys >> 32;
+			y = *bx - (ys & 0xffffffffUL) - borrow;
+			borrow = y >> 32 & 1UL;
+			*bx++ = y & 0xffffffffUL;
+#else
+#ifdef Pack_32
+			si = *sx++;
+			ys = (si & 0xffff) * q + carry;
+			zs = (si >> 16) * q + (ys >> 16);
+			carry = zs >> 16;
+			y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			z = (*bx >> 16) - (zs & 0xffff) - borrow;
+			borrow = (z & 0x10000) >> 16;
+			Storeinc(bx, z, y);
+#else
+			ys = *sx++ * q + carry;
+			carry = ys >> 16;
+			y = *bx - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			*bx++ = y & 0xffff;
+#endif
+#endif
+			}
+			while(sx <= sxe);
+		if (!*bxe) {
+			bx = b->_x;
+			while(--bxe > bx && !*bxe)
+				--n;
+			b->_wds = n;
+			}
+		}
+	if (cmp(b, S) >= 0) {
+		q++;
+		borrow = 0;
+		carry = 0;
+		bx = b->_x;
+		sx = S->_x;
+		do {
+#ifdef ULLong
+			ys = *sx++ + carry;
+			carry = ys >> 32;
+			y = *bx - (ys & 0xffffffffUL) - borrow;
+			borrow = y >> 32 & 1UL;
+			*bx++ = y & 0xffffffffUL;
+#else
+#ifdef Pack_32
+			si = *sx++;
+			ys = (si & 0xffff) + carry;
+			zs = (si >> 16) + (ys >> 16);
+			carry = zs >> 16;
+			y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			z = (*bx >> 16) - (zs & 0xffff) - borrow;
+			borrow = (z & 0x10000) >> 16;
+			Storeinc(bx, z, y);
+#else
+			ys = *sx++ + carry;
+			carry = ys >> 16;
+			y = *bx - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			*bx++ = y & 0xffff;
+#endif
+#endif
+			}
+			while(sx <= sxe);
+		bx = b->_x;
+		bxe = bx + n;
+		if (!*bxe) {
+			while(--bxe > bx && !*bxe)
+				--n;
+			b->_wds = n;
+			}
+		}
+	return q;
+	}
+#endif /* _USE_GDTOA */
diff --git a/newlib/libc/stdlib/gdtoa-dtoa.c b/newlib/libc/stdlib/gdtoa-dtoa.c
new file mode 100644
index 000000000..f05265855
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-dtoa.c
@@ -0,0 +1,846 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998, 1999 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include <newlib.h>
+#include <sys/config.h>
+
+#ifdef _USE_GDTOA
+#include "gdtoaimp.h"
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ *	1. Rather than iterating, we use a simple numeric overestimate
+ *	   to determine k = floor(log10(d)).  We scale relevant
+ *	   quantities using O(log2(k)) rather than O(k) multiplications.
+ *	2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ *	   try to generate digits strictly left to right.  Instead, we
+ *	   compute with fewer bits and propagate the carry if necessary
+ *	   when rounding the final digit up.  This is often faster.
+ *	3. Under the assumption that input will be rounded nearest,
+ *	   mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ *	   That is, we allow equality in stopping tests when the
+ *	   round-nearest rule will give the same floating-point value
+ *	   as would satisfaction of the stopping test with strict
+ *	   inequality.
+ *	4. We remove common factors of powers of 2 from relevant
+ *	   quantities.
+ *	5. When converting floating-point integers less than 1e16,
+ *	   we use floating-point arithmetic rather than resorting
+ *	   to multiple-precision integers.
+ *	6. When asked to produce fewer than 15 digits, we first try
+ *	   to get by with floating-point arithmetic; we resort to
+ *	   multiple-precision integer arithmetic only if we cannot
+ *	   guarantee that the floating-point calculation has given
+ *	   the correctly rounded result.  For k requested digits and
+ *	   "uniformly" distributed input, the probability is
+ *	   something like 10^(k-15) that we must resort to the Long
+ *	   calculation.
+ */
+
+#ifdef Honor_FLT_ROUNDS
+#undef Check_FLT_ROUNDS
+#define Check_FLT_ROUNDS
+#else
+#define Rounding Flt_Rounds
+#endif
+
+ char *
+dtoa
+#ifdef KR_headers
+	(ptr, d0, mode, ndigits, decpt, sign, rve)
+	struct _reent *ptr,
+	double d0; int mode, ndigits, *decpt, *sign; char **rve;
+#else
+	(struct _reent *ptr,
+	 double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
+#endif
+{
+ /*	Arguments ndigits, decpt, sign are similar to those
+	of ecvt and fcvt; trailing zeros are suppressed from
+	the returned string.  If not null, *rve is set to point
+	to the end of the return value.  If d is +-Infinity or NaN,
+	then *decpt is set to 9999.
+
+	mode:
+		0 ==> shortest string that yields d when read in
+			and rounded to nearest.
+		1 ==> like 0, but with Steele & White stopping rule;
+			e.g. with IEEE P754 arithmetic , mode 0 gives
+			1e23 whereas mode 1 gives 9.999999999999999e22.
+		2 ==> max(1,ndigits) significant digits.  This gives a
+			return value similar to that of ecvt, except
+			that trailing zeros are suppressed.
+		3 ==> through ndigits past the decimal point.  This
+			gives a return value similar to that from fcvt,
+			except that trailing zeros are suppressed, and
+			ndigits can be negative.
+		4,5 ==> similar to 2 and 3, respectively, but (in
+			round-nearest mode) with the tests of mode 0 to
+			possibly return a shorter string that rounds to d.
+			With IEEE arithmetic and compilation with
+			-DHonor_FLT_ROUNDS, modes 4 and 5 behave the same
+			as modes 2 and 3 when FLT_ROUNDS != 1.
+		6-9 ==> Debugging modes similar to mode - 4:  don't try
+			fast floating-point estimate (if applicable).
+
+		Values of mode other than 0-9 are treated as mode 0.
+
+		Sufficient space is allocated to the return value
+		to hold the suppressed trailing zeros.
+	*/
+
+	int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,
+		j, j1, k, k0, k_check, leftright, m2, m5, s2, s5,
+		spec_case, try_quick;
+	Long L;
+#ifndef Sudden_Underflow
+	int denorm;
+	ULong x;
+#endif
+	Bigint *b, *b1, *delta, *mlo, *mhi, *S;
+	U d, d2, eps;
+	double ds;
+	char *s, *s0;
+#ifdef SET_INEXACT
+	int inexact, oldinexact;
+#endif
+#ifdef Honor_FLT_ROUNDS /*{*/
+	int Rounding;
+#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */
+	Rounding = Flt_Rounds;
+#else /*}{*/
+	Rounding = 1;
+	switch(fegetround()) {
+	  case FE_TOWARDZERO:	Rounding = 0; break;
+	  case FE_UPWARD:	Rounding = 2; break;
+	  case FE_DOWNWARD:	Rounding = 3;
+	  }
+#endif /*}}*/
+#endif /*}*/
+
+#ifndef MULTIPLE_THREADS
+	if (dtoa_result) {
+		freedtoa(ptr, dtoa_result);
+		dtoa_result = 0;
+		}
+#endif
+	d.d = d0;
+	if (word0(d) & Sign_bit) {
+		/* set sign for everything, including 0's and NaNs */
+		*sign = 1;
+		word0(d) &= ~Sign_bit;	/* clear sign bit */
+		}
+	else
+		*sign = 0;
+
+#if defined(IEEE_Arith) + defined(VAX)
+#ifdef IEEE_Arith
+	if ((word0(d) & Exp_mask) == Exp_mask)
+#else
+	if (word0(d)  == 0x8000)
+#endif
+		{
+		/* Infinity or NaN */
+		*decpt = 9999;
+#ifdef IEEE_Arith
+		if (!word1(d) && !(word0(d) & 0xfffff))
+			return nrv_alloc(ptr, "Infinity", rve, 8);
+#endif
+		return nrv_alloc(ptr, "NaN", rve, 3);
+		}
+#endif
+#ifdef IBM
+	dval(d) += 0; /* normalize */
+#endif
+	if (!dval(d)) {
+		*decpt = 1;
+		return nrv_alloc(ptr, "0", rve, 1);
+		}
+
+#ifdef SET_INEXACT
+	try_quick = oldinexact = get_inexact();
+	inexact = 1;
+#endif
+#ifdef Honor_FLT_ROUNDS
+	if (Rounding >= 2) {
+		if (*sign)
+			Rounding = Rounding == 2 ? 0 : 2;
+		else
+			if (Rounding != 2)
+				Rounding = 0;
+		}
+#endif
+
+	b = d2b(ptr, dval(d), &be, &bbits);
+	if (b == NULL)
+		return (NULL);
+#ifdef Sudden_Underflow
+	i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
+#else
+	if (( i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)) )!=0) {
+#endif
+		dval(d2) = dval(d);
+		word0(d2) &= Frac_mask1;
+		word0(d2) |= Exp_11;
+#ifdef IBM
+		if (( j = 11 - hi0bits(word0(d2) & Frac_mask) )!=0)
+			dval(d2) /= 1 << j;
+#endif
+
+		/* log(x)	~=~ log(1.5) + (x-1.5)/1.5
+		 * log10(x)	 =  log(x) / log(10)
+		 *		~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+		 * log10(&d) = (i-Bias)*log(2)/log(10) + log10(&d2)
+		 *
+		 * This suggests computing an approximation k to log10(&d) by
+		 *
+		 * k = (i - Bias)*0.301029995663981
+		 *	+ ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+		 *
+		 * We want k to be too large rather than too small.
+		 * The error in the first-order Taylor series approximation
+		 * is in our favor, so we just round up the constant enough
+		 * to compensate for any error in the multiplication of
+		 * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+		 * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+		 * adding 1e-13 to the constant term more than suffices.
+		 * Hence we adjust the constant term to 0.1760912590558.
+		 * (We could get a more accurate k by invoking log10,
+		 *  but this is probably not worthwhile.)
+		 */
+
+		i -= Bias;
+#ifdef IBM
+		i <<= 2;
+		i += j;
+#endif
+#ifndef Sudden_Underflow
+		denorm = 0;
+		}
+	else {
+		/* d is denormalized */
+
+		i = bbits + be + (Bias + (P-1) - 1);
+		x = i > 32  ? word0(d) << (64 - i) | word1(d) >> (i - 32)
+			    : word1(d) << (32 - i);
+		dval(d2) = x;
+		word0(d2) -= 31*Exp_msk1; /* adjust exponent */
+		i -= (Bias + (P-1) - 1) + 1;
+		denorm = 1;
+		}
+#endif
+	ds = (dval(d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
+	k = (int)ds;
+	if (ds < 0. && ds != k)
+		k--;	/* want k = floor(ds) */
+	k_check = 1;
+	if (k >= 0 && k <= Ten_pmax) {
+		if (dval(d) < tens[k])
+			k--;
+		k_check = 0;
+		}
+	j = bbits - i - 1;
+	if (j >= 0) {
+		b2 = 0;
+		s2 = j;
+		}
+	else {
+		b2 = -j;
+		s2 = 0;
+		}
+	if (k >= 0) {
+		b5 = 0;
+		s5 = k;
+		s2 += k;
+		}
+	else {
+		b2 -= k;
+		b5 = -k;
+		s5 = 0;
+		}
+	if (mode < 0 || mode > 9)
+		mode = 0;
+
+#ifndef SET_INEXACT
+#ifdef Check_FLT_ROUNDS
+	try_quick = Rounding == 1;
+#else
+	try_quick = 1;
+#endif
+#endif /*SET_INEXACT*/
+
+	if (mode > 5) {
+		mode -= 4;
+		try_quick = 0;
+		}
+	leftright = 1;
+	ilim = ilim1 = -1;	/* Values for cases 0 and 1; done here to */
+				/* silence erroneous "gcc -Wall" warning. */
+	switch(mode) {
+		case 0:
+		case 1:
+			i = 18;
+			ndigits = 0;
+			break;
+		case 2:
+			leftright = 0;
+			/* no break */
+		case 4:
+			if (ndigits <= 0)
+				ndigits = 1;
+			ilim = ilim1 = i = ndigits;
+			break;
+		case 3:
+			leftright = 0;
+			/* no break */
+		case 5:
+			i = ndigits + k + 1;
+			ilim = i;
+			ilim1 = i - 1;
+			if (i <= 0)
+				i = 1;
+		}
+	s = s0 = rv_alloc(ptr, i);
+	if (s == NULL)
+		return (NULL);
+
+#ifdef Honor_FLT_ROUNDS
+	if (mode > 1 && Rounding != 1)
+		leftright = 0;
+#endif
+
+	if (ilim >= 0 && ilim <= Quick_max && try_quick) {
+
+		/* Try to get by with floating-point arithmetic. */
+
+		i = 0;
+		dval(d2) = dval(d);
+		k0 = k;
+		ilim0 = ilim;
+		ieps = 2; /* conservative */
+		if (k > 0) {
+			ds = tens[k&0xf];
+			j = k >> 4;
+			if (j & Bletch) {
+				/* prevent overflows */
+				j &= Bletch - 1;
+				dval(d) /= bigtens[n_bigtens-1];
+				ieps++;
+				}
+			for(; j; j >>= 1, i++)
+				if (j & 1) {
+					ieps++;
+					ds *= bigtens[i];
+					}
+			dval(d) /= ds;
+			}
+		else if (( j1 = -k )!=0) {
+			dval(d) *= tens[j1 & 0xf];
+			for(j = j1 >> 4; j; j >>= 1, i++)
+				if (j & 1) {
+					ieps++;
+					dval(d) *= bigtens[i];
+					}
+			}
+		if (k_check && dval(d) < 1. && ilim > 0) {
+			if (ilim1 <= 0)
+				goto fast_failed;
+			ilim = ilim1;
+			k--;
+			dval(d) *= 10.;
+			ieps++;
+			}
+		dval(eps) = ieps*dval(d) + 7.;
+		word0(eps) -= (P-1)*Exp_msk1;
+		if (ilim == 0) {
+			S = mhi = 0;
+			dval(d) -= 5.;
+			if (dval(d) > dval(eps))
+				goto one_digit;
+			if (dval(d) < -dval(eps))
+				goto no_digits;
+			goto fast_failed;
+			}
+#ifndef No_leftright
+		if (leftright) {
+			/* Use Steele & White method of only
+			 * generating digits needed.
+			 */
+			dval(eps) = 0.5/tens[ilim-1] - dval(eps);
+			for(i = 0;;) {
+				L = dval(d);
+				dval(d) -= L;
+				*s++ = '0' + (int)L;
+				if (dval(d) < dval(eps))
+					goto ret1;
+				if (1. - dval(d) < dval(eps))
+					goto bump_up;
+				if (++i >= ilim)
+					break;
+				dval(eps) *= 10.;
+				dval(d) *= 10.;
+				}
+			}
+		else {
+#endif
+			/* Generate ilim digits, then fix them up. */
+			dval(eps) *= tens[ilim-1];
+			for(i = 1;; i++, dval(d) *= 10.) {
+				L = (Long)(dval(d));
+				if (!(dval(d) -= L))
+					ilim = i;
+				*s++ = '0' + (int)L;
+				if (i == ilim) {
+					if (dval(d) > 0.5 + dval(eps))
+						goto bump_up;
+					else if (dval(d) < 0.5 - dval(eps)) {
+						while(*--s == '0');
+						s++;
+						goto ret1;
+						}
+					break;
+					}
+				}
+#ifndef No_leftright
+			}
+#endif
+ fast_failed:
+		s = s0;
+		dval(d) = dval(d2);
+		k = k0;
+		ilim = ilim0;
+		}
+
+	/* Do we have a "small" integer? */
+
+	if (be >= 0 && k <= Int_max) {
+		/* Yes. */
+		ds = tens[k];
+		if (ndigits < 0 && ilim <= 0) {
+			S = mhi = 0;
+			if (ilim < 0 || dval(d) <= 5*ds)
+				goto no_digits;
+			goto one_digit;
+			}
+		for(i = 1;; i++, dval(d) *= 10.) {
+			L = (Long)(dval(d) / ds);
+			dval(d) -= L*ds;
+#ifdef Check_FLT_ROUNDS
+			/* If FLT_ROUNDS == 2, L will usually be high by 1 */
+			if (dval(d) < 0) {
+				L--;
+				dval(d) += ds;
+				}
+#endif
+			*s++ = '0' + (int)L;
+			if (!dval(d)) {
+#ifdef SET_INEXACT
+				inexact = 0;
+#endif
+				break;
+				}
+			if (i == ilim) {
+#ifdef Honor_FLT_ROUNDS
+				if (mode > 1)
+				switch(Rounding) {
+				  case 0: goto ret1;
+				  case 2: goto bump_up;
+				  }
+#endif
+				dval(d) += dval(d);
+#ifdef ROUND_BIASED
+				if (dval(d) >= ds)
+#else
+				if (dval(d) > ds || (dval(d) == ds && L & 1))
+#endif
+					{
+ bump_up:
+					while(*--s == '9')
+						if (s == s0) {
+							k++;
+							*s = '0';
+							break;
+							}
+					++*s++;
+					}
+				break;
+				}
+			}
+		goto ret1;
+		}
+
+	m2 = b2;
+	m5 = b5;
+	mhi = mlo = 0;
+	if (leftright) {
+		i =
+#ifndef Sudden_Underflow
+			denorm ? be + (Bias + (P-1) - 1 + 1) :
+#endif
+#ifdef IBM
+			1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3);
+#else
+			1 + P - bbits;
+#endif
+		b2 += i;
+		s2 += i;
+		mhi = i2b(ptr, 1);
+		if (mhi == NULL)
+			return (NULL);
+		}
+	if (m2 > 0 && s2 > 0) {
+		i = m2 < s2 ? m2 : s2;
+		b2 -= i;
+		m2 -= i;
+		s2 -= i;
+		}
+	if (b5 > 0) {
+		if (leftright) {
+			if (m5 > 0) {
+				mhi = pow5mult(ptr, mhi, m5);
+				if (mhi == NULL)
+					return (NULL);
+				b1 = mult(ptr, mhi, b);
+				if (b1 == NULL)
+					return (NULL);
+				Bfree(ptr, b);
+				b = b1;
+				}
+			if (( j = b5 - m5 )!=0) {
+				b = pow5mult(ptr, b, j);
+				if (b == NULL)
+					return (NULL);
+				}
+			}
+		else {
+			b = pow5mult(ptr, b, b5);
+			if (b == NULL)
+				return (NULL);
+			}
+		}
+	S = i2b(ptr, 1);
+	if (S == NULL)
+		return (NULL);
+	if (s5 > 0) {
+		S = pow5mult(ptr, S, s5);
+		if (S == NULL)
+			return (NULL);
+		}
+
+	/* Check for special case that d is a normalized power of 2. */
+
+	spec_case = 0;
+	if ((mode < 2 || leftright)
+#ifdef Honor_FLT_ROUNDS
+			&& Rounding == 1
+#endif
+				) {
+		if (!word1(d) && !(word0(d) & Bndry_mask)
+#ifndef Sudden_Underflow
+		 && word0(d) & (Exp_mask & ~Exp_msk1)
+#endif
+				) {
+			/* The special case */
+			b2 += Log2P;
+			s2 += Log2P;
+			spec_case = 1;
+			}
+		}
+
+	/* Arrange for convenient computation of quotients:
+	 * shift left if necessary so divisor has 4 leading 0 bits.
+	 *
+	 * Perhaps we should just compute leading 28 bits of S once
+	 * and for all and pass them and a shift to quorem, so it
+	 * can do shifts and ors to compute the numerator for q.
+	 */
+#ifdef Pack_32
+	if (( i = ((s5 ? 32 - hi0bits(S->_x[S->_wds-1]) : 1) + s2) & 0x1f )!=0)
+		i = 32 - i;
+#else
+	if (( i = ((s5 ? 32 - hi0bits(S->_x[S->_wds-1]) : 1) + s2) & 0xf )!=0)
+		i = 16 - i;
+#endif
+	if (i > 4) {
+		i -= 4;
+		b2 += i;
+		m2 += i;
+		s2 += i;
+		}
+	else if (i < 4) {
+		i += 28;
+		b2 += i;
+		m2 += i;
+		s2 += i;
+		}
+	if (b2 > 0) {
+		b = lshift(ptr, b, b2);
+		if (b == NULL)
+			return (NULL);
+		}
+	if (s2 > 0) {
+		S = lshift(ptr, S, s2);
+		if (S == NULL)
+			return (NULL);
+		}
+	if (k_check) {
+		if (cmp(b,S) < 0) {
+			k--;
+			b = multadd(ptr, b, 10, 0); /* we botched the k estimate */
+			if (b == NULL)
+				return (NULL);
+			if (leftright) {
+				mhi = multadd(ptr, mhi, 10, 0);
+				if (mhi == NULL)
+					return (NULL);
+				}
+			ilim = ilim1;
+			}
+		}
+	if (ilim <= 0 && (mode == 3 || mode == 5)) {
+		S = multadd(ptr, S,5,0);
+		if (S == NULL)
+			return (NULL);
+		if (ilim < 0 || cmp(b,S) <= 0) {
+			/* no digits, fcvt style */
+ no_digits:
+			k = -1 - ndigits;
+			goto ret;
+			}
+ one_digit:
+		*s++ = '1';
+		k++;
+		goto ret;
+		}
+	if (leftright) {
+		if (m2 > 0) {
+			mhi = lshift(ptr, mhi, m2);
+			if (mhi == NULL)
+				return (NULL);
+			}
+
+		/* Compute mlo -- check for special case
+		 * that d is a normalized power of 2.
+		 */
+
+		mlo = mhi;
+		if (spec_case) {
+			mhi = Balloc(ptr, mhi->_k);
+			if (mhi == NULL)
+				return (NULL);
+			Bcopy(mhi, mlo);
+			mhi = lshift(ptr, mhi, Log2P);
+			if (mhi == NULL)
+				return (NULL);
+			}
+
+		for(i = 1;;i++) {
+			dig = quorem(b,S) + '0';
+			/* Do we yet have the shortest decimal string
+			 * that will round to d?
+			 */
+			j = cmp(b, mlo);
+			delta = diff(ptr, S, mhi);
+			if (delta == NULL)
+				return (NULL);
+			j1 = delta->_sign ? 1 : cmp(b, delta);
+			Bfree(ptr, delta);
+#ifndef ROUND_BIASED
+			if (j1 == 0 && mode != 1 && !(word1(d) & 1)
+#ifdef Honor_FLT_ROUNDS
+				&& Rounding >= 1
+#endif
+								   ) {
+				if (dig == '9')
+					goto round_9_up;
+				if (j > 0)
+					dig++;
+#ifdef SET_INEXACT
+				else if (!b->_x[0] && b->_wds <= 1)
+					inexact = 0;
+#endif
+				*s++ = dig;
+				goto ret;
+				}
+#endif
+			if (j < 0 || (j == 0 && mode != 1
+#ifndef ROUND_BIASED
+							&& !(word1(d) & 1)
+#endif
+					)) {
+				if (!b->_x[0] && b->_wds <= 1) {
+#ifdef SET_INEXACT
+					inexact = 0;
+#endif
+					goto accept_dig;
+					}
+#ifdef Honor_FLT_ROUNDS
+				if (mode > 1)
+				 switch(Rounding) {
+				  case 0: goto accept_dig;
+				  case 2: goto keep_dig;
+				  }
+#endif /*Honor_FLT_ROUNDS*/
+				if (j1 > 0) {
+					b = lshift(ptr, b, 1);
+					if (b == NULL)
+						return (NULL);
+					j1 = cmp(b, S);
+#ifdef ROUND_BIASED
+					if (j1 >= 0 /*)*/
+#else
+					if ((j1 > 0 || (j1 == 0 && dig & 1))
+#endif
+					&& dig++ == '9')
+						goto round_9_up;
+					}
+ accept_dig:
+				*s++ = dig;
+				goto ret;
+				}
+			if (j1 > 0) {
+#ifdef Honor_FLT_ROUNDS
+				if (!Rounding)
+					goto accept_dig;
+#endif
+				if (dig == '9') { /* possible if i == 1 */
+ round_9_up:
+					*s++ = '9';
+					goto roundoff;
+					}
+				*s++ = dig + 1;
+				goto ret;
+				}
+#ifdef Honor_FLT_ROUNDS
+ keep_dig:
+#endif
+			*s++ = dig;
+			if (i == ilim)
+				break;
+			b = multadd(ptr, b, 10, 0);
+			if (b == NULL)
+				return (NULL);
+			if (mlo == mhi) {
+				mlo = mhi = multadd(ptr, mhi, 10, 0);
+				if (mlo == NULL)
+					return (NULL);
+				}
+			else {
+				mlo = multadd(ptr, mlo, 10, 0);
+				if (mlo == NULL)
+					return (NULL);
+				mhi = multadd(ptr, mhi, 10, 0);
+				if (mhi == NULL)
+					return (NULL);
+				}
+			}
+		}
+	else
+		for(i = 1;; i++) {
+			*s++ = dig = quorem(b,S) + '0';
+			if (!b->_x[0] && b->_wds <= 1) {
+#ifdef SET_INEXACT
+				inexact = 0;
+#endif
+				goto ret;
+				}
+			if (i >= ilim)
+				break;
+			b = multadd(ptr, b, 10, 0);
+			if (b == NULL)
+				return (NULL);
+			}
+
+	/* Round off last digit */
+
+#ifdef Honor_FLT_ROUNDS
+	switch(Rounding) {
+	  case 0: goto trimzeros;
+	  case 2: goto roundoff;
+	  }
+#endif
+	b = lshift(ptr, b, 1);
+	if (b == NULL)
+		return (NULL);
+	j = cmp(b, S);
+#ifdef ROUND_BIASED
+	if (j >= 0)
+#else
+	if (j > 0 || (j == 0 && dig & 1))
+#endif
+		{
+ roundoff:
+		while(*--s == '9')
+			if (s == s0) {
+				k++;
+				*s++ = '1';
+				goto ret;
+				}
+		++*s++;
+		}
+	else {
+#ifdef Honor_FLT_ROUNDS
+ trimzeros:
+#endif
+		while(*--s == '0');
+		s++;
+		}
+ ret:
+	Bfree(ptr, S);
+	if (mhi) {
+		if (mlo && mlo != mhi)
+			Bfree(ptr, mlo);
+		Bfree(ptr, mhi);
+		}
+ ret1:
+#ifdef SET_INEXACT
+	if (inexact) {
+		if (!oldinexact) {
+			word0(d) = Exp_1 + (70 << Exp_shift);
+			word1(d) = 0;
+			dval(d) += 1.;
+			}
+		}
+	else if (!oldinexact)
+		clear_inexact();
+#endif
+	Bfree(ptr, b);
+	*s = 0;
+	*decpt = k + 1;
+	if (rve)
+		*rve = s;
+	return s0;
+}
+#endif /* _USE_GDTOA */
diff --git a/newlib/libc/stdlib/gdtoa-gdtoa.c b/newlib/libc/stdlib/gdtoa-gdtoa.c
new file mode 100644
index 000000000..da2338c48
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-gdtoa.c
@@ -0,0 +1,837 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998, 1999 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include <newlib.h>
+#include <sys/config.h>
+
+#ifdef _USE_GDTOA
+#include "gdtoaimp.h"
+
+ static Bigint *
+#ifdef KR_headers
+bitstob(ptr, bits, nbits, bbits) ULong *bits;
+struct _reent ptr, int nbits; int *bbits;
+#else
+bitstob(struct _reent *ptr, ULong *bits, int nbits, int *bbits)
+#endif
+{
+	int i, k;
+	Bigint *b;
+	ULong *be, *x, *x0;
+
+	i = ULbits;
+	k = 0;
+	while(i < nbits) {
+		i <<= 1;
+		k++;
+		}
+#ifndef Pack_32
+	if (!k)
+		k = 1;
+#endif
+	b = Balloc(ptr, k);
+	if (b == NULL)
+		return (NULL);
+	be = bits + ((nbits - 1) >> kshift);
+	x = x0 = b->_x;
+	do {
+		*x++ = *bits & ALL_ON;
+#ifdef Pack_16
+		*x++ = (*bits >> 16) & ALL_ON;
+#endif
+		} while(++bits <= be);
+	i = x - x0;
+	while(!x0[--i])
+		if (!i) {
+			b->_wds = 0;
+			*bbits = 0;
+			goto ret;
+			}
+	b->_wds = i + 1;
+	*bbits = i*ULbits + 32 - hi0bits(b->_x[i]);
+ ret:
+	return b;
+	}
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ *	1. Rather than iterating, we use a simple numeric overestimate
+ *	   to determine k = floor(log10(d)).  We scale relevant
+ *	   quantities using O(log2(k)) rather than O(k) multiplications.
+ *	2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ *	   try to generate digits strictly left to right.  Instead, we
+ *	   compute with fewer bits and propagate the carry if necessary
+ *	   when rounding the final digit up.  This is often faster.
+ *	3. Under the assumption that input will be rounded nearest,
+ *	   mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ *	   That is, we allow equality in stopping tests when the
+ *	   round-nearest rule will give the same floating-point value
+ *	   as would satisfaction of the stopping test with strict
+ *	   inequality.
+ *	4. We remove common factors of powers of 2 from relevant
+ *	   quantities.
+ *	5. When converting floating-point integers less than 1e16,
+ *	   we use floating-point arithmetic rather than resorting
+ *	   to multiple-precision integers.
+ *	6. When asked to produce fewer than 15 digits, we first try
+ *	   to get by with floating-point arithmetic; we resort to
+ *	   multiple-precision integer arithmetic only if we cannot
+ *	   guarantee that the floating-point calculation has given
+ *	   the correctly rounded result.  For k requested digits and
+ *	   "uniformly" distributed input, the probability is
+ *	   something like 10^(k-15) that we must resort to the Long
+ *	   calculation.
+ */
+
+ char *
+gdtoa
+#ifdef KR_headers
+	(ptr, fpi, be, bits, kindp, mode, ndigits, decpt, rve)
+	struct _reent *ptr, FPI *fpi; int be; ULong *bits;
+	int *kindp, mode, ndigits, *decpt; char **rve;
+#else
+	(struct _reent *ptr, FPI *fpi, int be, ULong *bits, int *kindp,
+	 int mode, int ndigits, int *decpt, char **rve)
+#endif
+{
+ /*	Arguments ndigits and decpt are similar to the second and third
+	arguments of ecvt and fcvt; trailing zeros are suppressed from
+	the returned string.  If not null, *rve is set to point
+	to the end of the return value.  If d is +-Infinity or NaN,
+	then *decpt is set to 9999.
+	be = exponent: value = (integer represented by bits) * (2 to the power of be).
+
+	mode:
+		0 ==> shortest string that yields d when read in
+			and rounded to nearest.
+		1 ==> like 0, but with Steele & White stopping rule;
+			e.g. with IEEE P754 arithmetic , mode 0 gives
+			1e23 whereas mode 1 gives 9.999999999999999e22.
+		2 ==> max(1,ndigits) significant digits.  This gives a
+			return value similar to that of ecvt, except
+			that trailing zeros are suppressed.
+		3 ==> through ndigits past the decimal point.  This
+			gives a return value similar to that from fcvt,
+			except that trailing zeros are suppressed, and
+			ndigits can be negative.
+		4-9 should give the same return values as 2-3, i.e.,
+			4 <= mode <= 9 ==> same return as mode
+			2 + (mode & 1).  These modes are mainly for
+			debugging; often they run slower but sometimes
+			faster than modes 2-3.
+		4,5,8,9 ==> left-to-right digit generation.
+		6-9 ==> don't try fast floating-point estimate
+			(if applicable).
+
+		Values of mode other than 0-9 are treated as mode 0.
+
+		Sufficient space is allocated to the return value
+		to hold the suppressed trailing zeros.
+	*/
+
+	int bbits, b2, b5, be0, dig, i, ieps, ilim, ilim0, ilim1, inex;
+	int j, j1, k, k0, k_check, kind, leftright, m2, m5, nbits;
+	int rdir, s2, s5, spec_case, try_quick;
+	Long L;
+	Bigint *b, *b1, *delta, *mlo, *mhi, *mhi1, *S;
+	double d2, ds;
+	char *s, *s0;
+	U d, eps;
+
+#ifndef MULTIPLE_THREADS
+	if (dtoa_result) {
+		freedtoa(ptr, dtoa_result);
+		dtoa_result = 0;
+		}
+#endif
+	inex = 0;
+	kind = *kindp &= ~STRTOG_Inexact;
+	switch(kind & STRTOG_Retmask) {
+	  case STRTOG_Zero:
+		goto ret_zero;
+	  case STRTOG_Normal:
+	  case STRTOG_Denormal:
+		break;
+	  case STRTOG_Infinite:
+		*decpt = -32768;
+		return nrv_alloc(ptr, "Infinity", rve, 8);
+	  case STRTOG_NaN:
+		*decpt = -32768;
+		return nrv_alloc(ptr, "NaN", rve, 3);
+	  default:
+		return 0;
+	  }
+	b = bitstob(ptr, bits, nbits = fpi->nbits, &bbits);
+	if (b == NULL)
+		return (NULL);
+	be0 = be;
+	if ( (i = trailz(b)) !=0) {
+		rshift(b, i);
+		be += i;
+		bbits -= i;
+		}
+	if (!b->_wds) {
+		Bfree(ptr, b);
+ ret_zero:
+		*decpt = 1;
+		return nrv_alloc(ptr, "0", rve, 1);
+		}
+
+	dval(d) = b2d(b, &i);
+	i = be + bbits - 1;
+	word0(d) &= Frac_mask1;
+	word0(d) |= Exp_11;
+#ifdef IBM
+	if ( (j = 11 - hi0bits(word0(d) & Frac_mask)) !=0)
+		dval(d) /= 1 << j;
+#endif
+
+	/* log(x)	~=~ log(1.5) + (x-1.5)/1.5
+	 * log10(x)	 =  log(x) / log(10)
+	 *		~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+	 * log10(&d) = (i-Bias)*log(2)/log(10) + log10(d2)
+	 *
+	 * This suggests computing an approximation k to log10(&d) by
+	 *
+	 * k = (i - Bias)*0.301029995663981
+	 *	+ ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+	 *
+	 * We want k to be too large rather than too small.
+	 * The error in the first-order Taylor series approximation
+	 * is in our favor, so we just round up the constant enough
+	 * to compensate for any error in the multiplication of
+	 * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+	 * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+	 * adding 1e-13 to the constant term more than suffices.
+	 * Hence we adjust the constant term to 0.1760912590558.
+	 * (We could get a more accurate k by invoking log10,
+	 *  but this is probably not worthwhile.)
+	 */
+#ifdef IBM
+	i <<= 2;
+	i += j;
+#endif
+	ds = (dval(d)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
+
+	/* correct assumption about exponent range */
+	if ((j = i) < 0)
+		j = -j;
+	if ((j -= 1077) > 0)
+		ds += j * 7e-17;
+
+	k = (int)ds;
+	if (ds < 0. && ds != k)
+		k--;	/* want k = floor(ds) */
+	k_check = 1;
+#ifdef IBM
+	j = be + bbits - 1;
+	if ( (j1 = j & 3) !=0)
+		dval(d) *= 1 << j1;
+	word0(d) += j << Exp_shift - 2 & Exp_mask;
+#else
+	word0(d) += (be + bbits - 1) << Exp_shift;
+#endif
+	if (k >= 0 && k <= Ten_pmax) {
+		if (dval(d) < tens[k])
+			k--;
+		k_check = 0;
+		}
+	j = bbits - i - 1;
+	if (j >= 0) {
+		b2 = 0;
+		s2 = j;
+		}
+	else {
+		b2 = -j;
+		s2 = 0;
+		}
+	if (k >= 0) {
+		b5 = 0;
+		s5 = k;
+		s2 += k;
+		}
+	else {
+		b2 -= k;
+		b5 = -k;
+		s5 = 0;
+		}
+	if (mode < 0 || mode > 9)
+		mode = 0;
+	try_quick = 1;
+	if (mode > 5) {
+		mode -= 4;
+		try_quick = 0;
+		}
+	else if (i >= -4 - Emin || i < Emin)
+		try_quick = 0;
+	leftright = 1;
+	ilim = ilim1 = -1;	/* Values for cases 0 and 1; done here to */
+				/* silence erroneous "gcc -Wall" warning. */
+	switch(mode) {
+		case 0:
+		case 1:
+			i = (int)(nbits * .30103) + 3;
+			ndigits = 0;
+			break;
+		case 2:
+			leftright = 0;
+			/* no break */
+		case 4:
+			if (ndigits <= 0)
+				ndigits = 1;
+			ilim = ilim1 = i = ndigits;
+			break;
+		case 3:
+			leftright = 0;
+			/* no break */
+		case 5:
+			i = ndigits + k + 1;
+			ilim = i;
+			ilim1 = i - 1;
+			if (i <= 0)
+				i = 1;
+		}
+	s = s0 = rv_alloc(ptr, i);
+	if (s == NULL)
+		return (NULL);
+
+	if ( (rdir = fpi->rounding - 1) !=0) {
+		if (rdir < 0)
+			rdir = 2;
+		if (kind & STRTOG_Neg)
+			rdir = 3 - rdir;
+		}
+
+	/* Now rdir = 0 ==> round near, 1 ==> round up, 2 ==> round down. */
+
+	if (ilim >= 0 && ilim <= Quick_max && try_quick && !rdir
+#ifndef IMPRECISE_INEXACT
+		&& k == 0
+#endif
+								) {
+
+		/* Try to get by with floating-point arithmetic. */
+
+		i = 0;
+		d2 = dval(d);
+#ifdef IBM
+		if ( (j = 11 - hi0bits(word0(d) & Frac_mask)) !=0)
+			dval(d) /= 1 << j;
+#endif
+		k0 = k;
+		ilim0 = ilim;
+		ieps = 2; /* conservative */
+		if (k > 0) {
+			ds = tens[k&0xf];
+			j = k >> 4;
+			if (j & Bletch) {
+				/* prevent overflows */
+				j &= Bletch - 1;
+				dval(d) /= bigtens[n_bigtens-1];
+				ieps++;
+				}
+			for(; j; j >>= 1, i++)
+				if (j & 1) {
+					ieps++;
+					ds *= bigtens[i];
+					}
+			}
+		else  {
+			ds = 1.;
+			if ( (j1 = -k) !=0) {
+				dval(d) *= tens[j1 & 0xf];
+				for(j = j1 >> 4; j; j >>= 1, i++)
+					if (j & 1) {
+						ieps++;
+						dval(d) *= bigtens[i];
+						}
+				}
+			}
+		if (k_check && dval(d) < 1. && ilim > 0) {
+			if (ilim1 <= 0)
+				goto fast_failed;
+			ilim = ilim1;
+			k--;
+			dval(d) *= 10.;
+			ieps++;
+			}
+		dval(eps) = ieps*dval(d) + 7.;
+		word0(eps) -= (P-1)*Exp_msk1;
+		if (ilim == 0) {
+			S = mhi = 0;
+			dval(d) -= 5.;
+			if (dval(d) > dval(eps))
+				goto one_digit;
+			if (dval(d) < -dval(eps))
+				goto no_digits;
+			goto fast_failed;
+			}
+#ifndef No_leftright
+		if (leftright) {
+			/* Use Steele & White method of only
+			 * generating digits needed.
+			 */
+			dval(eps) = ds*0.5/tens[ilim-1] - dval(eps);
+			for(i = 0;;) {
+				L = (Long)(dval(d)/ds);
+				dval(d) -= L*ds;
+				*s++ = '0' + (int)L;
+				if (dval(d) < dval(eps)) {
+					if (dval(d))
+						inex = STRTOG_Inexlo;
+					goto ret1;
+					}
+				if (ds - dval(d) < dval(eps))
+					goto bump_up;
+				if (++i >= ilim)
+					break;
+				dval(eps) *= 10.;
+				dval(d) *= 10.;
+				}
+			}
+		else {
+#endif
+			/* Generate ilim digits, then fix them up. */
+			dval(eps) *= tens[ilim-1];
+			for(i = 1;; i++, dval(d) *= 10.) {
+				if ( (L = (Long)(dval(d)/ds)) !=0)
+					dval(d) -= L*ds;
+				*s++ = '0' + (int)L;
+				if (i == ilim) {
+					ds *= 0.5;
+					if (dval(d) > ds + dval(eps))
+						goto bump_up;
+					else if (dval(d) < ds - dval(eps)) {
+						if (dval(d))
+							inex = STRTOG_Inexlo;
+						goto clear_trailing0;
+						}
+					break;
+					}
+				}
+#ifndef No_leftright
+			}
+#endif
+ fast_failed:
+		s = s0;
+		dval(d) = d2;
+		k = k0;
+		ilim = ilim0;
+		}
+
+	/* Do we have a "small" integer? */
+
+	if (be >= 0 && k <= Int_max) {
+		/* Yes. */
+		ds = tens[k];
+		if (ndigits < 0 && ilim <= 0) {
+			S = mhi = 0;
+			if (ilim < 0 || dval(d) <= 5*ds)
+				goto no_digits;
+			goto one_digit;
+			}
+		for(i = 1;; i++, dval(d) *= 10.) {
+			L = dval(d) / ds;
+			dval(d) -= L*ds;
+#ifdef Check_FLT_ROUNDS
+			/* If FLT_ROUNDS == 2, L will usually be high by 1 */
+			if (dval(d) < 0) {
+				L--;
+				dval(d) += ds;
+				}
+#endif
+			*s++ = '0' + (int)L;
+			if (dval(d) == 0.)
+				break;
+			if (i == ilim) {
+				if (rdir) {
+					if (rdir == 1)
+						goto bump_up;
+					inex = STRTOG_Inexlo;
+					goto ret1;
+					}
+				dval(d) += dval(d);
+#ifdef ROUND_BIASED
+				if (dval(d) >= ds)
+#else
+				if (dval(d) > ds || (dval(d) == ds && L & 1))
+#endif
+					{
+ bump_up:
+					inex = STRTOG_Inexhi;
+					while(*--s == '9')
+						if (s == s0) {
+							k++;
+							*s = '0';
+							break;
+							}
+					++*s++;
+					}
+				else {
+					inex = STRTOG_Inexlo;
+ clear_trailing0:
+					while(*--s == '0'){}
+					++s;
+					}
+				break;
+				}
+			}
+		goto ret1;
+		}
+
+	m2 = b2;
+	m5 = b5;
+	mhi = mlo = 0;
+	if (leftright) {
+		i = nbits - bbits;
+		if (be - i++ < fpi->emin && mode != 3 && mode != 5) {
+			/* denormal */
+			i = be - fpi->emin + 1;
+			if (mode >= 2 && ilim > 0 && ilim < i)
+				goto small_ilim;
+			}
+		else if (mode >= 2) {
+ small_ilim:
+			j = ilim - 1;
+			if (m5 >= j)
+				m5 -= j;
+			else {
+				s5 += j -= m5;
+				b5 += j;
+				m5 = 0;
+				}
+			if ((i = ilim) < 0) {
+				m2 -= i;
+				i = 0;
+				}
+			}
+		b2 += i;
+		s2 += i;
+		mhi = i2b(ptr, 1);
+		if (mhi == NULL)
+			return (NULL);
+		}
+	if (m2 > 0 && s2 > 0) {
+		i = m2 < s2 ? m2 : s2;
+		b2 -= i;
+		m2 -= i;
+		s2 -= i;
+		}
+	if (b5 > 0) {
+		if (leftright) {
+			if (m5 > 0) {
+				mhi = pow5mult(ptr, mhi, m5);
+				if (mhi == NULL)
+					return (NULL);
+				b1 = mult(ptr, mhi, b);
+				if (b1 == NULL)
+					return (NULL);
+				Bfree(ptr, b);
+				b = b1;
+				}
+			if ( (j = b5 - m5) !=0) {
+				b = pow5mult(ptr, b, j);
+				if (b == NULL)
+					return (NULL);
+				}
+			}
+		else {
+			b = pow5mult(ptr, b, b5);
+			if (b == NULL)
+				return (NULL);
+			}
+		}
+	S = i2b(ptr, 1);
+	if (S == NULL)
+		return (NULL);
+	if (s5 > 0) {
+		S = pow5mult(ptr, S, s5);
+		if (S == NULL)
+			return (NULL);
+		}
+
+	/* Check for special case that d is a normalized power of 2. */
+
+	spec_case = 0;
+	if (mode < 2) {
+		if (bbits == 1 && be0 > fpi->emin + 1) {
+			/* The special case */
+			b2++;
+			s2++;
+			spec_case = 1;
+			}
+		}
+
+	/* Arrange for convenient computation of quotients:
+	 * shift left if necessary so divisor has 4 leading 0 bits.
+	 *
+	 * Perhaps we should just compute leading 28 bits of S once
+	 * and for all and pass them and a shift to quorem, so it
+	 * can do shifts and ors to compute the numerator for q.
+	 */
+	i = ((s5 ? hi0bits(S->_x[S->_wds-1]) : ULbits - 1) - s2 - 4) & kmask;
+	m2 += i;
+	if ((b2 += i) > 0) {
+		b = lshift(ptr, b, b2);
+		if (b == NULL)
+			return (NULL);
+		}
+	if ((s2 += i) > 0) {
+		S = lshift(ptr, S, s2);
+		if (S == NULL)
+			return (NULL);
+		}
+	if (k_check) {
+		if (cmp(b,S) < 0) {
+			k--;
+			b = multadd(ptr, b, 10, 0); /* we botched the k estimate */
+			if (b == NULL)
+				return (NULL);
+			if (leftright) {
+				mhi = multadd(ptr, mhi, 10, 0);
+				if (mhi == NULL)
+					return (NULL);
+				}
+			ilim = ilim1;
+			}
+		}
+	if (ilim <= 0 && mode > 2) {
+		S = multadd(ptr, S,5,0);
+		if (S == NULL)
+			return (NULL);
+		if (ilim < 0 || cmp(b,S) <= 0) {
+			/* no digits, fcvt style */
+ no_digits:
+			k = -1 - ndigits;
+			inex = STRTOG_Inexlo;
+			goto ret;
+			}
+ one_digit:
+		inex = STRTOG_Inexhi;
+		*s++ = '1';
+		k++;
+		goto ret;
+		}
+	if (leftright) {
+		if (m2 > 0) {
+			mhi = lshift(ptr, mhi, m2);
+			if (mhi == NULL)
+				return (NULL);
+			}
+
+		/* Compute mlo -- check for special case
+		 * that d is a normalized power of 2.
+		 */
+
+		mlo = mhi;
+		if (spec_case) {
+			mhi = Balloc(ptr, mhi->_k);
+			if (mhi == NULL)
+				return (NULL);
+			Bcopy(mhi, mlo);
+			mhi = lshift(ptr, mhi, 1);
+			if (mhi == NULL)
+				return (NULL);
+			}
+
+		for(i = 1;;i++) {
+			dig = quorem(b,S) + '0';
+			/* Do we yet have the shortest decimal string
+			 * that will round to d?
+			 */
+			j = cmp(b, mlo);
+			delta = diff(ptr, S, mhi);
+			if (delta == NULL)
+				return (NULL);
+			j1 = delta->_sign ? 1 : cmp(b, delta);
+			Bfree(ptr, delta);
+#ifndef ROUND_BIASED
+			if (j1 == 0 && !mode && !(bits[0] & 1) && !rdir) {
+				if (dig == '9')
+					goto round_9_up;
+				if (j <= 0) {
+					if (b->_wds > 1 || b->_x[0])
+						inex = STRTOG_Inexlo;
+					}
+				else {
+					dig++;
+					inex = STRTOG_Inexhi;
+					}
+				*s++ = dig;
+				goto ret;
+				}
+#endif
+			if (j < 0 || (j == 0 && !mode
+#ifndef ROUND_BIASED
+							&& !(bits[0] & 1)
+#endif
+					)) {
+				if (rdir && (b->_wds > 1 || b->_x[0])) {
+					if (rdir == 2) {
+						inex = STRTOG_Inexlo;
+						goto accept;
+						}
+					while (cmp(S,mhi) > 0) {
+						*s++ = dig;
+						mhi1 = multadd(ptr, mhi, 10, 0);
+						if (mhi1 == NULL)
+							return (NULL);
+						if (mlo == mhi)
+							mlo = mhi1;
+						mhi = mhi1;
+						b = multadd(ptr, b, 10, 0);
+						if (b == NULL)
+							return (NULL);
+						dig = quorem(b,S) + '0';
+						}
+					if (dig++ == '9')
+						goto round_9_up;
+					inex = STRTOG_Inexhi;
+					goto accept;
+					}
+				if (j1 > 0) {
+					b = lshift(ptr, b, 1);
+					if (b == NULL)
+						return (NULL);
+					j1 = cmp(b, S);
+#ifdef ROUND_BIASED
+					if (j1 >= 0 /*)*/
+#else
+					if ((j1 > 0 || (j1 == 0 && dig & 1))
+#endif
+					&& dig++ == '9')
+						goto round_9_up;
+					inex = STRTOG_Inexhi;
+					}
+				if (b->_wds > 1 || b->_x[0])
+					inex = STRTOG_Inexlo;
+ accept:
+				*s++ = dig;
+				goto ret;
+				}
+			if (j1 > 0 && rdir != 2) {
+				if (dig == '9') { /* possible if i == 1 */
+ round_9_up:
+					*s++ = '9';
+					inex = STRTOG_Inexhi;
+					goto roundoff;
+					}
+				inex = STRTOG_Inexhi;
+				*s++ = dig + 1;
+				goto ret;
+				}
+			*s++ = dig;
+			if (i == ilim)
+				break;
+			b = multadd(ptr, b, 10, 0);
+			if (b == NULL)
+				return (NULL);
+			if (mlo == mhi) {
+				mlo = mhi = multadd(ptr, mhi, 10, 0);
+				if (mlo == NULL)
+					return (NULL);
+				}
+			else {
+				mlo = multadd(ptr, mlo, 10, 0);
+				if (mlo == NULL)
+					return (NULL);
+				mhi = multadd(ptr, mhi, 10, 0);
+				if (mhi == NULL)
+					return (NULL);
+				}
+			}
+		}
+	else
+		for(i = 1;; i++) {
+			*s++ = dig = quorem(b,S) + '0';
+			if (i >= ilim)
+				break;
+			b = multadd(ptr, b, 10, 0);
+			if (b == NULL)
+				return (NULL);
+			}
+
+	/* Round off last digit */
+
+	if (rdir) {
+		if (rdir == 2 || (b->_wds <= 1 && !b->_x[0]))
+			goto chopzeros;
+		goto roundoff;
+		}
+	b = lshift(ptr, b, 1);
+	if (b == NULL)
+		return (NULL);
+	j = cmp(b, S);
+#ifdef ROUND_BIASED
+	if (j >= 0)
+#else
+	if (j > 0 || (j == 0 && dig & 1))
+#endif
+		{
+ roundoff:
+		inex = STRTOG_Inexhi;
+		while(*--s == '9')
+			if (s == s0) {
+				k++;
+				*s++ = '1';
+				goto ret;
+				}
+		++*s++;
+		}
+	else {
+ chopzeros:
+		if (b->_wds > 1 || b->_x[0])
+			inex = STRTOG_Inexlo;
+		while(*--s == '0'){}
+		++s;
+		}
+ ret:
+	Bfree(ptr, S);
+	if (mhi) {
+		if (mlo && mlo != mhi)
+			Bfree(ptr, mlo);
+		Bfree(ptr, mhi);
+		}
+ ret1:
+	Bfree(ptr, b);
+	*s = 0;
+	*decpt = k + 1;
+	if (rve)
+		*rve = s;
+	*kindp |= inex;
+	return s0;
+	}
+DEF_STRONG(gdtoa);
+#endif /* _USE_GDTOA */
diff --git a/newlib/libc/stdlib/gdtoa-gmisc.c b/newlib/libc/stdlib/gdtoa-gmisc.c
new file mode 100644
index 000000000..40c3c2d13
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-gmisc.c
@@ -0,0 +1,91 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include <newlib.h>
+#include <sys/config.h>
+
+#ifdef _USE_GDTOA
+#include "gdtoaimp.h"
+
+ void
+#ifdef KR_headers
+rshift(b, k) Bigint *b; int k;
+#else
+rshift(Bigint *b, int k)
+#endif
+{
+	ULong *x, *x1, *xe, y;
+	int n;
+
+	x = x1 = b->_x;
+	n = k >> kshift;
+	if (n < b->_wds) {
+		xe = x + b->_wds;
+		x += n;
+		if (k &= kmask) {
+			n = ULbits - k;
+			y = *x++ >> k;
+			while(x < xe) {
+				*x1++ = (y | (*x << n)) & ALL_ON;
+				y = *x++ >> k;
+				}
+			if ((*x1 = y) !=0)
+				x1++;
+			}
+		else
+			while(x < xe)
+				*x1++ = *x++;
+		}
+	if ((b->_wds = x1 - b->_x) == 0)
+		b->_x[0] = 0;
+	}
+
+ int
+#ifdef KR_headers
+trailz(b) Bigint *b;
+#else
+trailz(Bigint *b)
+#endif
+{
+	ULong L, *x, *xe;
+	int n = 0;
+
+	x = b->_x;
+	xe = x + b->_wds;
+	for(n = 0; x < xe && !*x; x++)
+		n += ULbits;
+	if (x < xe) {
+		L = *x;
+		n += lo0bits(&L);
+		}
+	return n;
+	}
+#endif /* _USE_GDTOA */
diff --git a/newlib/libc/stdlib/gdtoa-ldtoa.c b/newlib/libc/stdlib/gdtoa-ldtoa.c
new file mode 100644
index 000000000..35bd3a32a
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-ldtoa.c
@@ -0,0 +1,130 @@
+/*	$OpenBSD: ldtoa.c,v 1.4 2016/03/09 16:28:47 deraadt Exp $	*/
+/*-
+ * Copyright (c) 2003 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <newlib.h>
+#include <sys/config.h>
+
+#ifdef _USE_GDTOA
+#include <sys/types.h>
+#include <machine/ieee.h>
+#include <float.h>
+#include <stdint.h>
+#include <limits.h>
+#include <math.h>
+#include <stdlib.h>
+#include "gdtoaimp.h"
+
+#if (LDBL_MANT_DIG > DBL_MANT_DIG)
+
+/*
+ * ldtoa() is a wrapper for gdtoa() that makes it smell like dtoa(),
+ * except that the floating point argument is passed by reference.
+ * When dtoa() is passed a NaN or infinity, it sets expt to 9999.
+ * However, a long double could have a valid exponent of 9999, so we
+ * use INT_MAX in ldtoa() instead.
+ */
+char *
+__ldtoa(struct _reent *ptr,
+    long double *ld, int mode, int ndigits, int *decpt, int *sign, char **rve)
+{
+	FPI fpi = {
+		LDBL_MANT_DIG,			/* nbits */
+		LDBL_MIN_EXP - LDBL_MANT_DIG,	/* emin */
+		LDBL_MAX_EXP - LDBL_MANT_DIG,	/* emax */
+		FLT_ROUNDS,	       		/* rounding */
+#ifdef Sudden_Underflow	/* unused, but correct anyway */
+		1
+#else
+		0
+#endif
+	};
+	int be, kind;
+	char *ret;
+	struct ieee_ext *p = (struct ieee_ext *)ld;
+	uint32_t bits[(LDBL_MANT_DIG + 31) / 32];
+	void *vbits = bits;
+
+	/*
+	 * gdtoa doesn't know anything about the sign of the number, so
+	 * if the number is negative, we need to swap rounding modes of
+	 * 2 (upwards) and 3 (downwards).
+	 */
+	*sign = p->ext_sign;
+	fpi.rounding ^= (fpi.rounding >> 1) & p->ext_sign;
+
+	be = p->ext_exp - (LDBL_MAX_EXP - 1) - (LDBL_MANT_DIG - 1);
+	EXT_TO_ARRAY32(p, bits);
+
+	switch (fpclassify(*ld)) {
+	case FP_NORMAL:
+		kind = STRTOG_Normal;
+#ifdef EXT_IMPLICIT_NBIT
+		bits[LDBL_MANT_DIG / 32] |= 1 << ((LDBL_MANT_DIG - 1) % 32);
+#endif /* EXT_IMPLICIT_NBIT */
+		break;
+	case FP_ZERO:
+		kind = STRTOG_Zero;
+		break;
+	case FP_SUBNORMAL:
+		kind = STRTOG_Denormal;
+		be++;
+		break;
+	case FP_INFINITE:
+		kind = STRTOG_Infinite;
+		break;
+	case FP_NAN:
+		kind = STRTOG_NaN;
+		break;
+	default:
+		abort();
+	}
+
+	ret = gdtoa(ptr, &fpi, be, vbits, &kind, mode, ndigits, decpt, rve);
+	if (*decpt == -32768)
+		*decpt = INT_MAX;
+	return ret;
+}
+DEF_STRONG(__ldtoa);
+
+#else   /* (LDBL_MANT_DIG == DBL_MANT_DIG) */
+
+char *
+__ldtoa(struct _reent *ptr,
+    long double *ld, int mode, int ndigits, int *decpt, int *sign,
+    char **rve)
+{
+	char *ret;
+
+	ret = dtoa(ptr, (double)*ld, mode, ndigits, decpt, sign, rve);
+	if (*decpt == 9999)
+		*decpt = INT_MAX;
+	return ret;
+}
+DEF_STRONG(__ldtoa);
+
+#endif  /* (LDBL_MANT_DIG == DBL_MANT_DIG) */
+#endif /* _USE_GDTOA */
diff --git a/newlib/libc/stdlib/gdtoa.h b/newlib/libc/stdlib/gdtoa.h
index 07506aac1..f4d2a56db 100644
--- a/newlib/libc/stdlib/gdtoa.h
+++ b/newlib/libc/stdlib/gdtoa.h
@@ -32,25 +32,55 @@ THIS SOFTWARE.
 #ifndef GDTOA_H_INCLUDED
 #define GDTOA_H_INCLUDED
 
+#include <stddef.h> /* for size_t */
+#include <reent.h>
+
+#define PROTO_NORMAL(x)
+#define __BEGIN_HIDDEN_DECLS
+#define __END_HIDDEN_DECLS
+#define DEF_STRONG(x)
+
+#ifndef ULong
+#define ULong __ULong
+#endif
+
+#ifndef ANSI
+#ifdef KR_headers
+#define ANSI(x) ()
+#define Void /*nothing*/
+#else
+#define ANSI(x) x
+#define Void void
+#endif
+#endif /* ANSI */
+
+#ifndef CONST
+#ifdef KR_headers
+#define CONST /* blank */
+#else
+#define CONST const
+#endif
+#endif /* CONST */
 
  enum {	/* return values from strtodg */
-	STRTOG_Zero	= 0,
-	STRTOG_Normal	= 1,
-	STRTOG_Denormal	= 2,
-	STRTOG_Infinite	= 3,
-	STRTOG_NaN	= 4,
-	STRTOG_NaNbits	= 5,
-	STRTOG_NoNumber	= 6,
-	STRTOG_Retmask	= 7,
+	STRTOG_Zero	= 0x000,
+	STRTOG_Normal	= 0x001,
+	STRTOG_Denormal	= 0x002,
+	STRTOG_Infinite	= 0x003,
+	STRTOG_NaN	= 0x004,
+	STRTOG_NaNbits	= 0x005,
+	STRTOG_NoNumber	= 0x006,
+	STRTOG_NoMemory = 0x007,
+	STRTOG_Retmask	= 0x00f,
 
 	/* The following may be or-ed into one of the above values. */
 
-	STRTOG_Neg	= 0x08,
-	STRTOG_Inexlo	= 0x10,
-	STRTOG_Inexhi	= 0x20,
-	STRTOG_Inexact	= 0x30,
-	STRTOG_Underflow= 0x40,
-	STRTOG_Overflow	= 0x80
+	STRTOG_Inexlo	= 0x010, /* returned result rounded toward zero */
+	STRTOG_Inexhi	= 0x020, /* returned result rounded away from zero */
+	STRTOG_Inexact	= 0x030,
+	STRTOG_Underflow= 0x040,
+	STRTOG_Overflow	= 0x080,
+	STRTOG_Neg	= 0x100 /* does not affect STRTOG_Inexlo or STRTOG_Inexhi */
 	};
 
  typedef struct
@@ -69,6 +99,74 @@ enum {	/* FPI.rounding values: same as FLT_ROUNDS */
 	FPI_Round_down = 3
 	};
 
-#endif /* GDTOA_H_INCLUDED */
-
 typedef unsigned short __UShort;
+typedef struct _Bigint Bigint;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char* __dtoa  ANSI((struct _reent *ptr,
+			double d, int mode, int ndigits, int *decpt,
+			int *sign, char **rve));
+extern char* __gdtoa ANSI((struct _reent *ptr,
+			FPI *fpi, int be, ULong *bits, int *kindp,
+			int mode, int ndigits, int *decpt, char **rve));
+extern void __freedtoa ANSI((struct _reent *, char*));
+extern float  strtof ANSI((CONST char *, char **));
+extern double strtod ANSI((CONST char *, char **));
+extern int __strtodg ANSI((CONST char*, char**, FPI*, Long*, ULong*));
+char	*__hdtoa(double, const char *, int, int *, int *, char **);
+char	*__hldtoa(long double, const char *, int, int *, int *, char **);
+char	*__ldtoa(struct _reent *ptr,
+		 long double *, int, int, int *, int *, char **);
+
+PROTO_NORMAL(__dtoa);
+PROTO_NORMAL(__gdtoa);
+PROTO_NORMAL(__freedtoa);
+PROTO_NORMAL(__hdtoa);
+PROTO_NORMAL(__hldtoa);
+PROTO_NORMAL(__ldtoa);
+
+__BEGIN_HIDDEN_DECLS
+extern char*	__g_ddfmt  ANSI((char*, double*, int, size_t));
+extern char*	__g_dfmt   ANSI((char*, double*, int, size_t));
+extern char*	__g_ffmt   ANSI((char*, float*,  int, size_t));
+extern char*	__g_Qfmt   ANSI((char*, void*,   int, size_t));
+extern char*	__g_xfmt   ANSI((char*, void*,   int, size_t));
+extern char*	__g_xLfmt  ANSI((char*, void*,   int, size_t));
+
+extern int	__strtoId  ANSI((CONST char*, char**, double*, double*));
+extern int	__strtoIdd ANSI((CONST char*, char**, double*, double*));
+extern int	__strtoIf  ANSI((CONST char*, char**, float*, float*));
+extern int	__strtoIQ  ANSI((CONST char*, char**, void*, void*));
+extern int	__strtoIx  ANSI((CONST char*, char**, void*, void*));
+extern int	__strtoIxL ANSI((CONST char*, char**, void*, void*));
+extern int	__strtord  ANSI((CONST char*, char**, int, double*));
+extern int	__strtordd ANSI((CONST char*, char**, int, double*));
+extern int	__strtorf  ANSI((CONST char*, char**, int, float*));
+extern int	__strtorQ  ANSI((CONST char*, char**, int, void*));
+extern int	__strtorx  ANSI((CONST char*, char**, int, void*));
+extern int	__strtorxL ANSI((CONST char*, char**, int, void*));
+#if 1
+extern int	__strtodI  ANSI((CONST char*, char**, double*));
+extern int	__strtopd  ANSI((CONST char*, char**, double*));
+extern int	__strtopdd ANSI((CONST char*, char**, double*));
+extern int	__strtopf  ANSI((CONST char*, char**, float*));
+extern int	__strtopQ  ANSI((CONST char*, char**, void*));
+extern int	__strtopx  ANSI((CONST char*, char**, void*));
+extern int	__strtopxL ANSI((CONST char*, char**, void*));
+#else
+#define __strtopd(s,se,x) strtord(s,se,1,x)
+#define __strtopdd(s,se,x) strtordd(s,se,1,x)
+#define __strtopf(s,se,x) strtorf(s,se,1,x)
+#define __strtopQ(s,se,x) strtorQ(s,se,1,x)
+#define __strtopx(s,se,x) strtorx(s,se,1,x)
+#define __strtopxL(s,se,x) strtorxL(s,se,1,x)
+#endif
+__END_HIDDEN_DECLS
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* GDTOA_H_INCLUDED */
diff --git a/newlib/libc/stdlib/gdtoaimp.h b/newlib/libc/stdlib/gdtoaimp.h
new file mode 100644
index 000000000..f2da3fc67
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoaimp.h
@@ -0,0 +1,206 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998-2000 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* This is a variation on dtoa.c that converts arbitary binary
+   floating-point formats to and from decimal notation.  It uses
+   double-precision arithmetic internally, so there are still
+   various #ifdefs that adapt the calculations to the native
+   double-precision arithmetic (any of IEEE, VAX D_floating,
+   or IBM mainframe arithmetic).
+
+   Please send bug reports to David M. Gay (dmg at acm dot org,
+   with " at " changed at "@" and " dot " changed to ".").
+ */
+
+/* On a machine with IEEE extended-precision registers, it is
+ * necessary to specify double-precision (53-bit) rounding precision
+ * before invoking strtod or dtoa.  If the machine uses (the equivalent
+ * of) Intel 80x87 arithmetic, the call
+ *	_control87(PC_53, MCW_PC);
+ * does this with many compilers.  Whether this or another call is
+ * appropriate depends on the compiler; for this to work, it may be
+ * necessary to #include "float.h" or another system-dependent header
+ * file.
+ */
+
+/* strtod for IEEE-, VAX-, and IBM-arithmetic machines.
+ *
+ * This strtod returns a nearest machine number to the input decimal
+ * string (or sets errno to ERANGE).  With IEEE arithmetic, ties are
+ * broken by the IEEE round-even rule.  Otherwise ties are broken by
+ * biased rounding (add half and chop).
+ *
+ * Inspired loosely by William D. Clinger's paper "How to Read Floating
+ * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ *
+ *	1. We only require IEEE, IBM, or VAX double-precision
+ *		arithmetic (not IEEE double-extended).
+ *	2. We get by with floating-point arithmetic in a case that
+ *		Clinger missed -- when we're computing d * 10^n
+ *		for a small integer d and the integer n is not too
+ *		much larger than 22 (the maximum integer k for which
+ *		we can represent 10^k exactly), we may be able to
+ *		compute (d*10^k) * 10^(e-k) with just one roundoff.
+ *	3. Rather than a bit-at-a-time adjustment of the binary
+ *		result in the hard case, we use floating-point
+ *		arithmetic to determine the adjustment to within
+ *		one bit; only in really hard cases do we need to
+ *		compute a second residual.
+ *	4. Because of 3., we don't need a large table of powers of 10
+ *		for ten-to-e (just some small tables, e.g. of 10^k
+ *		for 0 <= k <= 22).
+ */
+
+/*
+ * #define IEEE_8087 for IEEE-arithmetic machines where the least
+ *	significant byte has the lowest address.
+ * #define IEEE_MC68k for IEEE-arithmetic machines where the most
+ *	significant byte has the lowest address.
+ * #define Long int on machines with 32-bit ints and 64-bit longs.
+ * #define Sudden_Underflow for IEEE-format machines without gradual
+ *	underflow (i.e., that flush to zero on underflow).
+ * #define IBM for IBM mainframe-style floating-point arithmetic.
+ * #define VAX for VAX-style floating-point arithmetic (D_floating).
+ * #define No_leftright to omit left-right logic in fast floating-point
+ *	computation of dtoa and gdtoa.  This will cause modes 4 and 5 to be
+ *	treated the same as modes 2 and 3 for some inputs.
+ * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3.
+ * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines
+ *	that use extended-precision instructions to compute rounded
+ *	products and quotients) with IBM.
+ * #define ROUND_BIASED for IEEE-format with biased rounding and arithmetic
+ *	that rounds toward +Infinity.
+ * #define ROUND_BIASED_without_Round_Up for IEEE-format with biased
+ *	rounding when the underlying floating-point arithmetic uses
+ *	unbiased rounding.  This prevent using ordinary floating-point
+ *	arithmetic when the result could be computed with one rounding error.
+ * #define Inaccurate_Divide for IEEE-format with correctly rounded
+ *	products but inaccurate quotients, e.g., for Intel i860.
+ * #define NO_LONG_LONG on machines that do not have a "long long"
+ *	integer type (of >= 64 bits).  On such machines, you can
+ *	#define Just_16 to store 16 bits per 32-bit Long when doing
+ *	high-precision integer arithmetic.  Whether this speeds things
+ *	up or slows things down depends on the machine and the number
+ *	being converted.  If long long is available and the name is
+ *	something other than "long long", #define Llong to be the name,
+ *	and if "unsigned Llong" does not work as an unsigned version of
+ *	Llong, #define #ULLong to be the corresponding unsigned type.
+ * #define KR_headers for old-style C function headers.
+ * #define Bad_float_h if your system lacks a float.h or if it does not
+ *	define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP,
+ *	FLT_RADIX, FLT_ROUNDS, and DBL_MAX.
+ * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n)
+ *	if memory is available and otherwise does something you deem
+ *	appropriate.  If MALLOC is undefined, malloc will be invoked
+ *	directly -- and assumed always to succeed.  Similarly, if you
+ *	want something other than the system's free() to be called to
+ *	recycle memory acquired from MALLOC, #define FREE to be the
+ *	name of the alternate routine.  (FREE or free is only called in
+ *	pathological cases, e.g., in a gdtoa call after a gdtoa return in
+ *	mode 3 with thousands of digits requested.)
+ * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making
+ *	memory allocations from a private pool of memory when possible.
+ *	When used, the private pool is PRIVATE_MEM bytes long:  2304 bytes,
+ *	unless #defined to be a different length.  This default length
+ *	suffices to get rid of MALLOC calls except for unusual cases,
+ *	such as decimal-to-binary conversion of a very long string of
+ *	digits.  When converting IEEE double precision values, the
+ *	longest string gdtoa can return is about 751 bytes long.  For
+ *	conversions by strtod of strings of 800 digits and all gdtoa
+ *	conversions of IEEE doubles in single-threaded executions with
+ *	8-byte pointers, PRIVATE_MEM >= 7400 appears to suffice; with
+ *	4-byte pointers, PRIVATE_MEM >= 7112 appears adequate.
+ * #define NO_INFNAN_CHECK if you do not wish to have INFNAN_CHECK
+ *	#defined automatically on IEEE systems.  On such systems,
+ *	when INFNAN_CHECK is #defined, strtod checks
+ *	for Infinity and NaN (case insensitively).
+ *	When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined,
+ *	strtodg also accepts (case insensitively) strings of the form
+ *	NaN(x), where x is a string of hexadecimal digits (optionally
+ *	preceded by 0x or 0X) and spaces; if there is only one string
+ *	of hexadecimal digits, it is taken for the fraction bits of the
+ *	resulting NaN; if there are two or more strings of hexadecimal
+ *	digits, each string is assigned to the next available sequence
+ *	of 32-bit words of fractions bits (starting with the most
+ *	significant), right-aligned in each sequence.
+ *	Unless GDTOA_NON_PEDANTIC_NANCHECK is #defined, input "NaN(...)"
+ *	is consumed even when ... has the wrong form (in which case the
+ *	"(...)" is consumed but ignored).
+ * #define MULTIPLE_THREADS if the system offers preemptively scheduled
+ *	multiple threads.  In this case, you must provide (or suitably
+ *	#define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed
+ *	by FREE_DTOA_LOCK(n) for n = 0 or 1.  (The second lock, accessed
+ *	in pow5mult, ensures lazy evaluation of only one copy of high
+ *	powers of 5; omitting this lock would introduce a small
+ *	probability of wasting memory, but would otherwise be harmless.)
+ *	You must also invoke freedtoa(s) to free the value s returned by
+ *	dtoa.  You may do so whether or not MULTIPLE_THREADS is #defined.
+ * #define IMPRECISE_INEXACT if you do not care about the setting of
+ *	the STRTOG_Inexact bits in the special case of doing IEEE double
+ *	precision conversions (which could also be done by the strtod in
+ *	dtoa.c).
+ * #define NO_HEX_FP to disable recognition of C9x's hexadecimal
+ *	floating-point constants.
+ * #define -DNO_ERRNO to suppress setting errno (in strtod.c and
+ *	strtodg.c).
+ * #define NO_STRING_H to use private versions of memcpy.
+ *	On some K&R systems, it may also be necessary to
+ *	#define DECLARE_SIZE_T in this case.
+ * #define USE_LOCALE to use the current locale's decimal_point value.
+ */
+
+#ifndef GDTOAIMP_H_INCLUDED
+#define GDTOAIMP_H_INCLUDED
+#include "mprec.h"
+#include "gdtoa.h"
+
+#ifndef __SINGLE_THREAD__
+#define MULTIPLE_THREADS
+#endif
+
+#define dtoa __dtoa
+#define gdtoa __gdtoa
+#define freedtoa __freedtoa
+
+#define dtoa_result __dtoa_result_D2A
+#define nrv_alloc __nrv_alloc_D2A
+#define quorem __quorem_D2A
+#define rshift __rshift_D2A
+#define rv_alloc __rv_alloc_D2A
+#define trailz __trailz_D2A
+
+extern char *dtoa_result;
+extern char *nrv_alloc ANSI((struct _reent *, char*, char **, int));
+extern int quorem ANSI((Bigint*, Bigint*));
+extern void rshift ANSI((Bigint*, int));
+extern char *rv_alloc ANSI((struct _reent *, int));
+extern int trailz ANSI((Bigint*));
+
+#endif /* GDTOAIMP_H_INCLUDED */
diff --git a/newlib/libc/stdlib/ldtoa.c b/newlib/libc/stdlib/ldtoa.c
index 26c61948b..28e2b5023 100644
--- a/newlib/libc/stdlib/ldtoa.c
+++ b/newlib/libc/stdlib/ldtoa.c
@@ -2,11 +2,15 @@
   * This program has been placed in the public domain.
   */
 
+#include <newlib.h>
+#include <sys/config.h>
+
 #include <_ansi.h>
 #include <reent.h>
 #include <string.h>
 #include <stdlib.h>
 #include "mprec.h"
+#include "gdtoa.h"
 
 /* These are the externally visible entries. */
 /* linux name:  long double _IO_strtold (char *, char **); */
@@ -2787,6 +2791,20 @@ char *
 _ldtoa_r (struct _reent *ptr, long double d, int mode, int ndigits,
 	  int *decpt, int *sign, char **rve)
 {
+#ifdef _USE_GDTOA
+  _REENT_CHECK_MP (ptr);
+
+/* reentrancy addition to use mprec storage pool */
+  if (_REENT_MP_RESULT (ptr))
+    {
+      _REENT_MP_RESULT (ptr)->_k = _REENT_MP_RESULT_K (ptr);
+      _REENT_MP_RESULT (ptr)->_maxwds = 1 << _REENT_MP_RESULT_K (ptr);
+      Bfree (ptr, _REENT_MP_RESULT (ptr));
+      _REENT_MP_RESULT (ptr) = 0;
+    }
+
+  return __ldtoa (ptr, &d, mode, ndigits, decpt, sign, rve);
+#else /* _USE_GDTOA */
   unsigned short e[NI];
   char *s, *p;
   int i, j, k;
@@ -2960,6 +2978,7 @@ stripspaces:
     _free_r (ptr, outbuf);
 
   return outstr;
+#endif /* _USE_GDTOA */
 }
 
 /* Routine used to tell if long double is NaN or Infinity or regular number. 
diff --git a/newlib/libc/stdlib/mprec.h b/newlib/libc/stdlib/mprec.h
index a1492aa38..83de932c2 100644
--- a/newlib/libc/stdlib/mprec.h
+++ b/newlib/libc/stdlib/mprec.h
@@ -26,7 +26,7 @@
 	dmg@research.att.com or research!dmg
  */
 
-#include <ieeefp.h>
+#include <machine/ieeefp.h>
 #include <math.h>
 #include <float.h>
 #include <errno.h>
diff --git a/newlib/newlib.hin b/newlib/newlib.hin
index 416d0c629..a0999512c 100644
--- a/newlib/newlib.hin
+++ b/newlib/newlib.hin
@@ -96,6 +96,9 @@
 /* Define to use type long for time_t.  */
 #undef _WANT_USE_LONG_TIME_T
 
+/* Define if using gdtoa rather than legacy ldtoa.  */
+#undef _WANT_USE_GDTOA
+
 /*
  * Iconv encodings enabled ("to" direction)
  */
-- 
2.33.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed value is incorrectly rounded
  2021-11-30 10:51                 ` Takashi Yano
@ 2021-11-30 15:09                   ` Corinna Vinschen
  2021-11-30 20:38                     ` Takashi Yano
  2021-12-01 12:05                     ` Takashi Yano
  0 siblings, 2 replies; 25+ messages in thread
From: Corinna Vinschen @ 2021-11-30 15:09 UTC (permalink / raw)
  To: newlib

On Nov 30 19:51, Takashi Yano wrote:
> On Mon, 29 Nov 2021 16:55:32 +0100
> Corinna Vinschen wrote:
> > On Nov 29 23:24, Takashi Yano wrote:
> > > [...]
> > > > > > > I have tried to import gdtoa into newlib from OpenBSD.
> > > > > > > [...]
> > [...struct __reent stuff...]
> Thanks for checking and advice. I have done these.
> 
> > As for the allocations, how big are those?  If they are comparable with
> > the allocation we now perform in _ldtoa_r, it might not be worth to keep
> > both functions.  Some users of smaller targets might also complain that
> 
> I saw max 16404 byte malloc().
> 
> > using printf now always pulls in both variants of ldtoa, thus raising
> > code size unnecessarily.  It might be better to keep the calls separate
> > and only use one or the other, per target or per code size constraints,
> > perhaps as a configure option.
> 
> I have added --enable-newlib-use-gdtoa option, which defaults
> to 'yes', into newlib/configure.ac. Is this the right thing?

That patch looks good to me, at least as far as Cygwin is concerned.

This isn't essential, but it might make sense to rename __ldtoa to
_ldtoa_r to avoid an extra function call, which could be time consuming
and add stack pressure.  I. e., in gdtoa-ldtoa.c

  #ifdef _USE_GDTOA
  // all code in gdtoa-ldtoa.c
  #endif

and in ldtoa.c:

  #ifndef _USE_GDTOA
  // all code in ldtoa.c
  #endif

AFAICS, __ldtoa could easily be changed to take the long double argument
by value because it's used in only two places, one of which just checks
the value anyway.  But, as I said, not essential.  We can keep in mind
for the time being.


Could some people with other targets than Cygwin give this patch a try?
RTEMS, anybody?


Thanks,
Corinna


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed value is incorrectly rounded
  2021-11-30 15:09                   ` Corinna Vinschen
@ 2021-11-30 20:38                     ` Takashi Yano
  2021-11-30 21:17                       ` Takashi Yano
  2021-12-01 12:05                     ` Takashi Yano
  1 sibling, 1 reply; 25+ messages in thread
From: Takashi Yano @ 2021-11-30 20:38 UTC (permalink / raw)
  To: newlib

[-- Attachment #1: Type: text/plain, Size: 1957 bytes --]

On Tue, 30 Nov 2021 16:09:26 +0100
Corinna Vinschen wrote:
> On Nov 30 19:51, Takashi Yano wrote:
> > On Mon, 29 Nov 2021 16:55:32 +0100
> > Corinna Vinschen wrote:
> > > On Nov 29 23:24, Takashi Yano wrote:
> > > > [...]
> > > > > > > > I have tried to import gdtoa into newlib from OpenBSD.
> > > > > > > > [...]
> > > [...struct __reent stuff...]
> > Thanks for checking and advice. I have done these.
> > 
> > > As for the allocations, how big are those?  If they are comparable with
> > > the allocation we now perform in _ldtoa_r, it might not be worth to keep
> > > both functions.  Some users of smaller targets might also complain that
> > 
> > I saw max 16404 byte malloc().
> > 
> > > using printf now always pulls in both variants of ldtoa, thus raising
> > > code size unnecessarily.  It might be better to keep the calls separate
> > > and only use one or the other, per target or per code size constraints,
> > > perhaps as a configure option.
> > 
> > I have added --enable-newlib-use-gdtoa option, which defaults
> > to 'yes', into newlib/configure.ac. Is this the right thing?
> 
> That patch looks good to me, at least as far as Cygwin is concerned.

Thanks for reviewing.

> This isn't essential, but it might make sense to rename __ldtoa to
> _ldtoa_r to avoid an extra function call, which could be time consuming
> and add stack pressure.  I. e., in gdtoa-ldtoa.c
> 
>   #ifdef _USE_GDTOA
>   // all code in gdtoa-ldtoa.c
>   #endif
> 
> and in ldtoa.c:
> 
>   #ifndef _USE_GDTOA
>   // all code in ldtoa.c
>   #endif
> 
> AFAICS, __ldtoa could easily be changed to take the long double argument
> by value because it's used in only two places, one of which just checks
> the value anyway.  But, as I said, not essential.  We can keep in mind
> for the time being.

Done.

> Could some people with other targets than Cygwin give this patch a try?
> RTEMS, anybody?

I would appreciate it.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: v3-0001-ldtoa-Import-gdtoa-from-OpenBSD.patch --]
[-- Type: application/octet-stream, Size: 124634 bytes --]

From 5dcfbea69c7ce9154d1e726583ab5a8e67f30d95 Mon Sep 17 00:00:00 2001
From: Takashi Yano <takashi.yano@nifty.ne.jp>
Date: Wed, 1 Dec 2021 05:24:28 +0900
Subject: [PATCH v3] ldtoa: Import gdtoa from OpenBSD.

- This patch uses gdtoa imported from OpenBSD if newlib configure
  option "--enable-newlib-use-gdtoa=no" is NOT specified.  gdtoa
  provides more accurate output and faster conversion than legacy
  ldtoa, while it requires more heap memory.
---
 newlib/README                      |  10 +
 newlib/configure                   | 317 ++++++-----
 newlib/configure.ac                |  15 +
 newlib/libc/include/machine/ieee.h | 127 +++++
 newlib/libc/include/sys/config.h   |   6 +
 newlib/libc/stdlib/Makefile.am     |  12 +-
 newlib/libc/stdlib/Makefile.in     | 109 ++--
 newlib/libc/stdlib/gdtoa-dmisc.c   | 230 ++++++++
 newlib/libc/stdlib/gdtoa-dtoa.c    | 846 +++++++++++++++++++++++++++++
 newlib/libc/stdlib/gdtoa-gdtoa.c   | 837 ++++++++++++++++++++++++++++
 newlib/libc/stdlib/gdtoa-gmisc.c   |  91 ++++
 newlib/libc/stdlib/gdtoa-ldtoa.c   | 159 ++++++
 newlib/libc/stdlib/gdtoa.h         | 130 ++++-
 newlib/libc/stdlib/gdtoaimp.h      | 206 +++++++
 newlib/libc/stdlib/ldtoa.c         |   6 +
 newlib/libc/stdlib/mprec.h         |   2 +-
 newlib/newlib.hin                  |   3 +
 17 files changed, 2915 insertions(+), 191 deletions(-)
 create mode 100644 newlib/libc/include/machine/ieee.h
 create mode 100644 newlib/libc/stdlib/gdtoa-dmisc.c
 create mode 100644 newlib/libc/stdlib/gdtoa-dtoa.c
 create mode 100644 newlib/libc/stdlib/gdtoa-gdtoa.c
 create mode 100644 newlib/libc/stdlib/gdtoa-gmisc.c
 create mode 100644 newlib/libc/stdlib/gdtoa-ldtoa.c
 create mode 100644 newlib/libc/stdlib/gdtoaimp.h

diff --git a/newlib/README b/newlib/README
index 064c5784c..c82bf8b8c 100644
--- a/newlib/README
+++ b/newlib/README
@@ -352,6 +352,16 @@ One feature can be enabled by specifying `--enable-FEATURE=yes' or
      64-bit integer on most systems.
      Disabled by default.
 
+`--enable-newlib-use-gdtoa'
+     Use gdtoa rather than legacy ldtoa.  gdtoa privides more accurate
+     output and faster conversion than legacy ldtoa, while it requires
+     more heap memory.  gdtoa sometimes requires 16KB heap memory, so
+     if the platform does not have enough heap memory, consider disabling
+     this option. Legacy ldtoa also use heap, however, only 1KB memory
+     is malloc'ed.  In addition, if malloc fails, it still works, with
+     less conversion accuracy.
+     Enabled by default.
+
 `--enable-multilib'
      Build many library versions.
      Enabled by default.
diff --git a/newlib/configure b/newlib/configure
index ce2fb55d2..7ab6e3423 100755
--- a/newlib/configure
+++ b/newlib/configure
@@ -1,11 +1,9 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.68 for newlib 4.1.0.
+# Generated by GNU Autoconf 2.69 for newlib 4.1.0.
 #
 #
-# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
-# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
-# Foundation, Inc.
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
 #
 #
 # This configure script is free software; the Free Software Foundation
@@ -134,6 +132,31 @@ export LANGUAGE
 # CDPATH.
 (unset CDPATH) >/dev/null 2>&1 && unset CDPATH
 
+# Use a proper internal environment variable to ensure we don't fall
+  # into an infinite loop, continuously re-executing ourselves.
+  if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+    _as_can_reexec=no; export _as_can_reexec;
+    # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+  fi
+  # We don't want this to propagate to other subprocesses.
+          { _as_can_reexec=; unset _as_can_reexec;}
 if test "x$CONFIG_SHELL" = x; then
   as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
   emulate sh
@@ -167,7 +190,8 @@ if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
 else
   exitcode=1; echo positional parameters were not saved.
 fi
-test x\$exitcode = x0 || exit 1"
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
   as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
   as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
   eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
@@ -220,21 +244,25 @@ IFS=$as_save_IFS
 
 
       if test "x$CONFIG_SHELL" != x; then :
-  # We cannot yet assume a decent shell, so we have to provide a
-	# neutralization value for shells without unset; and this also
-	# works around shells that cannot unset nonexistent variables.
-	# Preserve -v and -x to the replacement shell.
-	BASH_ENV=/dev/null
-	ENV=/dev/null
-	(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
-	export CONFIG_SHELL
-	case $- in # ((((
-	  *v*x* | *x*v* ) as_opts=-vx ;;
-	  *v* ) as_opts=-v ;;
-	  *x* ) as_opts=-x ;;
-	  * ) as_opts= ;;
-	esac
-	exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"}
+  export CONFIG_SHELL
+             # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
 fi
 
     if test x$as_have_required = xno; then :
@@ -336,6 +364,14 @@ $as_echo X"$as_dir" |
 
 
 } # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
 # as_fn_append VAR VALUE
 # ----------------------
 # Append the text in VALUE to the end of the definition contained in VAR. Take
@@ -457,6 +493,10 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits
   chmod +x "$as_me.lineno" ||
     { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
 
+  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+  # already done that, so ensure we don't try to do so again and fall
+  # in an infinite loop.  This has already happened in practice.
+  _as_can_reexec=no; export _as_can_reexec
   # Don't try to exec as it changes $[0], causing all sort of problems
   # (the dirname of $[0] is not the place where we might find the
   # original and so on.  Autoconf is especially sensitive to this).
@@ -491,16 +531,16 @@ if (echo >conf$$.file) 2>/dev/null; then
     # ... but there are two gotchas:
     # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
     # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
-    # In both cases, we have to default to `cp -p'.
+    # In both cases, we have to default to `cp -pR'.
     ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
-      as_ln_s='cp -p'
+      as_ln_s='cp -pR'
   elif ln conf$$.file conf$$ 2>/dev/null; then
     as_ln_s=ln
   else
-    as_ln_s='cp -p'
+    as_ln_s='cp -pR'
   fi
 else
-  as_ln_s='cp -p'
+  as_ln_s='cp -pR'
 fi
 rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
 rmdir conf$$.dir 2>/dev/null
@@ -512,28 +552,8 @@ else
   as_mkdir_p=false
 fi
 
-if test -x / >/dev/null 2>&1; then
-  as_test_x='test -x'
-else
-  if ls -dL / >/dev/null 2>&1; then
-    as_ls_L_option=L
-  else
-    as_ls_L_option=
-  fi
-  as_test_x='
-    eval sh -c '\''
-      if test -d "$1"; then
-	test -d "$1/.";
-      else
-	case $1 in #(
-	-*)set "./$1";;
-	esac;
-	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
-	???[sx]*):;;*)false;;esac;fi
-    '\'' sh
-  '
-fi
-as_executable_p=$as_test_x
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
 
 # Sed expression to map a string onto a valid CPP name.
 as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
@@ -762,6 +782,7 @@ infodir
 docdir
 oldincludedir
 includedir
+runstatedir
 localstatedir
 sharedstatedir
 sysconfdir
@@ -808,6 +829,7 @@ enable_lite_exit
 enable_newlib_nano_formatted_io
 enable_newlib_retargetable_locking
 enable_newlib_long_time_t
+enable_newlib_use_gdtoa
 enable_multilib
 enable_target_optspace
 enable_malloc_debugging
@@ -877,6 +899,7 @@ datadir='${datarootdir}'
 sysconfdir='${prefix}/etc'
 sharedstatedir='${prefix}/com'
 localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
 includedir='${prefix}/include'
 oldincludedir='/usr/include'
 docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@@ -1129,6 +1152,15 @@ do
   | -silent | --silent | --silen | --sile | --sil)
     silent=yes ;;
 
+  -runstatedir | --runstatedir | --runstatedi | --runstated \
+  | --runstate | --runstat | --runsta | --runst | --runs \
+  | --run | --ru | --r)
+    ac_prev=runstatedir ;;
+  -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+  | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+  | --run=* | --ru=* | --r=*)
+    runstatedir=$ac_optarg ;;
+
   -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
     ac_prev=sbindir ;;
   -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1266,7 +1298,7 @@ fi
 for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
 		datadir sysconfdir sharedstatedir localstatedir includedir \
 		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
-		libdir localedir mandir
+		libdir localedir mandir runstatedir
 do
   eval ac_val=\$$ac_var
   # Remove trailing slashes.
@@ -1294,8 +1326,6 @@ target=$target_alias
 if test "x$host_alias" != x; then
   if test "x$build_alias" = x; then
     cross_compiling=maybe
-    $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.
-    If a cross compiler is detected then cross compile mode will be used" >&2
   elif test "x$build_alias" != "x$host_alias"; then
     cross_compiling=yes
   fi
@@ -1421,6 +1451,7 @@ Fine tuning of the installation directories:
   --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
   --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
   --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --runstatedir=DIR       modifiable per-process data [LOCALSTATEDIR/run]
   --libdir=DIR            object code libraries [EPREFIX/lib]
   --includedir=DIR        C header files [PREFIX/include]
   --oldincludedir=DIR     C header files for non-gcc [/usr/include]
@@ -1483,6 +1514,7 @@ Optional Features:
   --enable-newlib-nano-formatted-io    Use nano version formatted IO
   --enable-newlib-retargetable-locking    Allow locking routines to be retargeted at link time
   --enable-newlib-long-time_t   define time_t to long
+  --enable-newlib-use-gdtoa   Use gdtoa rather than legacy ldtoa
   --enable-multilib         build many library versions (default)
   --enable-target-optspace  optimize for space
   --enable-malloc-debugging indicate malloc debugging requested
@@ -1588,9 +1620,9 @@ test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
 newlib configure 4.1.0
-generated by GNU Autoconf 2.68
+generated by GNU Autoconf 2.69
 
-Copyright (C) 2010 Free Software Foundation, Inc.
+Copyright (C) 2012 Free Software Foundation, Inc.
 This configure script is free software; the Free Software Foundation
 gives unlimited permission to copy, distribute and modify it.
 _ACEOF
@@ -1666,7 +1698,7 @@ $as_echo "$ac_try_echo"; } >&5
 	 test ! -s conftest.err
        } && test -s conftest$ac_exeext && {
 	 test "$cross_compiling" = yes ||
-	 $as_test_x conftest$ac_exeext
+	 test -x conftest$ac_exeext
        }; then :
   ac_retval=0
 else
@@ -1866,7 +1898,7 @@ This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
 It was created by newlib $as_me 4.1.0, which was
-generated by GNU Autoconf 2.68.  Invocation command line was
+generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
 
@@ -2532,6 +2564,19 @@ else
   newlib_long_time_t=no
 fi
 
+# Check whether --enable-newlib-use-gdtoa was given.
+if test "${enable_newlib_use_gdtoa+set}" = set; then :
+  enableval=$enable_newlib_use_gdtoa; if test "${newlib_use_gdtoa+set}" != set; then
+  case "${enableval}" in
+    yes) newlib_use_gdtoa=yes ;;
+    no)  newlib_use_gdtoa=no  ;;
+    *)   as_fn_error $? "bad value ${enableval} for newlib-use-gdtoa option" "$LINENO" 5 ;;
+  esac
+ fi
+else
+  newlib_use_gdtoa=yes
+fi
+
 
 # Make sure we can run config.sub.
 $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
@@ -2643,7 +2688,7 @@ case $as_dir/ in #((
     # by default.
     for ac_prog in ginstall scoinst install; do
       for ac_exec_ext in '' $ac_executable_extensions; do
-	if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+	if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
 	  if test $ac_prog = install &&
 	    grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
 	    # AIX install.  It has an incompatible calling convention.
@@ -2812,7 +2857,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_STRIP="${ac_tool_prefix}strip"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -2852,7 +2897,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_STRIP="strip"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -2903,7 +2948,7 @@ do
   test -z "$as_dir" && as_dir=.
     for ac_prog in mkdir gmkdir; do
 	 for ac_exec_ext in '' $ac_executable_extensions; do
-	   { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue
+	   as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue
 	   case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
 	     'mkdir (GNU coreutils) '* | \
 	     'mkdir (coreutils) '* | \
@@ -2956,7 +3001,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_AWK="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3296,7 +3341,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_CC="gcc"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3464,7 +3509,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
        ac_prog_rejected=yes
        continue
@@ -3642,7 +3687,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_AS="${ac_tool_prefix}as"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3682,7 +3727,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_AS="as"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3734,7 +3779,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_AR="${ac_tool_prefix}ar"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3774,7 +3819,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_AR="ar"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3826,7 +3871,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3866,7 +3911,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_RANLIB="ranlib"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3918,7 +3963,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_READELF="${ac_tool_prefix}readelf"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3958,7 +4003,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_READELF="readelf"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4146,7 +4191,7 @@ do
     for ac_prog in sed gsed; do
     for ac_exec_ext in '' $ac_executable_extensions; do
       ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
-      { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue
+      as_fn_executable_p "$ac_path_SED" || continue
 # Check for GNU ac_path_SED and select it if it is found.
   # Check for GNU $ac_path_SED
 case `"$ac_path_SED" --version 2>&1` in
@@ -4276,7 +4321,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_AWK="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4322,7 +4367,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_AS="${ac_tool_prefix}as"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4362,7 +4407,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_AS="as"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4414,7 +4459,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4454,7 +4499,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_DLLTOOL="dlltool"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4506,7 +4551,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4546,7 +4591,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_OBJDUMP="objdump"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4668,7 +4713,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_CC="${ac_tool_prefix}gcc"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4708,7 +4753,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_CC="gcc"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4761,7 +4806,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_CC="${ac_tool_prefix}cc"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4802,7 +4847,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
        ac_prog_rejected=yes
        continue
@@ -4860,7 +4905,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4904,7 +4949,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_CC="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -5350,8 +5395,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #include <stdarg.h>
 #include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
+struct stat;
 /* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
 struct buf { int x; };
 FILE * (*rcsopen) (struct buf *, struct stat *, int);
@@ -5580,7 +5624,7 @@ do
     for ac_prog in grep ggrep; do
     for ac_exec_ext in '' $ac_executable_extensions; do
       ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
-      { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+      as_fn_executable_p "$ac_path_GREP" || continue
 # Check for GNU ac_path_GREP and select it if it is found.
   # Check for GNU $ac_path_GREP
 case `"$ac_path_GREP" --version 2>&1` in
@@ -5646,7 +5690,7 @@ do
     for ac_prog in egrep; do
     for ac_exec_ext in '' $ac_executable_extensions; do
       ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
-      { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+      as_fn_executable_p "$ac_path_EGREP" || continue
 # Check for GNU ac_path_EGREP and select it if it is found.
   # Check for GNU $ac_path_EGREP
 case `"$ac_path_EGREP" --version 2>&1` in
@@ -5713,7 +5757,7 @@ do
     for ac_prog in fgrep; do
     for ac_exec_ext in '' $ac_executable_extensions; do
       ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
-      { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue
+      as_fn_executable_p "$ac_path_FGREP" || continue
 # Check for GNU ac_path_FGREP and select it if it is found.
   # Check for GNU $ac_path_FGREP
 case `"$ac_path_FGREP" --version 2>&1` in
@@ -5969,7 +6013,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6013,7 +6057,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6353,7 +6397,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6393,7 +6437,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_OBJDUMP="objdump"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6670,7 +6714,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_AR="${ac_tool_prefix}ar"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6710,7 +6754,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_AR="ar"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6775,7 +6819,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_STRIP="${ac_tool_prefix}strip"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6815,7 +6859,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_STRIP="strip"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6874,7 +6918,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6914,7 +6958,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_RANLIB="ranlib"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7504,7 +7548,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7544,7 +7588,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7596,7 +7640,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7636,7 +7680,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_NMEDIT="nmedit"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7688,7 +7732,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7728,7 +7772,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_LIPO="lipo"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7780,7 +7824,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7820,7 +7864,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_OTOOL="otool"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7872,7 +7916,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7912,7 +7956,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_OTOOL64="otool64"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -11855,7 +11899,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11858 "configure"
+#line 11902 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11961,7 +12005,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11964 "configure"
+#line 12008 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12586,6 +12630,13 @@ _ACEOF
 
 fi
 
+if test "${newlib_use_gdtoa}" = "yes"; then
+cat >>confdefs.h <<_ACEOF
+#define _WANT_USE_GDTOA 1
+_ACEOF
+
+fi
+
 
 if test "x${iconv_encodings}" != "x" \
    || test "x${iconv_to_encodings}" != "x" \
@@ -13302,16 +13353,16 @@ if (echo >conf$$.file) 2>/dev/null; then
     # ... but there are two gotchas:
     # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
     # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
-    # In both cases, we have to default to `cp -p'.
+    # In both cases, we have to default to `cp -pR'.
     ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
-      as_ln_s='cp -p'
+      as_ln_s='cp -pR'
   elif ln conf$$.file conf$$ 2>/dev/null; then
     as_ln_s=ln
   else
-    as_ln_s='cp -p'
+    as_ln_s='cp -pR'
   fi
 else
-  as_ln_s='cp -p'
+  as_ln_s='cp -pR'
 fi
 rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
 rmdir conf$$.dir 2>/dev/null
@@ -13371,28 +13422,16 @@ else
   as_mkdir_p=false
 fi
 
-if test -x / >/dev/null 2>&1; then
-  as_test_x='test -x'
-else
-  if ls -dL / >/dev/null 2>&1; then
-    as_ls_L_option=L
-  else
-    as_ls_L_option=
-  fi
-  as_test_x='
-    eval sh -c '\''
-      if test -d "$1"; then
-	test -d "$1/.";
-      else
-	case $1 in #(
-	-*)set "./$1";;
-	esac;
-	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
-	???[sx]*):;;*)false;;esac;fi
-    '\'' sh
-  '
-fi
-as_executable_p=$as_test_x
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
 
 # Sed expression to map a string onto a valid CPP name.
 as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
@@ -13414,7 +13453,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # values after options handling.
 ac_log="
 This file was extended by newlib $as_me 4.1.0, which was
-generated by GNU Autoconf 2.68.  Invocation command line was
+generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
   CONFIG_HEADERS  = $CONFIG_HEADERS
@@ -13480,10 +13519,10 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
 newlib config.status 4.1.0
-configured by $0, generated by GNU Autoconf 2.68,
+configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
-Copyright (C) 2010 Free Software Foundation, Inc.
+Copyright (C) 2012 Free Software Foundation, Inc.
 This config.status script is free software; the Free Software Foundation
 gives unlimited permission to copy, distribute and modify it."
 
@@ -13574,7 +13613,7 @@ fi
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 if \$ac_cs_recheck; then
-  set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
   shift
   \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
   CONFIG_SHELL='$SHELL'
diff --git a/newlib/configure.ac b/newlib/configure.ac
index 49a1b5fdd..25f6d07ed 100644
--- a/newlib/configure.ac
+++ b/newlib/configure.ac
@@ -259,6 +259,17 @@ AC_ARG_ENABLE(newlib-long-time_t,
   esac
  fi], [newlib_long_time_t=no])dnl
 
+dnl Support --enable-newlib-use-gdtoa
+AC_ARG_ENABLE(newlib-use-gdtoa,
+[  --enable-newlib-use-gdtoa   Use gdtoa rather than legacy ldtoa],
+[if test "${newlib_use_gdtoa+set}" != set; then
+  case "${enableval}" in
+    yes) newlib_use_gdtoa=yes ;;
+    no)  newlib_use_gdtoa=no  ;;
+    *)   AC_MSG_ERROR(bad value ${enableval} for newlib-use-gdtoa option) ;;
+  esac
+ fi], [newlib_use_gdtoa=yes])dnl
+
 NEWLIB_CONFIGURE(.)
 
 dnl We have to enable libtool after NEWLIB_CONFIGURE because if we try and
@@ -537,6 +548,10 @@ if test "${newlib_long_time_t}" = "yes"; then
 AC_DEFINE_UNQUOTED(_WANT_USE_LONG_TIME_T)
 fi
 
+if test "${newlib_use_gdtoa}" = "yes"; then
+AC_DEFINE_UNQUOTED(_WANT_USE_GDTOA)
+fi
+
 dnl
 dnl Parse --enable-newlib-iconv-encodings option argument
 dnl
diff --git a/newlib/libc/include/machine/ieee.h b/newlib/libc/include/machine/ieee.h
new file mode 100644
index 000000000..0656909ab
--- /dev/null
+++ b/newlib/libc/include/machine/ieee.h
@@ -0,0 +1,127 @@
+#ifndef _MACHINE_IEEE_H_
+#define _MACHINE_IEEE_H_
+#include <sys/types.h>
+#include <sys/cdefs.h>
+#include <machine/ieeefp.h>
+#include <float.h>
+
+#if LDBL_MANT_DIG == 24
+#define EXT_IMPLICIT_NBIT
+#define EXT_TO_ARRAY32(p, a) do {      \
+    (a)[0] = (p)->ext_frac;  \
+} while (0)
+#ifdef __IEEE_LITTLE_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_frac:23;
+    uint32_t   ext_exp:8;
+    uint32_t   ext_sign:1;
+};
+#endif
+#ifdef __IEEE_BIG_ENDIAN
+struct ieee_ext {
+#ifndef ___IEEE_BYTES_LITTLE_ENDIAN
+    uint32_t   ext_sign:1;
+    uint32_t   ext_exp:8;
+    uint32_t   ext_frac:23;
+#else /* ARMEL without __VFP_FP__ */
+    uint32_t   ext_frac:23;
+    uint32_t   ext_exp:8;
+    uint32_t   ext_sign:1;
+#endif
+};
+#endif
+#elif LDBL_MANT_DIG == 53
+#define EXT_IMPLICIT_NBIT
+#define EXT_TO_ARRAY32(p, a) do {       \
+    (a)[0] = (p)->ext_fracl;  \
+    (a)[1] = (p)->ext_frach;  \
+} while (0)
+#ifdef __IEEE_LITTLE_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_fracl;
+    uint32_t   ext_frach:20;
+    uint32_t   ext_exp:11;
+    uint32_t   ext_sign:1;
+};
+#endif
+#ifdef __IEEE_BIG_ENDIAN
+struct ieee_ext {
+#ifndef ___IEEE_BYTES_LITTLE_ENDIAN
+    uint32_t   ext_sign:1;
+    uint32_t   ext_exp:11;
+    uint32_t   ext_frach:20;
+#else /* ARMEL without __VFP_FP__ */
+    uint32_t   ext_frach:20;
+    uint32_t   ext_exp:11;
+    uint32_t   ext_sign:1;
+#endif
+    uint32_t   ext_fracl;
+};
+#endif
+#elif LDBL_MANT_DIG == 64
+#define EXT_TO_ARRAY32(p, a) do {       \
+    (a)[0] = (p)->ext_fracl;  \
+    (a)[1] = (p)->ext_frach;  \
+} while (0)
+#ifdef __IEEE_LITTLE_ENDIAN /* for Intel CPU */
+struct ieee_ext {
+    uint32_t   ext_fracl;
+    uint32_t   ext_frach;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_sign:1;
+    uint32_t   ext_padl:16;
+    uint32_t   ext_padh;
+};
+#endif
+#ifdef __IEEE_BIG_ENDIAN
+struct ieee_ext {
+#ifndef ___IEEE_BYTES_LITTLE_ENDIAN /* for m68k */
+    uint32_t   ext_sign:1;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_pad:16;
+#else /* ARM FPA10 math coprocessor */
+    uint32_t   ext_exp:15;
+    uint32_t   ext_pad:16;
+    uint32_t   ext_sign:1;
+#endif
+    uint32_t   ext_frach;
+    uint32_t   ext_fracl;
+};
+#endif
+#elif LDBL_MANT_DIG == 113
+#define EXT_IMPLICIT_NBIT
+#define EXT_TO_ARRAY32(p, a) do {        \
+    (a)[0] = (p)->ext_fracl;   \
+    (a)[1] = (p)->ext_fraclm;  \
+    (a)[2] = (p)->ext_frachm;  \
+    (a)[3] = (p)->ext_frach;   \
+} while (0)
+#ifdef __IEEE_LITTLE_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_fracl;
+    uint32_t   ext_fraclm;
+    uint32_t   ext_frachm;
+    uint32_t   ext_frach:16;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_sign:1;
+};
+#endif
+#ifdef __IEEE_BIG_ENDIAN
+struct ieee_ext {
+#ifndef ___IEEE_BYTES_LITTLE_ENDIAN
+    uint32_t   ext_sign:1;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_frach:16;
+#else /* ARMEL without __VFP_FP__ */
+    uint32_t   ext_frach:16;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_sign:1;
+#endif
+    uint32_t   ext_frachm;
+    uint32_t   ext_fraclm;
+    uint32_t   ext_fracl;
+};
+#endif
+#endif
+
+#endif /* _MACHINE_IEEE_H_ */
diff --git a/newlib/libc/include/sys/config.h b/newlib/libc/include/sys/config.h
index b9dff88ff..61a6f95d8 100644
--- a/newlib/libc/include/sys/config.h
+++ b/newlib/libc/include/sys/config.h
@@ -293,6 +293,12 @@
 #endif
 #endif
 
+#ifdef _WANT_USE_GDTOA
+#ifndef _USE_GDTOA
+#define _USE_GDTOA
+#endif
+#endif
+
 /* If _MB_EXTENDED_CHARSETS_ALL is set, we want all of the extended
    charsets.  The extended charsets add a few functions and a couple
    of tables of a few K each. */
diff --git a/newlib/libc/stdlib/Makefile.am b/newlib/libc/stdlib/Makefile.am
index 357e37beb..e353c8d29 100644
--- a/newlib/libc/stdlib/Makefile.am
+++ b/newlib/libc/stdlib/Makefile.am
@@ -38,6 +38,11 @@ GENERAL_SOURCES = \
 	labs.c 		\
 	ldiv.c  	\
 	ldtoa.c		\
+	gdtoa-ldtoa.c	\
+	gdtoa-gdtoa.c	\
+	gdtoa-dtoa.c	\
+	gdtoa-dmisc.c	\
+	gdtoa-gmisc.c	\
 	malloc.c  	\
 	mblen.c		\
 	mblen_r.c	\
@@ -311,7 +316,12 @@ CHEWOUT_FILES= \
 CHAPTERS = stdlib.tex
 
 $(lpfx)dtoa.$(oext): dtoa.c mprec.h
-$(lpfx)ldtoa.$(oext): ldtoa.c mprec.h
+$(lpfx)ldtoa.$(oext): ldtoa.c mprec.h gdtoa.h
+$(lpfx)gdtoa-ldtoa.$(oext): gdtoa-ldtoa.c mprec.h gdtoaimp.h gdtoa.h
+$(lpfx)gdtoa-gdtoa.$(oext): gdtoa-gdtoa.c mprec.h gdtoaimp.h gdtoa.h
+$(lpfx)gdtoa-dtoa.$(oext): gdtoa-dtoa.c mprec.h gdtoaimp.h gdtoa.h
+$(lpfx)gdtoa-dmisc.$(oext): gdtoa-dmisc.c mprec.h gdtoaimp.h gdtoa.h
+$(lpfx)gdtoa-gmisc.$(oext): gdtoa-gmisc.c mprec.h gdtoaimp.h gdtoa.h
 $(lpfx)ecvtbuf.$(oext): ecvtbuf.c mprec.h
 $(lpfx)mbtowc_r.$(oext): mbtowc_r.c mbctype.h
 $(lpfx)mprec.$(oext): mprec.c mprec.h
diff --git a/newlib/libc/stdlib/Makefile.in b/newlib/libc/stdlib/Makefile.in
index a812b6a95..d87334306 100644
--- a/newlib/libc/stdlib/Makefile.in
+++ b/newlib/libc/stdlib/Makefile.in
@@ -101,24 +101,27 @@ am__objects_2 = lib_a-__adjust.$(OBJEXT) lib_a-__atexit.$(OBJEXT) \
 	lib_a-getenv_r.$(OBJEXT) lib_a-imaxabs.$(OBJEXT) \
 	lib_a-imaxdiv.$(OBJEXT) lib_a-itoa.$(OBJEXT) \
 	lib_a-labs.$(OBJEXT) lib_a-ldiv.$(OBJEXT) \
-	lib_a-ldtoa.$(OBJEXT) lib_a-malloc.$(OBJEXT) \
-	lib_a-mblen.$(OBJEXT) lib_a-mblen_r.$(OBJEXT) \
-	lib_a-mbstowcs.$(OBJEXT) lib_a-mbstowcs_r.$(OBJEXT) \
-	lib_a-mbtowc.$(OBJEXT) lib_a-mbtowc_r.$(OBJEXT) \
-	lib_a-mlock.$(OBJEXT) lib_a-mprec.$(OBJEXT) \
-	lib_a-mstats.$(OBJEXT) lib_a-on_exit_args.$(OBJEXT) \
-	lib_a-quick_exit.$(OBJEXT) lib_a-rand.$(OBJEXT) \
-	lib_a-rand_r.$(OBJEXT) lib_a-random.$(OBJEXT) \
-	lib_a-realloc.$(OBJEXT) lib_a-reallocarray.$(OBJEXT) \
-	lib_a-reallocf.$(OBJEXT) lib_a-sb_charsets.$(OBJEXT) \
-	lib_a-strtod.$(OBJEXT) lib_a-strtoimax.$(OBJEXT) \
-	lib_a-strtol.$(OBJEXT) lib_a-strtoul.$(OBJEXT) \
-	lib_a-strtoumax.$(OBJEXT) lib_a-utoa.$(OBJEXT) \
-	lib_a-wcstod.$(OBJEXT) lib_a-wcstoimax.$(OBJEXT) \
-	lib_a-wcstol.$(OBJEXT) lib_a-wcstoul.$(OBJEXT) \
-	lib_a-wcstoumax.$(OBJEXT) lib_a-wcstombs.$(OBJEXT) \
-	lib_a-wcstombs_r.$(OBJEXT) lib_a-wctomb.$(OBJEXT) \
-	lib_a-wctomb_r.$(OBJEXT) $(am__objects_1)
+	lib_a-ldtoa.$(OBJEXT) lib_a-gdtoa-ldtoa.$(OBJEXT) \
+	lib_a-gdtoa-gdtoa.$(OBJEXT) lib_a-gdtoa-dtoa.$(OBJEXT) \
+	lib_a-gdtoa-dmisc.$(OBJEXT) lib_a-gdtoa-gmisc.$(OBJEXT) \
+	lib_a-malloc.$(OBJEXT) lib_a-mblen.$(OBJEXT) \
+	lib_a-mblen_r.$(OBJEXT) lib_a-mbstowcs.$(OBJEXT) \
+	lib_a-mbstowcs_r.$(OBJEXT) lib_a-mbtowc.$(OBJEXT) \
+	lib_a-mbtowc_r.$(OBJEXT) lib_a-mlock.$(OBJEXT) \
+	lib_a-mprec.$(OBJEXT) lib_a-mstats.$(OBJEXT) \
+	lib_a-on_exit_args.$(OBJEXT) lib_a-quick_exit.$(OBJEXT) \
+	lib_a-rand.$(OBJEXT) lib_a-rand_r.$(OBJEXT) \
+	lib_a-random.$(OBJEXT) lib_a-realloc.$(OBJEXT) \
+	lib_a-reallocarray.$(OBJEXT) lib_a-reallocf.$(OBJEXT) \
+	lib_a-sb_charsets.$(OBJEXT) lib_a-strtod.$(OBJEXT) \
+	lib_a-strtoimax.$(OBJEXT) lib_a-strtol.$(OBJEXT) \
+	lib_a-strtoul.$(OBJEXT) lib_a-strtoumax.$(OBJEXT) \
+	lib_a-utoa.$(OBJEXT) lib_a-wcstod.$(OBJEXT) \
+	lib_a-wcstoimax.$(OBJEXT) lib_a-wcstol.$(OBJEXT) \
+	lib_a-wcstoul.$(OBJEXT) lib_a-wcstoumax.$(OBJEXT) \
+	lib_a-wcstombs.$(OBJEXT) lib_a-wcstombs_r.$(OBJEXT) \
+	lib_a-wctomb.$(OBJEXT) lib_a-wctomb_r.$(OBJEXT) \
+	$(am__objects_1)
 am__objects_3 = lib_a-arc4random.$(OBJEXT) \
 	lib_a-arc4random_uniform.$(OBJEXT) lib_a-cxa_atexit.$(OBJEXT) \
 	lib_a-cxa_finalize.$(OBJEXT) lib_a-drand48.$(OBJEXT) \
@@ -165,14 +168,15 @@ am__objects_9 = __adjust.lo __atexit.lo __call_atexit.lo __exp10.lo \
 	div.lo dtoa.lo dtoastub.lo environ.lo envlock.lo eprintf.lo \
 	exit.lo gdtoa-gethex.lo gdtoa-hexnan.lo getenv.lo getenv_r.lo \
 	imaxabs.lo imaxdiv.lo itoa.lo labs.lo ldiv.lo ldtoa.lo \
-	malloc.lo mblen.lo mblen_r.lo mbstowcs.lo mbstowcs_r.lo \
-	mbtowc.lo mbtowc_r.lo mlock.lo mprec.lo mstats.lo \
-	on_exit_args.lo quick_exit.lo rand.lo rand_r.lo random.lo \
-	realloc.lo reallocarray.lo reallocf.lo sb_charsets.lo \
-	strtod.lo strtoimax.lo strtol.lo strtoul.lo strtoumax.lo \
-	utoa.lo wcstod.lo wcstoimax.lo wcstol.lo wcstoul.lo \
-	wcstoumax.lo wcstombs.lo wcstombs_r.lo wctomb.lo wctomb_r.lo \
-	$(am__objects_8)
+	gdtoa-ldtoa.lo gdtoa-gdtoa.lo gdtoa-dtoa.lo gdtoa-dmisc.lo \
+	gdtoa-gmisc.lo malloc.lo mblen.lo mblen_r.lo mbstowcs.lo \
+	mbstowcs_r.lo mbtowc.lo mbtowc_r.lo mlock.lo mprec.lo \
+	mstats.lo on_exit_args.lo quick_exit.lo rand.lo rand_r.lo \
+	random.lo realloc.lo reallocarray.lo reallocf.lo \
+	sb_charsets.lo strtod.lo strtoimax.lo strtol.lo strtoul.lo \
+	strtoumax.lo utoa.lo wcstod.lo wcstoimax.lo wcstol.lo \
+	wcstoul.lo wcstoumax.lo wcstombs.lo wcstombs_r.lo wctomb.lo \
+	wctomb_r.lo $(am__objects_8)
 am__objects_10 = arc4random.lo arc4random_uniform.lo cxa_atexit.lo \
 	cxa_finalize.lo drand48.lo ecvtbuf.lo efgcvt.lo erand48.lo \
 	jrand48.lo lcong48.lo lrand48.lo mrand48.lo msize.lo mtrim.lo \
@@ -354,6 +358,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 shared_machine_dir = @shared_machine_dir@
 sharedstatedir = @sharedstatedir@
@@ -372,13 +377,14 @@ GENERAL_SOURCES = __adjust.c __atexit.c __call_atexit.c __exp10.c \
 	atexit.c atof.c atoff.c atoi.c atol.c calloc.c div.c dtoa.c \
 	dtoastub.c environ.c envlock.c eprintf.c exit.c gdtoa-gethex.c \
 	gdtoa-hexnan.c getenv.c getenv_r.c imaxabs.c imaxdiv.c itoa.c \
-	labs.c ldiv.c ldtoa.c malloc.c mblen.c mblen_r.c mbstowcs.c \
-	mbstowcs_r.c mbtowc.c mbtowc_r.c mlock.c mprec.c mstats.c \
-	on_exit_args.c quick_exit.c rand.c rand_r.c random.c realloc.c \
-	reallocarray.c reallocf.c sb_charsets.c strtod.c strtoimax.c \
-	strtol.c strtoul.c strtoumax.c utoa.c wcstod.c wcstoimax.c \
-	wcstol.c wcstoul.c wcstoumax.c wcstombs.c wcstombs_r.c \
-	wctomb.c wctomb_r.c $(am__append_1)
+	labs.c ldiv.c ldtoa.c gdtoa-ldtoa.c gdtoa-gdtoa.c gdtoa-dtoa.c \
+	gdtoa-dmisc.c gdtoa-gmisc.c malloc.c mblen.c mblen_r.c \
+	mbstowcs.c mbstowcs_r.c mbtowc.c mbtowc_r.c mlock.c mprec.c \
+	mstats.c on_exit_args.c quick_exit.c rand.c rand_r.c random.c \
+	realloc.c reallocarray.c reallocf.c sb_charsets.c strtod.c \
+	strtoimax.c strtol.c strtoul.c strtoumax.c utoa.c wcstod.c \
+	wcstoimax.c wcstol.c wcstoul.c wcstoumax.c wcstombs.c \
+	wcstombs_r.c wctomb.c wctomb_r.c $(am__append_1)
 @NEWLIB_NANO_MALLOC_FALSE@MALIGNR = malignr
 @NEWLIB_NANO_MALLOC_TRUE@MALIGNR = nano-malignr
 @NEWLIB_NANO_MALLOC_FALSE@MALLOPTR = malloptr
@@ -827,6 +833,36 @@ lib_a-ldtoa.o: ldtoa.c
 lib_a-ldtoa.obj: ldtoa.c
 	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-ldtoa.obj `if test -f 'ldtoa.c'; then $(CYGPATH_W) 'ldtoa.c'; else $(CYGPATH_W) '$(srcdir)/ldtoa.c'; fi`
 
+lib_a-gdtoa-ldtoa.o: gdtoa-ldtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-ldtoa.o `test -f 'gdtoa-ldtoa.c' || echo '$(srcdir)/'`gdtoa-ldtoa.c
+
+lib_a-gdtoa-ldtoa.obj: gdtoa-ldtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-ldtoa.obj `if test -f 'gdtoa-ldtoa.c'; then $(CYGPATH_W) 'gdtoa-ldtoa.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-ldtoa.c'; fi`
+
+lib_a-gdtoa-gdtoa.o: gdtoa-gdtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-gdtoa.o `test -f 'gdtoa-gdtoa.c' || echo '$(srcdir)/'`gdtoa-gdtoa.c
+
+lib_a-gdtoa-gdtoa.obj: gdtoa-gdtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-gdtoa.obj `if test -f 'gdtoa-gdtoa.c'; then $(CYGPATH_W) 'gdtoa-gdtoa.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-gdtoa.c'; fi`
+
+lib_a-gdtoa-dtoa.o: gdtoa-dtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-dtoa.o `test -f 'gdtoa-dtoa.c' || echo '$(srcdir)/'`gdtoa-dtoa.c
+
+lib_a-gdtoa-dtoa.obj: gdtoa-dtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-dtoa.obj `if test -f 'gdtoa-dtoa.c'; then $(CYGPATH_W) 'gdtoa-dtoa.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-dtoa.c'; fi`
+
+lib_a-gdtoa-dmisc.o: gdtoa-dmisc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-dmisc.o `test -f 'gdtoa-dmisc.c' || echo '$(srcdir)/'`gdtoa-dmisc.c
+
+lib_a-gdtoa-dmisc.obj: gdtoa-dmisc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-dmisc.obj `if test -f 'gdtoa-dmisc.c'; then $(CYGPATH_W) 'gdtoa-dmisc.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-dmisc.c'; fi`
+
+lib_a-gdtoa-gmisc.o: gdtoa-gmisc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-gmisc.o `test -f 'gdtoa-gmisc.c' || echo '$(srcdir)/'`gdtoa-gmisc.c
+
+lib_a-gdtoa-gmisc.obj: gdtoa-gmisc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-gmisc.obj `if test -f 'gdtoa-gmisc.c'; then $(CYGPATH_W) 'gdtoa-gmisc.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-gmisc.c'; fi`
+
 lib_a-malloc.o: malloc.c
 	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-malloc.o `test -f 'malloc.c' || echo '$(srcdir)/'`malloc.c
 
@@ -1610,7 +1646,12 @@ $(lpfx)$(MALLOPTR).$(oext): $(MALLOCR).c
 	$(MALLOC_COMPILE) -DDEFINE_MALLOPT -c $(srcdir)/$(MALLOCR).c -o $@
 
 $(lpfx)dtoa.$(oext): dtoa.c mprec.h
-$(lpfx)ldtoa.$(oext): ldtoa.c mprec.h
+$(lpfx)ldtoa.$(oext): ldtoa.c mprec.h gdtoa.h
+$(lpfx)gdtoa-ldtoa.$(oext): gdtoa-ldtoa.c mprec.h gdtoaimp.h gdtoa.h
+$(lpfx)gdtoa-gdtoa.$(oext): gdtoa-gdtoa.c mprec.h gdtoaimp.h gdtoa.h
+$(lpfx)gdtoa-dtoa.$(oext): gdtoa-dtoa.c mprec.h gdtoaimp.h gdtoa.h
+$(lpfx)gdtoa-dmisc.$(oext): gdtoa-dmisc.c mprec.h gdtoaimp.h gdtoa.h
+$(lpfx)gdtoa-gmisc.$(oext): gdtoa-gmisc.c mprec.h gdtoaimp.h gdtoa.h
 $(lpfx)ecvtbuf.$(oext): ecvtbuf.c mprec.h
 $(lpfx)mbtowc_r.$(oext): mbtowc_r.c mbctype.h
 $(lpfx)mprec.$(oext): mprec.c mprec.h
diff --git a/newlib/libc/stdlib/gdtoa-dmisc.c b/newlib/libc/stdlib/gdtoa-dmisc.c
new file mode 100644
index 000000000..332023dae
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-dmisc.c
@@ -0,0 +1,230 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include <newlib.h>
+#include <sys/config.h>
+
+#ifdef _USE_GDTOA
+#include "gdtoaimp.h"
+
+#ifndef MULTIPLE_THREADS
+ char *dtoa_result;
+#endif
+
+ char *
+#ifdef KR_headers
+rv_alloc(ptr, i) struct _reent *ptr, int i;
+#else
+rv_alloc(struct _reent *ptr, int i)
+#endif
+{
+	int j, k, *r;
+
+	j = sizeof(ULong);
+	for(k = 0;
+		sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i;
+		j <<= 1)
+			k++;
+	r = (int*)Balloc(ptr, k);
+	if (r == NULL)
+		return (
+#ifndef MULTIPLE_THREADS
+		dtoa_result =
+#endif
+			NULL);
+	*r = k;
+	return
+#ifndef MULTIPLE_THREADS
+	dtoa_result =
+#endif
+		(char *)(r+1);
+	}
+
+ char *
+#ifdef KR_headers
+nrv_alloc(ptr, s, rve, n) struct _reent *ptr, char *s, **rve; int n;
+#else
+nrv_alloc(struct _reent *ptr, char *s, char **rve, int n)
+#endif
+{
+	char *rv, *t;
+
+	t = rv = rv_alloc(ptr, n);
+	if (t == NULL)
+		return (NULL);
+	while((*t = *s++) !=0)
+		t++;
+	if (rve)
+		*rve = t;
+	return rv;
+	}
+
+/* freedtoa(s) must be used to free values s returned by dtoa
+ * when MULTIPLE_THREADS is #defined.  It should be used in all cases,
+ * but for consistency with earlier versions of dtoa, it is optional
+ * when MULTIPLE_THREADS is not defined.
+ */
+
+ void
+#ifdef KR_headers
+freedtoa(ptr, s) struct _reent *ptr, char *s;
+#else
+freedtoa(struct _reent *ptr, char *s)
+#endif
+{
+	Bigint *b = (Bigint *)((int *)s - 1);
+	b->_maxwds = 1 << (b->_k = *(int*)b);
+	Bfree(ptr, b);
+#ifndef MULTIPLE_THREADS
+	if (s == dtoa_result)
+		dtoa_result = 0;
+#endif
+	}
+DEF_STRONG(freedtoa);
+
+ int
+quorem
+#ifdef KR_headers
+	(b, S) Bigint *b, *S;
+#else
+	(Bigint *b, Bigint *S)
+#endif
+{
+	int n;
+	ULong *bx, *bxe, q, *sx, *sxe;
+#ifdef ULLong
+	ULLong borrow, carry, y, ys;
+#else
+	ULong borrow, carry, y, ys;
+#ifdef Pack_32
+	ULong si, z, zs;
+#endif
+#endif
+
+	n = S->_wds;
+#ifdef DEBUG
+	/*debug*/ if (b->_wds > n)
+	/*debug*/	Bug("oversize b in quorem");
+#endif
+	if (b->_wds < n)
+		return 0;
+	sx = S->_x;
+	sxe = sx + --n;
+	bx = b->_x;
+	bxe = bx + n;
+	q = *bxe / (*sxe + 1);	/* ensure q <= true quotient */
+#ifdef DEBUG
+	/*debug*/ if (q > 9)
+	/*debug*/	Bug("oversized quotient in quorem");
+#endif
+	if (q) {
+		borrow = 0;
+		carry = 0;
+		do {
+#ifdef ULLong
+			ys = *sx++ * (ULLong)q + carry;
+			carry = ys >> 32;
+			y = *bx - (ys & 0xffffffffUL) - borrow;
+			borrow = y >> 32 & 1UL;
+			*bx++ = y & 0xffffffffUL;
+#else
+#ifdef Pack_32
+			si = *sx++;
+			ys = (si & 0xffff) * q + carry;
+			zs = (si >> 16) * q + (ys >> 16);
+			carry = zs >> 16;
+			y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			z = (*bx >> 16) - (zs & 0xffff) - borrow;
+			borrow = (z & 0x10000) >> 16;
+			Storeinc(bx, z, y);
+#else
+			ys = *sx++ * q + carry;
+			carry = ys >> 16;
+			y = *bx - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			*bx++ = y & 0xffff;
+#endif
+#endif
+			}
+			while(sx <= sxe);
+		if (!*bxe) {
+			bx = b->_x;
+			while(--bxe > bx && !*bxe)
+				--n;
+			b->_wds = n;
+			}
+		}
+	if (cmp(b, S) >= 0) {
+		q++;
+		borrow = 0;
+		carry = 0;
+		bx = b->_x;
+		sx = S->_x;
+		do {
+#ifdef ULLong
+			ys = *sx++ + carry;
+			carry = ys >> 32;
+			y = *bx - (ys & 0xffffffffUL) - borrow;
+			borrow = y >> 32 & 1UL;
+			*bx++ = y & 0xffffffffUL;
+#else
+#ifdef Pack_32
+			si = *sx++;
+			ys = (si & 0xffff) + carry;
+			zs = (si >> 16) + (ys >> 16);
+			carry = zs >> 16;
+			y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			z = (*bx >> 16) - (zs & 0xffff) - borrow;
+			borrow = (z & 0x10000) >> 16;
+			Storeinc(bx, z, y);
+#else
+			ys = *sx++ + carry;
+			carry = ys >> 16;
+			y = *bx - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			*bx++ = y & 0xffff;
+#endif
+#endif
+			}
+			while(sx <= sxe);
+		bx = b->_x;
+		bxe = bx + n;
+		if (!*bxe) {
+			while(--bxe > bx && !*bxe)
+				--n;
+			b->_wds = n;
+			}
+		}
+	return q;
+	}
+#endif /* _USE_GDTOA */
diff --git a/newlib/libc/stdlib/gdtoa-dtoa.c b/newlib/libc/stdlib/gdtoa-dtoa.c
new file mode 100644
index 000000000..f05265855
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-dtoa.c
@@ -0,0 +1,846 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998, 1999 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include <newlib.h>
+#include <sys/config.h>
+
+#ifdef _USE_GDTOA
+#include "gdtoaimp.h"
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ *	1. Rather than iterating, we use a simple numeric overestimate
+ *	   to determine k = floor(log10(d)).  We scale relevant
+ *	   quantities using O(log2(k)) rather than O(k) multiplications.
+ *	2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ *	   try to generate digits strictly left to right.  Instead, we
+ *	   compute with fewer bits and propagate the carry if necessary
+ *	   when rounding the final digit up.  This is often faster.
+ *	3. Under the assumption that input will be rounded nearest,
+ *	   mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ *	   That is, we allow equality in stopping tests when the
+ *	   round-nearest rule will give the same floating-point value
+ *	   as would satisfaction of the stopping test with strict
+ *	   inequality.
+ *	4. We remove common factors of powers of 2 from relevant
+ *	   quantities.
+ *	5. When converting floating-point integers less than 1e16,
+ *	   we use floating-point arithmetic rather than resorting
+ *	   to multiple-precision integers.
+ *	6. When asked to produce fewer than 15 digits, we first try
+ *	   to get by with floating-point arithmetic; we resort to
+ *	   multiple-precision integer arithmetic only if we cannot
+ *	   guarantee that the floating-point calculation has given
+ *	   the correctly rounded result.  For k requested digits and
+ *	   "uniformly" distributed input, the probability is
+ *	   something like 10^(k-15) that we must resort to the Long
+ *	   calculation.
+ */
+
+#ifdef Honor_FLT_ROUNDS
+#undef Check_FLT_ROUNDS
+#define Check_FLT_ROUNDS
+#else
+#define Rounding Flt_Rounds
+#endif
+
+ char *
+dtoa
+#ifdef KR_headers
+	(ptr, d0, mode, ndigits, decpt, sign, rve)
+	struct _reent *ptr,
+	double d0; int mode, ndigits, *decpt, *sign; char **rve;
+#else
+	(struct _reent *ptr,
+	 double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
+#endif
+{
+ /*	Arguments ndigits, decpt, sign are similar to those
+	of ecvt and fcvt; trailing zeros are suppressed from
+	the returned string.  If not null, *rve is set to point
+	to the end of the return value.  If d is +-Infinity or NaN,
+	then *decpt is set to 9999.
+
+	mode:
+		0 ==> shortest string that yields d when read in
+			and rounded to nearest.
+		1 ==> like 0, but with Steele & White stopping rule;
+			e.g. with IEEE P754 arithmetic , mode 0 gives
+			1e23 whereas mode 1 gives 9.999999999999999e22.
+		2 ==> max(1,ndigits) significant digits.  This gives a
+			return value similar to that of ecvt, except
+			that trailing zeros are suppressed.
+		3 ==> through ndigits past the decimal point.  This
+			gives a return value similar to that from fcvt,
+			except that trailing zeros are suppressed, and
+			ndigits can be negative.
+		4,5 ==> similar to 2 and 3, respectively, but (in
+			round-nearest mode) with the tests of mode 0 to
+			possibly return a shorter string that rounds to d.
+			With IEEE arithmetic and compilation with
+			-DHonor_FLT_ROUNDS, modes 4 and 5 behave the same
+			as modes 2 and 3 when FLT_ROUNDS != 1.
+		6-9 ==> Debugging modes similar to mode - 4:  don't try
+			fast floating-point estimate (if applicable).
+
+		Values of mode other than 0-9 are treated as mode 0.
+
+		Sufficient space is allocated to the return value
+		to hold the suppressed trailing zeros.
+	*/
+
+	int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,
+		j, j1, k, k0, k_check, leftright, m2, m5, s2, s5,
+		spec_case, try_quick;
+	Long L;
+#ifndef Sudden_Underflow
+	int denorm;
+	ULong x;
+#endif
+	Bigint *b, *b1, *delta, *mlo, *mhi, *S;
+	U d, d2, eps;
+	double ds;
+	char *s, *s0;
+#ifdef SET_INEXACT
+	int inexact, oldinexact;
+#endif
+#ifdef Honor_FLT_ROUNDS /*{*/
+	int Rounding;
+#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */
+	Rounding = Flt_Rounds;
+#else /*}{*/
+	Rounding = 1;
+	switch(fegetround()) {
+	  case FE_TOWARDZERO:	Rounding = 0; break;
+	  case FE_UPWARD:	Rounding = 2; break;
+	  case FE_DOWNWARD:	Rounding = 3;
+	  }
+#endif /*}}*/
+#endif /*}*/
+
+#ifndef MULTIPLE_THREADS
+	if (dtoa_result) {
+		freedtoa(ptr, dtoa_result);
+		dtoa_result = 0;
+		}
+#endif
+	d.d = d0;
+	if (word0(d) & Sign_bit) {
+		/* set sign for everything, including 0's and NaNs */
+		*sign = 1;
+		word0(d) &= ~Sign_bit;	/* clear sign bit */
+		}
+	else
+		*sign = 0;
+
+#if defined(IEEE_Arith) + defined(VAX)
+#ifdef IEEE_Arith
+	if ((word0(d) & Exp_mask) == Exp_mask)
+#else
+	if (word0(d)  == 0x8000)
+#endif
+		{
+		/* Infinity or NaN */
+		*decpt = 9999;
+#ifdef IEEE_Arith
+		if (!word1(d) && !(word0(d) & 0xfffff))
+			return nrv_alloc(ptr, "Infinity", rve, 8);
+#endif
+		return nrv_alloc(ptr, "NaN", rve, 3);
+		}
+#endif
+#ifdef IBM
+	dval(d) += 0; /* normalize */
+#endif
+	if (!dval(d)) {
+		*decpt = 1;
+		return nrv_alloc(ptr, "0", rve, 1);
+		}
+
+#ifdef SET_INEXACT
+	try_quick = oldinexact = get_inexact();
+	inexact = 1;
+#endif
+#ifdef Honor_FLT_ROUNDS
+	if (Rounding >= 2) {
+		if (*sign)
+			Rounding = Rounding == 2 ? 0 : 2;
+		else
+			if (Rounding != 2)
+				Rounding = 0;
+		}
+#endif
+
+	b = d2b(ptr, dval(d), &be, &bbits);
+	if (b == NULL)
+		return (NULL);
+#ifdef Sudden_Underflow
+	i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
+#else
+	if (( i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)) )!=0) {
+#endif
+		dval(d2) = dval(d);
+		word0(d2) &= Frac_mask1;
+		word0(d2) |= Exp_11;
+#ifdef IBM
+		if (( j = 11 - hi0bits(word0(d2) & Frac_mask) )!=0)
+			dval(d2) /= 1 << j;
+#endif
+
+		/* log(x)	~=~ log(1.5) + (x-1.5)/1.5
+		 * log10(x)	 =  log(x) / log(10)
+		 *		~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+		 * log10(&d) = (i-Bias)*log(2)/log(10) + log10(&d2)
+		 *
+		 * This suggests computing an approximation k to log10(&d) by
+		 *
+		 * k = (i - Bias)*0.301029995663981
+		 *	+ ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+		 *
+		 * We want k to be too large rather than too small.
+		 * The error in the first-order Taylor series approximation
+		 * is in our favor, so we just round up the constant enough
+		 * to compensate for any error in the multiplication of
+		 * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+		 * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+		 * adding 1e-13 to the constant term more than suffices.
+		 * Hence we adjust the constant term to 0.1760912590558.
+		 * (We could get a more accurate k by invoking log10,
+		 *  but this is probably not worthwhile.)
+		 */
+
+		i -= Bias;
+#ifdef IBM
+		i <<= 2;
+		i += j;
+#endif
+#ifndef Sudden_Underflow
+		denorm = 0;
+		}
+	else {
+		/* d is denormalized */
+
+		i = bbits + be + (Bias + (P-1) - 1);
+		x = i > 32  ? word0(d) << (64 - i) | word1(d) >> (i - 32)
+			    : word1(d) << (32 - i);
+		dval(d2) = x;
+		word0(d2) -= 31*Exp_msk1; /* adjust exponent */
+		i -= (Bias + (P-1) - 1) + 1;
+		denorm = 1;
+		}
+#endif
+	ds = (dval(d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
+	k = (int)ds;
+	if (ds < 0. && ds != k)
+		k--;	/* want k = floor(ds) */
+	k_check = 1;
+	if (k >= 0 && k <= Ten_pmax) {
+		if (dval(d) < tens[k])
+			k--;
+		k_check = 0;
+		}
+	j = bbits - i - 1;
+	if (j >= 0) {
+		b2 = 0;
+		s2 = j;
+		}
+	else {
+		b2 = -j;
+		s2 = 0;
+		}
+	if (k >= 0) {
+		b5 = 0;
+		s5 = k;
+		s2 += k;
+		}
+	else {
+		b2 -= k;
+		b5 = -k;
+		s5 = 0;
+		}
+	if (mode < 0 || mode > 9)
+		mode = 0;
+
+#ifndef SET_INEXACT
+#ifdef Check_FLT_ROUNDS
+	try_quick = Rounding == 1;
+#else
+	try_quick = 1;
+#endif
+#endif /*SET_INEXACT*/
+
+	if (mode > 5) {
+		mode -= 4;
+		try_quick = 0;
+		}
+	leftright = 1;
+	ilim = ilim1 = -1;	/* Values for cases 0 and 1; done here to */
+				/* silence erroneous "gcc -Wall" warning. */
+	switch(mode) {
+		case 0:
+		case 1:
+			i = 18;
+			ndigits = 0;
+			break;
+		case 2:
+			leftright = 0;
+			/* no break */
+		case 4:
+			if (ndigits <= 0)
+				ndigits = 1;
+			ilim = ilim1 = i = ndigits;
+			break;
+		case 3:
+			leftright = 0;
+			/* no break */
+		case 5:
+			i = ndigits + k + 1;
+			ilim = i;
+			ilim1 = i - 1;
+			if (i <= 0)
+				i = 1;
+		}
+	s = s0 = rv_alloc(ptr, i);
+	if (s == NULL)
+		return (NULL);
+
+#ifdef Honor_FLT_ROUNDS
+	if (mode > 1 && Rounding != 1)
+		leftright = 0;
+#endif
+
+	if (ilim >= 0 && ilim <= Quick_max && try_quick) {
+
+		/* Try to get by with floating-point arithmetic. */
+
+		i = 0;
+		dval(d2) = dval(d);
+		k0 = k;
+		ilim0 = ilim;
+		ieps = 2; /* conservative */
+		if (k > 0) {
+			ds = tens[k&0xf];
+			j = k >> 4;
+			if (j & Bletch) {
+				/* prevent overflows */
+				j &= Bletch - 1;
+				dval(d) /= bigtens[n_bigtens-1];
+				ieps++;
+				}
+			for(; j; j >>= 1, i++)
+				if (j & 1) {
+					ieps++;
+					ds *= bigtens[i];
+					}
+			dval(d) /= ds;
+			}
+		else if (( j1 = -k )!=0) {
+			dval(d) *= tens[j1 & 0xf];
+			for(j = j1 >> 4; j; j >>= 1, i++)
+				if (j & 1) {
+					ieps++;
+					dval(d) *= bigtens[i];
+					}
+			}
+		if (k_check && dval(d) < 1. && ilim > 0) {
+			if (ilim1 <= 0)
+				goto fast_failed;
+			ilim = ilim1;
+			k--;
+			dval(d) *= 10.;
+			ieps++;
+			}
+		dval(eps) = ieps*dval(d) + 7.;
+		word0(eps) -= (P-1)*Exp_msk1;
+		if (ilim == 0) {
+			S = mhi = 0;
+			dval(d) -= 5.;
+			if (dval(d) > dval(eps))
+				goto one_digit;
+			if (dval(d) < -dval(eps))
+				goto no_digits;
+			goto fast_failed;
+			}
+#ifndef No_leftright
+		if (leftright) {
+			/* Use Steele & White method of only
+			 * generating digits needed.
+			 */
+			dval(eps) = 0.5/tens[ilim-1] - dval(eps);
+			for(i = 0;;) {
+				L = dval(d);
+				dval(d) -= L;
+				*s++ = '0' + (int)L;
+				if (dval(d) < dval(eps))
+					goto ret1;
+				if (1. - dval(d) < dval(eps))
+					goto bump_up;
+				if (++i >= ilim)
+					break;
+				dval(eps) *= 10.;
+				dval(d) *= 10.;
+				}
+			}
+		else {
+#endif
+			/* Generate ilim digits, then fix them up. */
+			dval(eps) *= tens[ilim-1];
+			for(i = 1;; i++, dval(d) *= 10.) {
+				L = (Long)(dval(d));
+				if (!(dval(d) -= L))
+					ilim = i;
+				*s++ = '0' + (int)L;
+				if (i == ilim) {
+					if (dval(d) > 0.5 + dval(eps))
+						goto bump_up;
+					else if (dval(d) < 0.5 - dval(eps)) {
+						while(*--s == '0');
+						s++;
+						goto ret1;
+						}
+					break;
+					}
+				}
+#ifndef No_leftright
+			}
+#endif
+ fast_failed:
+		s = s0;
+		dval(d) = dval(d2);
+		k = k0;
+		ilim = ilim0;
+		}
+
+	/* Do we have a "small" integer? */
+
+	if (be >= 0 && k <= Int_max) {
+		/* Yes. */
+		ds = tens[k];
+		if (ndigits < 0 && ilim <= 0) {
+			S = mhi = 0;
+			if (ilim < 0 || dval(d) <= 5*ds)
+				goto no_digits;
+			goto one_digit;
+			}
+		for(i = 1;; i++, dval(d) *= 10.) {
+			L = (Long)(dval(d) / ds);
+			dval(d) -= L*ds;
+#ifdef Check_FLT_ROUNDS
+			/* If FLT_ROUNDS == 2, L will usually be high by 1 */
+			if (dval(d) < 0) {
+				L--;
+				dval(d) += ds;
+				}
+#endif
+			*s++ = '0' + (int)L;
+			if (!dval(d)) {
+#ifdef SET_INEXACT
+				inexact = 0;
+#endif
+				break;
+				}
+			if (i == ilim) {
+#ifdef Honor_FLT_ROUNDS
+				if (mode > 1)
+				switch(Rounding) {
+				  case 0: goto ret1;
+				  case 2: goto bump_up;
+				  }
+#endif
+				dval(d) += dval(d);
+#ifdef ROUND_BIASED
+				if (dval(d) >= ds)
+#else
+				if (dval(d) > ds || (dval(d) == ds && L & 1))
+#endif
+					{
+ bump_up:
+					while(*--s == '9')
+						if (s == s0) {
+							k++;
+							*s = '0';
+							break;
+							}
+					++*s++;
+					}
+				break;
+				}
+			}
+		goto ret1;
+		}
+
+	m2 = b2;
+	m5 = b5;
+	mhi = mlo = 0;
+	if (leftright) {
+		i =
+#ifndef Sudden_Underflow
+			denorm ? be + (Bias + (P-1) - 1 + 1) :
+#endif
+#ifdef IBM
+			1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3);
+#else
+			1 + P - bbits;
+#endif
+		b2 += i;
+		s2 += i;
+		mhi = i2b(ptr, 1);
+		if (mhi == NULL)
+			return (NULL);
+		}
+	if (m2 > 0 && s2 > 0) {
+		i = m2 < s2 ? m2 : s2;
+		b2 -= i;
+		m2 -= i;
+		s2 -= i;
+		}
+	if (b5 > 0) {
+		if (leftright) {
+			if (m5 > 0) {
+				mhi = pow5mult(ptr, mhi, m5);
+				if (mhi == NULL)
+					return (NULL);
+				b1 = mult(ptr, mhi, b);
+				if (b1 == NULL)
+					return (NULL);
+				Bfree(ptr, b);
+				b = b1;
+				}
+			if (( j = b5 - m5 )!=0) {
+				b = pow5mult(ptr, b, j);
+				if (b == NULL)
+					return (NULL);
+				}
+			}
+		else {
+			b = pow5mult(ptr, b, b5);
+			if (b == NULL)
+				return (NULL);
+			}
+		}
+	S = i2b(ptr, 1);
+	if (S == NULL)
+		return (NULL);
+	if (s5 > 0) {
+		S = pow5mult(ptr, S, s5);
+		if (S == NULL)
+			return (NULL);
+		}
+
+	/* Check for special case that d is a normalized power of 2. */
+
+	spec_case = 0;
+	if ((mode < 2 || leftright)
+#ifdef Honor_FLT_ROUNDS
+			&& Rounding == 1
+#endif
+				) {
+		if (!word1(d) && !(word0(d) & Bndry_mask)
+#ifndef Sudden_Underflow
+		 && word0(d) & (Exp_mask & ~Exp_msk1)
+#endif
+				) {
+			/* The special case */
+			b2 += Log2P;
+			s2 += Log2P;
+			spec_case = 1;
+			}
+		}
+
+	/* Arrange for convenient computation of quotients:
+	 * shift left if necessary so divisor has 4 leading 0 bits.
+	 *
+	 * Perhaps we should just compute leading 28 bits of S once
+	 * and for all and pass them and a shift to quorem, so it
+	 * can do shifts and ors to compute the numerator for q.
+	 */
+#ifdef Pack_32
+	if (( i = ((s5 ? 32 - hi0bits(S->_x[S->_wds-1]) : 1) + s2) & 0x1f )!=0)
+		i = 32 - i;
+#else
+	if (( i = ((s5 ? 32 - hi0bits(S->_x[S->_wds-1]) : 1) + s2) & 0xf )!=0)
+		i = 16 - i;
+#endif
+	if (i > 4) {
+		i -= 4;
+		b2 += i;
+		m2 += i;
+		s2 += i;
+		}
+	else if (i < 4) {
+		i += 28;
+		b2 += i;
+		m2 += i;
+		s2 += i;
+		}
+	if (b2 > 0) {
+		b = lshift(ptr, b, b2);
+		if (b == NULL)
+			return (NULL);
+		}
+	if (s2 > 0) {
+		S = lshift(ptr, S, s2);
+		if (S == NULL)
+			return (NULL);
+		}
+	if (k_check) {
+		if (cmp(b,S) < 0) {
+			k--;
+			b = multadd(ptr, b, 10, 0); /* we botched the k estimate */
+			if (b == NULL)
+				return (NULL);
+			if (leftright) {
+				mhi = multadd(ptr, mhi, 10, 0);
+				if (mhi == NULL)
+					return (NULL);
+				}
+			ilim = ilim1;
+			}
+		}
+	if (ilim <= 0 && (mode == 3 || mode == 5)) {
+		S = multadd(ptr, S,5,0);
+		if (S == NULL)
+			return (NULL);
+		if (ilim < 0 || cmp(b,S) <= 0) {
+			/* no digits, fcvt style */
+ no_digits:
+			k = -1 - ndigits;
+			goto ret;
+			}
+ one_digit:
+		*s++ = '1';
+		k++;
+		goto ret;
+		}
+	if (leftright) {
+		if (m2 > 0) {
+			mhi = lshift(ptr, mhi, m2);
+			if (mhi == NULL)
+				return (NULL);
+			}
+
+		/* Compute mlo -- check for special case
+		 * that d is a normalized power of 2.
+		 */
+
+		mlo = mhi;
+		if (spec_case) {
+			mhi = Balloc(ptr, mhi->_k);
+			if (mhi == NULL)
+				return (NULL);
+			Bcopy(mhi, mlo);
+			mhi = lshift(ptr, mhi, Log2P);
+			if (mhi == NULL)
+				return (NULL);
+			}
+
+		for(i = 1;;i++) {
+			dig = quorem(b,S) + '0';
+			/* Do we yet have the shortest decimal string
+			 * that will round to d?
+			 */
+			j = cmp(b, mlo);
+			delta = diff(ptr, S, mhi);
+			if (delta == NULL)
+				return (NULL);
+			j1 = delta->_sign ? 1 : cmp(b, delta);
+			Bfree(ptr, delta);
+#ifndef ROUND_BIASED
+			if (j1 == 0 && mode != 1 && !(word1(d) & 1)
+#ifdef Honor_FLT_ROUNDS
+				&& Rounding >= 1
+#endif
+								   ) {
+				if (dig == '9')
+					goto round_9_up;
+				if (j > 0)
+					dig++;
+#ifdef SET_INEXACT
+				else if (!b->_x[0] && b->_wds <= 1)
+					inexact = 0;
+#endif
+				*s++ = dig;
+				goto ret;
+				}
+#endif
+			if (j < 0 || (j == 0 && mode != 1
+#ifndef ROUND_BIASED
+							&& !(word1(d) & 1)
+#endif
+					)) {
+				if (!b->_x[0] && b->_wds <= 1) {
+#ifdef SET_INEXACT
+					inexact = 0;
+#endif
+					goto accept_dig;
+					}
+#ifdef Honor_FLT_ROUNDS
+				if (mode > 1)
+				 switch(Rounding) {
+				  case 0: goto accept_dig;
+				  case 2: goto keep_dig;
+				  }
+#endif /*Honor_FLT_ROUNDS*/
+				if (j1 > 0) {
+					b = lshift(ptr, b, 1);
+					if (b == NULL)
+						return (NULL);
+					j1 = cmp(b, S);
+#ifdef ROUND_BIASED
+					if (j1 >= 0 /*)*/
+#else
+					if ((j1 > 0 || (j1 == 0 && dig & 1))
+#endif
+					&& dig++ == '9')
+						goto round_9_up;
+					}
+ accept_dig:
+				*s++ = dig;
+				goto ret;
+				}
+			if (j1 > 0) {
+#ifdef Honor_FLT_ROUNDS
+				if (!Rounding)
+					goto accept_dig;
+#endif
+				if (dig == '9') { /* possible if i == 1 */
+ round_9_up:
+					*s++ = '9';
+					goto roundoff;
+					}
+				*s++ = dig + 1;
+				goto ret;
+				}
+#ifdef Honor_FLT_ROUNDS
+ keep_dig:
+#endif
+			*s++ = dig;
+			if (i == ilim)
+				break;
+			b = multadd(ptr, b, 10, 0);
+			if (b == NULL)
+				return (NULL);
+			if (mlo == mhi) {
+				mlo = mhi = multadd(ptr, mhi, 10, 0);
+				if (mlo == NULL)
+					return (NULL);
+				}
+			else {
+				mlo = multadd(ptr, mlo, 10, 0);
+				if (mlo == NULL)
+					return (NULL);
+				mhi = multadd(ptr, mhi, 10, 0);
+				if (mhi == NULL)
+					return (NULL);
+				}
+			}
+		}
+	else
+		for(i = 1;; i++) {
+			*s++ = dig = quorem(b,S) + '0';
+			if (!b->_x[0] && b->_wds <= 1) {
+#ifdef SET_INEXACT
+				inexact = 0;
+#endif
+				goto ret;
+				}
+			if (i >= ilim)
+				break;
+			b = multadd(ptr, b, 10, 0);
+			if (b == NULL)
+				return (NULL);
+			}
+
+	/* Round off last digit */
+
+#ifdef Honor_FLT_ROUNDS
+	switch(Rounding) {
+	  case 0: goto trimzeros;
+	  case 2: goto roundoff;
+	  }
+#endif
+	b = lshift(ptr, b, 1);
+	if (b == NULL)
+		return (NULL);
+	j = cmp(b, S);
+#ifdef ROUND_BIASED
+	if (j >= 0)
+#else
+	if (j > 0 || (j == 0 && dig & 1))
+#endif
+		{
+ roundoff:
+		while(*--s == '9')
+			if (s == s0) {
+				k++;
+				*s++ = '1';
+				goto ret;
+				}
+		++*s++;
+		}
+	else {
+#ifdef Honor_FLT_ROUNDS
+ trimzeros:
+#endif
+		while(*--s == '0');
+		s++;
+		}
+ ret:
+	Bfree(ptr, S);
+	if (mhi) {
+		if (mlo && mlo != mhi)
+			Bfree(ptr, mlo);
+		Bfree(ptr, mhi);
+		}
+ ret1:
+#ifdef SET_INEXACT
+	if (inexact) {
+		if (!oldinexact) {
+			word0(d) = Exp_1 + (70 << Exp_shift);
+			word1(d) = 0;
+			dval(d) += 1.;
+			}
+		}
+	else if (!oldinexact)
+		clear_inexact();
+#endif
+	Bfree(ptr, b);
+	*s = 0;
+	*decpt = k + 1;
+	if (rve)
+		*rve = s;
+	return s0;
+}
+#endif /* _USE_GDTOA */
diff --git a/newlib/libc/stdlib/gdtoa-gdtoa.c b/newlib/libc/stdlib/gdtoa-gdtoa.c
new file mode 100644
index 000000000..da2338c48
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-gdtoa.c
@@ -0,0 +1,837 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998, 1999 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include <newlib.h>
+#include <sys/config.h>
+
+#ifdef _USE_GDTOA
+#include "gdtoaimp.h"
+
+ static Bigint *
+#ifdef KR_headers
+bitstob(ptr, bits, nbits, bbits) ULong *bits;
+struct _reent ptr, int nbits; int *bbits;
+#else
+bitstob(struct _reent *ptr, ULong *bits, int nbits, int *bbits)
+#endif
+{
+	int i, k;
+	Bigint *b;
+	ULong *be, *x, *x0;
+
+	i = ULbits;
+	k = 0;
+	while(i < nbits) {
+		i <<= 1;
+		k++;
+		}
+#ifndef Pack_32
+	if (!k)
+		k = 1;
+#endif
+	b = Balloc(ptr, k);
+	if (b == NULL)
+		return (NULL);
+	be = bits + ((nbits - 1) >> kshift);
+	x = x0 = b->_x;
+	do {
+		*x++ = *bits & ALL_ON;
+#ifdef Pack_16
+		*x++ = (*bits >> 16) & ALL_ON;
+#endif
+		} while(++bits <= be);
+	i = x - x0;
+	while(!x0[--i])
+		if (!i) {
+			b->_wds = 0;
+			*bbits = 0;
+			goto ret;
+			}
+	b->_wds = i + 1;
+	*bbits = i*ULbits + 32 - hi0bits(b->_x[i]);
+ ret:
+	return b;
+	}
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ *	1. Rather than iterating, we use a simple numeric overestimate
+ *	   to determine k = floor(log10(d)).  We scale relevant
+ *	   quantities using O(log2(k)) rather than O(k) multiplications.
+ *	2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ *	   try to generate digits strictly left to right.  Instead, we
+ *	   compute with fewer bits and propagate the carry if necessary
+ *	   when rounding the final digit up.  This is often faster.
+ *	3. Under the assumption that input will be rounded nearest,
+ *	   mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ *	   That is, we allow equality in stopping tests when the
+ *	   round-nearest rule will give the same floating-point value
+ *	   as would satisfaction of the stopping test with strict
+ *	   inequality.
+ *	4. We remove common factors of powers of 2 from relevant
+ *	   quantities.
+ *	5. When converting floating-point integers less than 1e16,
+ *	   we use floating-point arithmetic rather than resorting
+ *	   to multiple-precision integers.
+ *	6. When asked to produce fewer than 15 digits, we first try
+ *	   to get by with floating-point arithmetic; we resort to
+ *	   multiple-precision integer arithmetic only if we cannot
+ *	   guarantee that the floating-point calculation has given
+ *	   the correctly rounded result.  For k requested digits and
+ *	   "uniformly" distributed input, the probability is
+ *	   something like 10^(k-15) that we must resort to the Long
+ *	   calculation.
+ */
+
+ char *
+gdtoa
+#ifdef KR_headers
+	(ptr, fpi, be, bits, kindp, mode, ndigits, decpt, rve)
+	struct _reent *ptr, FPI *fpi; int be; ULong *bits;
+	int *kindp, mode, ndigits, *decpt; char **rve;
+#else
+	(struct _reent *ptr, FPI *fpi, int be, ULong *bits, int *kindp,
+	 int mode, int ndigits, int *decpt, char **rve)
+#endif
+{
+ /*	Arguments ndigits and decpt are similar to the second and third
+	arguments of ecvt and fcvt; trailing zeros are suppressed from
+	the returned string.  If not null, *rve is set to point
+	to the end of the return value.  If d is +-Infinity or NaN,
+	then *decpt is set to 9999.
+	be = exponent: value = (integer represented by bits) * (2 to the power of be).
+
+	mode:
+		0 ==> shortest string that yields d when read in
+			and rounded to nearest.
+		1 ==> like 0, but with Steele & White stopping rule;
+			e.g. with IEEE P754 arithmetic , mode 0 gives
+			1e23 whereas mode 1 gives 9.999999999999999e22.
+		2 ==> max(1,ndigits) significant digits.  This gives a
+			return value similar to that of ecvt, except
+			that trailing zeros are suppressed.
+		3 ==> through ndigits past the decimal point.  This
+			gives a return value similar to that from fcvt,
+			except that trailing zeros are suppressed, and
+			ndigits can be negative.
+		4-9 should give the same return values as 2-3, i.e.,
+			4 <= mode <= 9 ==> same return as mode
+			2 + (mode & 1).  These modes are mainly for
+			debugging; often they run slower but sometimes
+			faster than modes 2-3.
+		4,5,8,9 ==> left-to-right digit generation.
+		6-9 ==> don't try fast floating-point estimate
+			(if applicable).
+
+		Values of mode other than 0-9 are treated as mode 0.
+
+		Sufficient space is allocated to the return value
+		to hold the suppressed trailing zeros.
+	*/
+
+	int bbits, b2, b5, be0, dig, i, ieps, ilim, ilim0, ilim1, inex;
+	int j, j1, k, k0, k_check, kind, leftright, m2, m5, nbits;
+	int rdir, s2, s5, spec_case, try_quick;
+	Long L;
+	Bigint *b, *b1, *delta, *mlo, *mhi, *mhi1, *S;
+	double d2, ds;
+	char *s, *s0;
+	U d, eps;
+
+#ifndef MULTIPLE_THREADS
+	if (dtoa_result) {
+		freedtoa(ptr, dtoa_result);
+		dtoa_result = 0;
+		}
+#endif
+	inex = 0;
+	kind = *kindp &= ~STRTOG_Inexact;
+	switch(kind & STRTOG_Retmask) {
+	  case STRTOG_Zero:
+		goto ret_zero;
+	  case STRTOG_Normal:
+	  case STRTOG_Denormal:
+		break;
+	  case STRTOG_Infinite:
+		*decpt = -32768;
+		return nrv_alloc(ptr, "Infinity", rve, 8);
+	  case STRTOG_NaN:
+		*decpt = -32768;
+		return nrv_alloc(ptr, "NaN", rve, 3);
+	  default:
+		return 0;
+	  }
+	b = bitstob(ptr, bits, nbits = fpi->nbits, &bbits);
+	if (b == NULL)
+		return (NULL);
+	be0 = be;
+	if ( (i = trailz(b)) !=0) {
+		rshift(b, i);
+		be += i;
+		bbits -= i;
+		}
+	if (!b->_wds) {
+		Bfree(ptr, b);
+ ret_zero:
+		*decpt = 1;
+		return nrv_alloc(ptr, "0", rve, 1);
+		}
+
+	dval(d) = b2d(b, &i);
+	i = be + bbits - 1;
+	word0(d) &= Frac_mask1;
+	word0(d) |= Exp_11;
+#ifdef IBM
+	if ( (j = 11 - hi0bits(word0(d) & Frac_mask)) !=0)
+		dval(d) /= 1 << j;
+#endif
+
+	/* log(x)	~=~ log(1.5) + (x-1.5)/1.5
+	 * log10(x)	 =  log(x) / log(10)
+	 *		~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+	 * log10(&d) = (i-Bias)*log(2)/log(10) + log10(d2)
+	 *
+	 * This suggests computing an approximation k to log10(&d) by
+	 *
+	 * k = (i - Bias)*0.301029995663981
+	 *	+ ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+	 *
+	 * We want k to be too large rather than too small.
+	 * The error in the first-order Taylor series approximation
+	 * is in our favor, so we just round up the constant enough
+	 * to compensate for any error in the multiplication of
+	 * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+	 * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+	 * adding 1e-13 to the constant term more than suffices.
+	 * Hence we adjust the constant term to 0.1760912590558.
+	 * (We could get a more accurate k by invoking log10,
+	 *  but this is probably not worthwhile.)
+	 */
+#ifdef IBM
+	i <<= 2;
+	i += j;
+#endif
+	ds = (dval(d)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
+
+	/* correct assumption about exponent range */
+	if ((j = i) < 0)
+		j = -j;
+	if ((j -= 1077) > 0)
+		ds += j * 7e-17;
+
+	k = (int)ds;
+	if (ds < 0. && ds != k)
+		k--;	/* want k = floor(ds) */
+	k_check = 1;
+#ifdef IBM
+	j = be + bbits - 1;
+	if ( (j1 = j & 3) !=0)
+		dval(d) *= 1 << j1;
+	word0(d) += j << Exp_shift - 2 & Exp_mask;
+#else
+	word0(d) += (be + bbits - 1) << Exp_shift;
+#endif
+	if (k >= 0 && k <= Ten_pmax) {
+		if (dval(d) < tens[k])
+			k--;
+		k_check = 0;
+		}
+	j = bbits - i - 1;
+	if (j >= 0) {
+		b2 = 0;
+		s2 = j;
+		}
+	else {
+		b2 = -j;
+		s2 = 0;
+		}
+	if (k >= 0) {
+		b5 = 0;
+		s5 = k;
+		s2 += k;
+		}
+	else {
+		b2 -= k;
+		b5 = -k;
+		s5 = 0;
+		}
+	if (mode < 0 || mode > 9)
+		mode = 0;
+	try_quick = 1;
+	if (mode > 5) {
+		mode -= 4;
+		try_quick = 0;
+		}
+	else if (i >= -4 - Emin || i < Emin)
+		try_quick = 0;
+	leftright = 1;
+	ilim = ilim1 = -1;	/* Values for cases 0 and 1; done here to */
+				/* silence erroneous "gcc -Wall" warning. */
+	switch(mode) {
+		case 0:
+		case 1:
+			i = (int)(nbits * .30103) + 3;
+			ndigits = 0;
+			break;
+		case 2:
+			leftright = 0;
+			/* no break */
+		case 4:
+			if (ndigits <= 0)
+				ndigits = 1;
+			ilim = ilim1 = i = ndigits;
+			break;
+		case 3:
+			leftright = 0;
+			/* no break */
+		case 5:
+			i = ndigits + k + 1;
+			ilim = i;
+			ilim1 = i - 1;
+			if (i <= 0)
+				i = 1;
+		}
+	s = s0 = rv_alloc(ptr, i);
+	if (s == NULL)
+		return (NULL);
+
+	if ( (rdir = fpi->rounding - 1) !=0) {
+		if (rdir < 0)
+			rdir = 2;
+		if (kind & STRTOG_Neg)
+			rdir = 3 - rdir;
+		}
+
+	/* Now rdir = 0 ==> round near, 1 ==> round up, 2 ==> round down. */
+
+	if (ilim >= 0 && ilim <= Quick_max && try_quick && !rdir
+#ifndef IMPRECISE_INEXACT
+		&& k == 0
+#endif
+								) {
+
+		/* Try to get by with floating-point arithmetic. */
+
+		i = 0;
+		d2 = dval(d);
+#ifdef IBM
+		if ( (j = 11 - hi0bits(word0(d) & Frac_mask)) !=0)
+			dval(d) /= 1 << j;
+#endif
+		k0 = k;
+		ilim0 = ilim;
+		ieps = 2; /* conservative */
+		if (k > 0) {
+			ds = tens[k&0xf];
+			j = k >> 4;
+			if (j & Bletch) {
+				/* prevent overflows */
+				j &= Bletch - 1;
+				dval(d) /= bigtens[n_bigtens-1];
+				ieps++;
+				}
+			for(; j; j >>= 1, i++)
+				if (j & 1) {
+					ieps++;
+					ds *= bigtens[i];
+					}
+			}
+		else  {
+			ds = 1.;
+			if ( (j1 = -k) !=0) {
+				dval(d) *= tens[j1 & 0xf];
+				for(j = j1 >> 4; j; j >>= 1, i++)
+					if (j & 1) {
+						ieps++;
+						dval(d) *= bigtens[i];
+						}
+				}
+			}
+		if (k_check && dval(d) < 1. && ilim > 0) {
+			if (ilim1 <= 0)
+				goto fast_failed;
+			ilim = ilim1;
+			k--;
+			dval(d) *= 10.;
+			ieps++;
+			}
+		dval(eps) = ieps*dval(d) + 7.;
+		word0(eps) -= (P-1)*Exp_msk1;
+		if (ilim == 0) {
+			S = mhi = 0;
+			dval(d) -= 5.;
+			if (dval(d) > dval(eps))
+				goto one_digit;
+			if (dval(d) < -dval(eps))
+				goto no_digits;
+			goto fast_failed;
+			}
+#ifndef No_leftright
+		if (leftright) {
+			/* Use Steele & White method of only
+			 * generating digits needed.
+			 */
+			dval(eps) = ds*0.5/tens[ilim-1] - dval(eps);
+			for(i = 0;;) {
+				L = (Long)(dval(d)/ds);
+				dval(d) -= L*ds;
+				*s++ = '0' + (int)L;
+				if (dval(d) < dval(eps)) {
+					if (dval(d))
+						inex = STRTOG_Inexlo;
+					goto ret1;
+					}
+				if (ds - dval(d) < dval(eps))
+					goto bump_up;
+				if (++i >= ilim)
+					break;
+				dval(eps) *= 10.;
+				dval(d) *= 10.;
+				}
+			}
+		else {
+#endif
+			/* Generate ilim digits, then fix them up. */
+			dval(eps) *= tens[ilim-1];
+			for(i = 1;; i++, dval(d) *= 10.) {
+				if ( (L = (Long)(dval(d)/ds)) !=0)
+					dval(d) -= L*ds;
+				*s++ = '0' + (int)L;
+				if (i == ilim) {
+					ds *= 0.5;
+					if (dval(d) > ds + dval(eps))
+						goto bump_up;
+					else if (dval(d) < ds - dval(eps)) {
+						if (dval(d))
+							inex = STRTOG_Inexlo;
+						goto clear_trailing0;
+						}
+					break;
+					}
+				}
+#ifndef No_leftright
+			}
+#endif
+ fast_failed:
+		s = s0;
+		dval(d) = d2;
+		k = k0;
+		ilim = ilim0;
+		}
+
+	/* Do we have a "small" integer? */
+
+	if (be >= 0 && k <= Int_max) {
+		/* Yes. */
+		ds = tens[k];
+		if (ndigits < 0 && ilim <= 0) {
+			S = mhi = 0;
+			if (ilim < 0 || dval(d) <= 5*ds)
+				goto no_digits;
+			goto one_digit;
+			}
+		for(i = 1;; i++, dval(d) *= 10.) {
+			L = dval(d) / ds;
+			dval(d) -= L*ds;
+#ifdef Check_FLT_ROUNDS
+			/* If FLT_ROUNDS == 2, L will usually be high by 1 */
+			if (dval(d) < 0) {
+				L--;
+				dval(d) += ds;
+				}
+#endif
+			*s++ = '0' + (int)L;
+			if (dval(d) == 0.)
+				break;
+			if (i == ilim) {
+				if (rdir) {
+					if (rdir == 1)
+						goto bump_up;
+					inex = STRTOG_Inexlo;
+					goto ret1;
+					}
+				dval(d) += dval(d);
+#ifdef ROUND_BIASED
+				if (dval(d) >= ds)
+#else
+				if (dval(d) > ds || (dval(d) == ds && L & 1))
+#endif
+					{
+ bump_up:
+					inex = STRTOG_Inexhi;
+					while(*--s == '9')
+						if (s == s0) {
+							k++;
+							*s = '0';
+							break;
+							}
+					++*s++;
+					}
+				else {
+					inex = STRTOG_Inexlo;
+ clear_trailing0:
+					while(*--s == '0'){}
+					++s;
+					}
+				break;
+				}
+			}
+		goto ret1;
+		}
+
+	m2 = b2;
+	m5 = b5;
+	mhi = mlo = 0;
+	if (leftright) {
+		i = nbits - bbits;
+		if (be - i++ < fpi->emin && mode != 3 && mode != 5) {
+			/* denormal */
+			i = be - fpi->emin + 1;
+			if (mode >= 2 && ilim > 0 && ilim < i)
+				goto small_ilim;
+			}
+		else if (mode >= 2) {
+ small_ilim:
+			j = ilim - 1;
+			if (m5 >= j)
+				m5 -= j;
+			else {
+				s5 += j -= m5;
+				b5 += j;
+				m5 = 0;
+				}
+			if ((i = ilim) < 0) {
+				m2 -= i;
+				i = 0;
+				}
+			}
+		b2 += i;
+		s2 += i;
+		mhi = i2b(ptr, 1);
+		if (mhi == NULL)
+			return (NULL);
+		}
+	if (m2 > 0 && s2 > 0) {
+		i = m2 < s2 ? m2 : s2;
+		b2 -= i;
+		m2 -= i;
+		s2 -= i;
+		}
+	if (b5 > 0) {
+		if (leftright) {
+			if (m5 > 0) {
+				mhi = pow5mult(ptr, mhi, m5);
+				if (mhi == NULL)
+					return (NULL);
+				b1 = mult(ptr, mhi, b);
+				if (b1 == NULL)
+					return (NULL);
+				Bfree(ptr, b);
+				b = b1;
+				}
+			if ( (j = b5 - m5) !=0) {
+				b = pow5mult(ptr, b, j);
+				if (b == NULL)
+					return (NULL);
+				}
+			}
+		else {
+			b = pow5mult(ptr, b, b5);
+			if (b == NULL)
+				return (NULL);
+			}
+		}
+	S = i2b(ptr, 1);
+	if (S == NULL)
+		return (NULL);
+	if (s5 > 0) {
+		S = pow5mult(ptr, S, s5);
+		if (S == NULL)
+			return (NULL);
+		}
+
+	/* Check for special case that d is a normalized power of 2. */
+
+	spec_case = 0;
+	if (mode < 2) {
+		if (bbits == 1 && be0 > fpi->emin + 1) {
+			/* The special case */
+			b2++;
+			s2++;
+			spec_case = 1;
+			}
+		}
+
+	/* Arrange for convenient computation of quotients:
+	 * shift left if necessary so divisor has 4 leading 0 bits.
+	 *
+	 * Perhaps we should just compute leading 28 bits of S once
+	 * and for all and pass them and a shift to quorem, so it
+	 * can do shifts and ors to compute the numerator for q.
+	 */
+	i = ((s5 ? hi0bits(S->_x[S->_wds-1]) : ULbits - 1) - s2 - 4) & kmask;
+	m2 += i;
+	if ((b2 += i) > 0) {
+		b = lshift(ptr, b, b2);
+		if (b == NULL)
+			return (NULL);
+		}
+	if ((s2 += i) > 0) {
+		S = lshift(ptr, S, s2);
+		if (S == NULL)
+			return (NULL);
+		}
+	if (k_check) {
+		if (cmp(b,S) < 0) {
+			k--;
+			b = multadd(ptr, b, 10, 0); /* we botched the k estimate */
+			if (b == NULL)
+				return (NULL);
+			if (leftright) {
+				mhi = multadd(ptr, mhi, 10, 0);
+				if (mhi == NULL)
+					return (NULL);
+				}
+			ilim = ilim1;
+			}
+		}
+	if (ilim <= 0 && mode > 2) {
+		S = multadd(ptr, S,5,0);
+		if (S == NULL)
+			return (NULL);
+		if (ilim < 0 || cmp(b,S) <= 0) {
+			/* no digits, fcvt style */
+ no_digits:
+			k = -1 - ndigits;
+			inex = STRTOG_Inexlo;
+			goto ret;
+			}
+ one_digit:
+		inex = STRTOG_Inexhi;
+		*s++ = '1';
+		k++;
+		goto ret;
+		}
+	if (leftright) {
+		if (m2 > 0) {
+			mhi = lshift(ptr, mhi, m2);
+			if (mhi == NULL)
+				return (NULL);
+			}
+
+		/* Compute mlo -- check for special case
+		 * that d is a normalized power of 2.
+		 */
+
+		mlo = mhi;
+		if (spec_case) {
+			mhi = Balloc(ptr, mhi->_k);
+			if (mhi == NULL)
+				return (NULL);
+			Bcopy(mhi, mlo);
+			mhi = lshift(ptr, mhi, 1);
+			if (mhi == NULL)
+				return (NULL);
+			}
+
+		for(i = 1;;i++) {
+			dig = quorem(b,S) + '0';
+			/* Do we yet have the shortest decimal string
+			 * that will round to d?
+			 */
+			j = cmp(b, mlo);
+			delta = diff(ptr, S, mhi);
+			if (delta == NULL)
+				return (NULL);
+			j1 = delta->_sign ? 1 : cmp(b, delta);
+			Bfree(ptr, delta);
+#ifndef ROUND_BIASED
+			if (j1 == 0 && !mode && !(bits[0] & 1) && !rdir) {
+				if (dig == '9')
+					goto round_9_up;
+				if (j <= 0) {
+					if (b->_wds > 1 || b->_x[0])
+						inex = STRTOG_Inexlo;
+					}
+				else {
+					dig++;
+					inex = STRTOG_Inexhi;
+					}
+				*s++ = dig;
+				goto ret;
+				}
+#endif
+			if (j < 0 || (j == 0 && !mode
+#ifndef ROUND_BIASED
+							&& !(bits[0] & 1)
+#endif
+					)) {
+				if (rdir && (b->_wds > 1 || b->_x[0])) {
+					if (rdir == 2) {
+						inex = STRTOG_Inexlo;
+						goto accept;
+						}
+					while (cmp(S,mhi) > 0) {
+						*s++ = dig;
+						mhi1 = multadd(ptr, mhi, 10, 0);
+						if (mhi1 == NULL)
+							return (NULL);
+						if (mlo == mhi)
+							mlo = mhi1;
+						mhi = mhi1;
+						b = multadd(ptr, b, 10, 0);
+						if (b == NULL)
+							return (NULL);
+						dig = quorem(b,S) + '0';
+						}
+					if (dig++ == '9')
+						goto round_9_up;
+					inex = STRTOG_Inexhi;
+					goto accept;
+					}
+				if (j1 > 0) {
+					b = lshift(ptr, b, 1);
+					if (b == NULL)
+						return (NULL);
+					j1 = cmp(b, S);
+#ifdef ROUND_BIASED
+					if (j1 >= 0 /*)*/
+#else
+					if ((j1 > 0 || (j1 == 0 && dig & 1))
+#endif
+					&& dig++ == '9')
+						goto round_9_up;
+					inex = STRTOG_Inexhi;
+					}
+				if (b->_wds > 1 || b->_x[0])
+					inex = STRTOG_Inexlo;
+ accept:
+				*s++ = dig;
+				goto ret;
+				}
+			if (j1 > 0 && rdir != 2) {
+				if (dig == '9') { /* possible if i == 1 */
+ round_9_up:
+					*s++ = '9';
+					inex = STRTOG_Inexhi;
+					goto roundoff;
+					}
+				inex = STRTOG_Inexhi;
+				*s++ = dig + 1;
+				goto ret;
+				}
+			*s++ = dig;
+			if (i == ilim)
+				break;
+			b = multadd(ptr, b, 10, 0);
+			if (b == NULL)
+				return (NULL);
+			if (mlo == mhi) {
+				mlo = mhi = multadd(ptr, mhi, 10, 0);
+				if (mlo == NULL)
+					return (NULL);
+				}
+			else {
+				mlo = multadd(ptr, mlo, 10, 0);
+				if (mlo == NULL)
+					return (NULL);
+				mhi = multadd(ptr, mhi, 10, 0);
+				if (mhi == NULL)
+					return (NULL);
+				}
+			}
+		}
+	else
+		for(i = 1;; i++) {
+			*s++ = dig = quorem(b,S) + '0';
+			if (i >= ilim)
+				break;
+			b = multadd(ptr, b, 10, 0);
+			if (b == NULL)
+				return (NULL);
+			}
+
+	/* Round off last digit */
+
+	if (rdir) {
+		if (rdir == 2 || (b->_wds <= 1 && !b->_x[0]))
+			goto chopzeros;
+		goto roundoff;
+		}
+	b = lshift(ptr, b, 1);
+	if (b == NULL)
+		return (NULL);
+	j = cmp(b, S);
+#ifdef ROUND_BIASED
+	if (j >= 0)
+#else
+	if (j > 0 || (j == 0 && dig & 1))
+#endif
+		{
+ roundoff:
+		inex = STRTOG_Inexhi;
+		while(*--s == '9')
+			if (s == s0) {
+				k++;
+				*s++ = '1';
+				goto ret;
+				}
+		++*s++;
+		}
+	else {
+ chopzeros:
+		if (b->_wds > 1 || b->_x[0])
+			inex = STRTOG_Inexlo;
+		while(*--s == '0'){}
+		++s;
+		}
+ ret:
+	Bfree(ptr, S);
+	if (mhi) {
+		if (mlo && mlo != mhi)
+			Bfree(ptr, mlo);
+		Bfree(ptr, mhi);
+		}
+ ret1:
+	Bfree(ptr, b);
+	*s = 0;
+	*decpt = k + 1;
+	if (rve)
+		*rve = s;
+	*kindp |= inex;
+	return s0;
+	}
+DEF_STRONG(gdtoa);
+#endif /* _USE_GDTOA */
diff --git a/newlib/libc/stdlib/gdtoa-gmisc.c b/newlib/libc/stdlib/gdtoa-gmisc.c
new file mode 100644
index 000000000..40c3c2d13
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-gmisc.c
@@ -0,0 +1,91 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include <newlib.h>
+#include <sys/config.h>
+
+#ifdef _USE_GDTOA
+#include "gdtoaimp.h"
+
+ void
+#ifdef KR_headers
+rshift(b, k) Bigint *b; int k;
+#else
+rshift(Bigint *b, int k)
+#endif
+{
+	ULong *x, *x1, *xe, y;
+	int n;
+
+	x = x1 = b->_x;
+	n = k >> kshift;
+	if (n < b->_wds) {
+		xe = x + b->_wds;
+		x += n;
+		if (k &= kmask) {
+			n = ULbits - k;
+			y = *x++ >> k;
+			while(x < xe) {
+				*x1++ = (y | (*x << n)) & ALL_ON;
+				y = *x++ >> k;
+				}
+			if ((*x1 = y) !=0)
+				x1++;
+			}
+		else
+			while(x < xe)
+				*x1++ = *x++;
+		}
+	if ((b->_wds = x1 - b->_x) == 0)
+		b->_x[0] = 0;
+	}
+
+ int
+#ifdef KR_headers
+trailz(b) Bigint *b;
+#else
+trailz(Bigint *b)
+#endif
+{
+	ULong L, *x, *xe;
+	int n = 0;
+
+	x = b->_x;
+	xe = x + b->_wds;
+	for(n = 0; x < xe && !*x; x++)
+		n += ULbits;
+	if (x < xe) {
+		L = *x;
+		n += lo0bits(&L);
+		}
+	return n;
+	}
+#endif /* _USE_GDTOA */
diff --git a/newlib/libc/stdlib/gdtoa-ldtoa.c b/newlib/libc/stdlib/gdtoa-ldtoa.c
new file mode 100644
index 000000000..7957f4c16
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-ldtoa.c
@@ -0,0 +1,159 @@
+/*	$OpenBSD: ldtoa.c,v 1.4 2016/03/09 16:28:47 deraadt Exp $	*/
+/*-
+ * Copyright (c) 2003 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <newlib.h>
+#include <sys/config.h>
+
+#ifdef _USE_GDTOA
+#include <sys/types.h>
+#include <machine/ieee.h>
+#include <float.h>
+#include <stdint.h>
+#include <limits.h>
+#include <math.h>
+#include <stdlib.h>
+#include "gdtoaimp.h"
+
+#if (LDBL_MANT_DIG > DBL_MANT_DIG)
+
+/*
+ * ldtoa() is a wrapper for gdtoa() that makes it smell like dtoa(),
+ * except that the floating point argument is passed by reference.
+ * When dtoa() is passed a NaN or infinity, it sets expt to 9999.
+ * However, a long double could have a valid exponent of 9999, so we
+ * use INT_MAX in ldtoa() instead.
+ */
+char *
+_ldtoa_r(struct _reent *ptr,
+    long double ld, int mode, int ndigits, int *decpt, int *sign, char **rve)
+{
+	FPI fpi = {
+		LDBL_MANT_DIG,			/* nbits */
+		LDBL_MIN_EXP - LDBL_MANT_DIG,	/* emin */
+		LDBL_MAX_EXP - LDBL_MANT_DIG,	/* emax */
+		FLT_ROUNDS,	       		/* rounding */
+#ifdef Sudden_Underflow	/* unused, but correct anyway */
+		1
+#else
+		0
+#endif
+	};
+	int be, kind;
+	char *ret;
+	struct ieee_ext *p = (struct ieee_ext *)&ld;
+	uint32_t bits[(LDBL_MANT_DIG + 31) / 32];
+	void *vbits = bits;
+
+	_REENT_CHECK_MP (ptr);
+
+	/* reentrancy addition to use mprec storage pool */
+	if (_REENT_MP_RESULT (ptr)) {
+		_REENT_MP_RESULT (ptr)->_k = _REENT_MP_RESULT_K (ptr);
+		_REENT_MP_RESULT (ptr)->_maxwds = 1 << _REENT_MP_RESULT_K (ptr);
+		Bfree (ptr, _REENT_MP_RESULT (ptr));
+		_REENT_MP_RESULT (ptr) = 0;
+	}
+
+	/*
+	 * gdtoa doesn't know anything about the sign of the number, so
+	 * if the number is negative, we need to swap rounding modes of
+	 * 2 (upwards) and 3 (downwards).
+	 */
+	*sign = p->ext_sign;
+	fpi.rounding ^= (fpi.rounding >> 1) & p->ext_sign;
+
+	be = p->ext_exp - (LDBL_MAX_EXP - 1) - (LDBL_MANT_DIG - 1);
+	EXT_TO_ARRAY32(p, bits);
+
+	switch (fpclassify(ld)) {
+	case FP_NORMAL:
+		kind = STRTOG_Normal;
+#ifdef EXT_IMPLICIT_NBIT
+		bits[LDBL_MANT_DIG / 32] |= 1 << ((LDBL_MANT_DIG - 1) % 32);
+#endif /* EXT_IMPLICIT_NBIT */
+		break;
+	case FP_ZERO:
+		kind = STRTOG_Zero;
+		break;
+	case FP_SUBNORMAL:
+		kind = STRTOG_Denormal;
+		be++;
+		break;
+	case FP_INFINITE:
+		kind = STRTOG_Infinite;
+		break;
+	case FP_NAN:
+		kind = STRTOG_NaN;
+		break;
+	default:
+		abort();
+	}
+
+	ret = gdtoa(ptr, &fpi, be, vbits, &kind, mode, ndigits, decpt, rve);
+	if (*decpt == -32768)
+		*decpt = INT_MAX;
+	return ret;
+}
+DEF_STRONG(_ldtoa_r);
+
+#else   /* (LDBL_MANT_DIG == DBL_MANT_DIG) */
+
+char *
+_ldtoa_r(struct _reent *ptr,
+    long double ld, int mode, int ndigits, int *decpt, int *sign,
+    char **rve)
+{
+	char *ret;
+
+	ret = dtoa(ptr, (double)ld, mode, ndigits, decpt, sign, rve);
+	if (*decpt == 9999)
+		*decpt = INT_MAX;
+	return ret;
+}
+DEF_STRONG(_ldtoa_r);
+
+#endif  /* (LDBL_MANT_DIG == DBL_MANT_DIG) */
+
+/* Routine used to tell if long double is NaN or Infinity or regular number.
+   Returns:  0 = regular number
+             1 = Nan
+             2 = Infinity
+*/
+int
+_ldcheck (long double *d)
+{
+	switch (fpclassify(*d)) {
+	case FP_NAN:
+		return 1;
+	case FP_INFINITE:
+		return 2;
+	default:
+		return 0;
+	}
+}
+
+#endif /* _USE_GDTOA */
diff --git a/newlib/libc/stdlib/gdtoa.h b/newlib/libc/stdlib/gdtoa.h
index 07506aac1..f4d2a56db 100644
--- a/newlib/libc/stdlib/gdtoa.h
+++ b/newlib/libc/stdlib/gdtoa.h
@@ -32,25 +32,55 @@ THIS SOFTWARE.
 #ifndef GDTOA_H_INCLUDED
 #define GDTOA_H_INCLUDED
 
+#include <stddef.h> /* for size_t */
+#include <reent.h>
+
+#define PROTO_NORMAL(x)
+#define __BEGIN_HIDDEN_DECLS
+#define __END_HIDDEN_DECLS
+#define DEF_STRONG(x)
+
+#ifndef ULong
+#define ULong __ULong
+#endif
+
+#ifndef ANSI
+#ifdef KR_headers
+#define ANSI(x) ()
+#define Void /*nothing*/
+#else
+#define ANSI(x) x
+#define Void void
+#endif
+#endif /* ANSI */
+
+#ifndef CONST
+#ifdef KR_headers
+#define CONST /* blank */
+#else
+#define CONST const
+#endif
+#endif /* CONST */
 
  enum {	/* return values from strtodg */
-	STRTOG_Zero	= 0,
-	STRTOG_Normal	= 1,
-	STRTOG_Denormal	= 2,
-	STRTOG_Infinite	= 3,
-	STRTOG_NaN	= 4,
-	STRTOG_NaNbits	= 5,
-	STRTOG_NoNumber	= 6,
-	STRTOG_Retmask	= 7,
+	STRTOG_Zero	= 0x000,
+	STRTOG_Normal	= 0x001,
+	STRTOG_Denormal	= 0x002,
+	STRTOG_Infinite	= 0x003,
+	STRTOG_NaN	= 0x004,
+	STRTOG_NaNbits	= 0x005,
+	STRTOG_NoNumber	= 0x006,
+	STRTOG_NoMemory = 0x007,
+	STRTOG_Retmask	= 0x00f,
 
 	/* The following may be or-ed into one of the above values. */
 
-	STRTOG_Neg	= 0x08,
-	STRTOG_Inexlo	= 0x10,
-	STRTOG_Inexhi	= 0x20,
-	STRTOG_Inexact	= 0x30,
-	STRTOG_Underflow= 0x40,
-	STRTOG_Overflow	= 0x80
+	STRTOG_Inexlo	= 0x010, /* returned result rounded toward zero */
+	STRTOG_Inexhi	= 0x020, /* returned result rounded away from zero */
+	STRTOG_Inexact	= 0x030,
+	STRTOG_Underflow= 0x040,
+	STRTOG_Overflow	= 0x080,
+	STRTOG_Neg	= 0x100 /* does not affect STRTOG_Inexlo or STRTOG_Inexhi */
 	};
 
  typedef struct
@@ -69,6 +99,74 @@ enum {	/* FPI.rounding values: same as FLT_ROUNDS */
 	FPI_Round_down = 3
 	};
 
-#endif /* GDTOA_H_INCLUDED */
-
 typedef unsigned short __UShort;
+typedef struct _Bigint Bigint;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char* __dtoa  ANSI((struct _reent *ptr,
+			double d, int mode, int ndigits, int *decpt,
+			int *sign, char **rve));
+extern char* __gdtoa ANSI((struct _reent *ptr,
+			FPI *fpi, int be, ULong *bits, int *kindp,
+			int mode, int ndigits, int *decpt, char **rve));
+extern void __freedtoa ANSI((struct _reent *, char*));
+extern float  strtof ANSI((CONST char *, char **));
+extern double strtod ANSI((CONST char *, char **));
+extern int __strtodg ANSI((CONST char*, char**, FPI*, Long*, ULong*));
+char	*__hdtoa(double, const char *, int, int *, int *, char **);
+char	*__hldtoa(long double, const char *, int, int *, int *, char **);
+char	*__ldtoa(struct _reent *ptr,
+		 long double *, int, int, int *, int *, char **);
+
+PROTO_NORMAL(__dtoa);
+PROTO_NORMAL(__gdtoa);
+PROTO_NORMAL(__freedtoa);
+PROTO_NORMAL(__hdtoa);
+PROTO_NORMAL(__hldtoa);
+PROTO_NORMAL(__ldtoa);
+
+__BEGIN_HIDDEN_DECLS
+extern char*	__g_ddfmt  ANSI((char*, double*, int, size_t));
+extern char*	__g_dfmt   ANSI((char*, double*, int, size_t));
+extern char*	__g_ffmt   ANSI((char*, float*,  int, size_t));
+extern char*	__g_Qfmt   ANSI((char*, void*,   int, size_t));
+extern char*	__g_xfmt   ANSI((char*, void*,   int, size_t));
+extern char*	__g_xLfmt  ANSI((char*, void*,   int, size_t));
+
+extern int	__strtoId  ANSI((CONST char*, char**, double*, double*));
+extern int	__strtoIdd ANSI((CONST char*, char**, double*, double*));
+extern int	__strtoIf  ANSI((CONST char*, char**, float*, float*));
+extern int	__strtoIQ  ANSI((CONST char*, char**, void*, void*));
+extern int	__strtoIx  ANSI((CONST char*, char**, void*, void*));
+extern int	__strtoIxL ANSI((CONST char*, char**, void*, void*));
+extern int	__strtord  ANSI((CONST char*, char**, int, double*));
+extern int	__strtordd ANSI((CONST char*, char**, int, double*));
+extern int	__strtorf  ANSI((CONST char*, char**, int, float*));
+extern int	__strtorQ  ANSI((CONST char*, char**, int, void*));
+extern int	__strtorx  ANSI((CONST char*, char**, int, void*));
+extern int	__strtorxL ANSI((CONST char*, char**, int, void*));
+#if 1
+extern int	__strtodI  ANSI((CONST char*, char**, double*));
+extern int	__strtopd  ANSI((CONST char*, char**, double*));
+extern int	__strtopdd ANSI((CONST char*, char**, double*));
+extern int	__strtopf  ANSI((CONST char*, char**, float*));
+extern int	__strtopQ  ANSI((CONST char*, char**, void*));
+extern int	__strtopx  ANSI((CONST char*, char**, void*));
+extern int	__strtopxL ANSI((CONST char*, char**, void*));
+#else
+#define __strtopd(s,se,x) strtord(s,se,1,x)
+#define __strtopdd(s,se,x) strtordd(s,se,1,x)
+#define __strtopf(s,se,x) strtorf(s,se,1,x)
+#define __strtopQ(s,se,x) strtorQ(s,se,1,x)
+#define __strtopx(s,se,x) strtorx(s,se,1,x)
+#define __strtopxL(s,se,x) strtorxL(s,se,1,x)
+#endif
+__END_HIDDEN_DECLS
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* GDTOA_H_INCLUDED */
diff --git a/newlib/libc/stdlib/gdtoaimp.h b/newlib/libc/stdlib/gdtoaimp.h
new file mode 100644
index 000000000..f2da3fc67
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoaimp.h
@@ -0,0 +1,206 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998-2000 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* This is a variation on dtoa.c that converts arbitary binary
+   floating-point formats to and from decimal notation.  It uses
+   double-precision arithmetic internally, so there are still
+   various #ifdefs that adapt the calculations to the native
+   double-precision arithmetic (any of IEEE, VAX D_floating,
+   or IBM mainframe arithmetic).
+
+   Please send bug reports to David M. Gay (dmg at acm dot org,
+   with " at " changed at "@" and " dot " changed to ".").
+ */
+
+/* On a machine with IEEE extended-precision registers, it is
+ * necessary to specify double-precision (53-bit) rounding precision
+ * before invoking strtod or dtoa.  If the machine uses (the equivalent
+ * of) Intel 80x87 arithmetic, the call
+ *	_control87(PC_53, MCW_PC);
+ * does this with many compilers.  Whether this or another call is
+ * appropriate depends on the compiler; for this to work, it may be
+ * necessary to #include "float.h" or another system-dependent header
+ * file.
+ */
+
+/* strtod for IEEE-, VAX-, and IBM-arithmetic machines.
+ *
+ * This strtod returns a nearest machine number to the input decimal
+ * string (or sets errno to ERANGE).  With IEEE arithmetic, ties are
+ * broken by the IEEE round-even rule.  Otherwise ties are broken by
+ * biased rounding (add half and chop).
+ *
+ * Inspired loosely by William D. Clinger's paper "How to Read Floating
+ * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ *
+ *	1. We only require IEEE, IBM, or VAX double-precision
+ *		arithmetic (not IEEE double-extended).
+ *	2. We get by with floating-point arithmetic in a case that
+ *		Clinger missed -- when we're computing d * 10^n
+ *		for a small integer d and the integer n is not too
+ *		much larger than 22 (the maximum integer k for which
+ *		we can represent 10^k exactly), we may be able to
+ *		compute (d*10^k) * 10^(e-k) with just one roundoff.
+ *	3. Rather than a bit-at-a-time adjustment of the binary
+ *		result in the hard case, we use floating-point
+ *		arithmetic to determine the adjustment to within
+ *		one bit; only in really hard cases do we need to
+ *		compute a second residual.
+ *	4. Because of 3., we don't need a large table of powers of 10
+ *		for ten-to-e (just some small tables, e.g. of 10^k
+ *		for 0 <= k <= 22).
+ */
+
+/*
+ * #define IEEE_8087 for IEEE-arithmetic machines where the least
+ *	significant byte has the lowest address.
+ * #define IEEE_MC68k for IEEE-arithmetic machines where the most
+ *	significant byte has the lowest address.
+ * #define Long int on machines with 32-bit ints and 64-bit longs.
+ * #define Sudden_Underflow for IEEE-format machines without gradual
+ *	underflow (i.e., that flush to zero on underflow).
+ * #define IBM for IBM mainframe-style floating-point arithmetic.
+ * #define VAX for VAX-style floating-point arithmetic (D_floating).
+ * #define No_leftright to omit left-right logic in fast floating-point
+ *	computation of dtoa and gdtoa.  This will cause modes 4 and 5 to be
+ *	treated the same as modes 2 and 3 for some inputs.
+ * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3.
+ * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines
+ *	that use extended-precision instructions to compute rounded
+ *	products and quotients) with IBM.
+ * #define ROUND_BIASED for IEEE-format with biased rounding and arithmetic
+ *	that rounds toward +Infinity.
+ * #define ROUND_BIASED_without_Round_Up for IEEE-format with biased
+ *	rounding when the underlying floating-point arithmetic uses
+ *	unbiased rounding.  This prevent using ordinary floating-point
+ *	arithmetic when the result could be computed with one rounding error.
+ * #define Inaccurate_Divide for IEEE-format with correctly rounded
+ *	products but inaccurate quotients, e.g., for Intel i860.
+ * #define NO_LONG_LONG on machines that do not have a "long long"
+ *	integer type (of >= 64 bits).  On such machines, you can
+ *	#define Just_16 to store 16 bits per 32-bit Long when doing
+ *	high-precision integer arithmetic.  Whether this speeds things
+ *	up or slows things down depends on the machine and the number
+ *	being converted.  If long long is available and the name is
+ *	something other than "long long", #define Llong to be the name,
+ *	and if "unsigned Llong" does not work as an unsigned version of
+ *	Llong, #define #ULLong to be the corresponding unsigned type.
+ * #define KR_headers for old-style C function headers.
+ * #define Bad_float_h if your system lacks a float.h or if it does not
+ *	define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP,
+ *	FLT_RADIX, FLT_ROUNDS, and DBL_MAX.
+ * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n)
+ *	if memory is available and otherwise does something you deem
+ *	appropriate.  If MALLOC is undefined, malloc will be invoked
+ *	directly -- and assumed always to succeed.  Similarly, if you
+ *	want something other than the system's free() to be called to
+ *	recycle memory acquired from MALLOC, #define FREE to be the
+ *	name of the alternate routine.  (FREE or free is only called in
+ *	pathological cases, e.g., in a gdtoa call after a gdtoa return in
+ *	mode 3 with thousands of digits requested.)
+ * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making
+ *	memory allocations from a private pool of memory when possible.
+ *	When used, the private pool is PRIVATE_MEM bytes long:  2304 bytes,
+ *	unless #defined to be a different length.  This default length
+ *	suffices to get rid of MALLOC calls except for unusual cases,
+ *	such as decimal-to-binary conversion of a very long string of
+ *	digits.  When converting IEEE double precision values, the
+ *	longest string gdtoa can return is about 751 bytes long.  For
+ *	conversions by strtod of strings of 800 digits and all gdtoa
+ *	conversions of IEEE doubles in single-threaded executions with
+ *	8-byte pointers, PRIVATE_MEM >= 7400 appears to suffice; with
+ *	4-byte pointers, PRIVATE_MEM >= 7112 appears adequate.
+ * #define NO_INFNAN_CHECK if you do not wish to have INFNAN_CHECK
+ *	#defined automatically on IEEE systems.  On such systems,
+ *	when INFNAN_CHECK is #defined, strtod checks
+ *	for Infinity and NaN (case insensitively).
+ *	When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined,
+ *	strtodg also accepts (case insensitively) strings of the form
+ *	NaN(x), where x is a string of hexadecimal digits (optionally
+ *	preceded by 0x or 0X) and spaces; if there is only one string
+ *	of hexadecimal digits, it is taken for the fraction bits of the
+ *	resulting NaN; if there are two or more strings of hexadecimal
+ *	digits, each string is assigned to the next available sequence
+ *	of 32-bit words of fractions bits (starting with the most
+ *	significant), right-aligned in each sequence.
+ *	Unless GDTOA_NON_PEDANTIC_NANCHECK is #defined, input "NaN(...)"
+ *	is consumed even when ... has the wrong form (in which case the
+ *	"(...)" is consumed but ignored).
+ * #define MULTIPLE_THREADS if the system offers preemptively scheduled
+ *	multiple threads.  In this case, you must provide (or suitably
+ *	#define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed
+ *	by FREE_DTOA_LOCK(n) for n = 0 or 1.  (The second lock, accessed
+ *	in pow5mult, ensures lazy evaluation of only one copy of high
+ *	powers of 5; omitting this lock would introduce a small
+ *	probability of wasting memory, but would otherwise be harmless.)
+ *	You must also invoke freedtoa(s) to free the value s returned by
+ *	dtoa.  You may do so whether or not MULTIPLE_THREADS is #defined.
+ * #define IMPRECISE_INEXACT if you do not care about the setting of
+ *	the STRTOG_Inexact bits in the special case of doing IEEE double
+ *	precision conversions (which could also be done by the strtod in
+ *	dtoa.c).
+ * #define NO_HEX_FP to disable recognition of C9x's hexadecimal
+ *	floating-point constants.
+ * #define -DNO_ERRNO to suppress setting errno (in strtod.c and
+ *	strtodg.c).
+ * #define NO_STRING_H to use private versions of memcpy.
+ *	On some K&R systems, it may also be necessary to
+ *	#define DECLARE_SIZE_T in this case.
+ * #define USE_LOCALE to use the current locale's decimal_point value.
+ */
+
+#ifndef GDTOAIMP_H_INCLUDED
+#define GDTOAIMP_H_INCLUDED
+#include "mprec.h"
+#include "gdtoa.h"
+
+#ifndef __SINGLE_THREAD__
+#define MULTIPLE_THREADS
+#endif
+
+#define dtoa __dtoa
+#define gdtoa __gdtoa
+#define freedtoa __freedtoa
+
+#define dtoa_result __dtoa_result_D2A
+#define nrv_alloc __nrv_alloc_D2A
+#define quorem __quorem_D2A
+#define rshift __rshift_D2A
+#define rv_alloc __rv_alloc_D2A
+#define trailz __trailz_D2A
+
+extern char *dtoa_result;
+extern char *nrv_alloc ANSI((struct _reent *, char*, char **, int));
+extern int quorem ANSI((Bigint*, Bigint*));
+extern void rshift ANSI((Bigint*, int));
+extern char *rv_alloc ANSI((struct _reent *, int));
+extern int trailz ANSI((Bigint*));
+
+#endif /* GDTOAIMP_H_INCLUDED */
diff --git a/newlib/libc/stdlib/ldtoa.c b/newlib/libc/stdlib/ldtoa.c
index 26c61948b..36613faad 100644
--- a/newlib/libc/stdlib/ldtoa.c
+++ b/newlib/libc/stdlib/ldtoa.c
@@ -2,6 +2,10 @@
   * This program has been placed in the public domain.
   */
 
+#include <newlib.h>
+#include <sys/config.h>
+
+#ifndef _USE_GDTOA
 #include <_ansi.h>
 #include <reent.h>
 #include <string.h>
@@ -3900,3 +3904,5 @@ enan (short unsigned int *nan, int size)
   for (i = 0; i < n; i++)
     *nan++ = *p++;
 }
+
+#endif /* !_USE_GDTOA */
diff --git a/newlib/libc/stdlib/mprec.h b/newlib/libc/stdlib/mprec.h
index a1492aa38..83de932c2 100644
--- a/newlib/libc/stdlib/mprec.h
+++ b/newlib/libc/stdlib/mprec.h
@@ -26,7 +26,7 @@
 	dmg@research.att.com or research!dmg
  */
 
-#include <ieeefp.h>
+#include <machine/ieeefp.h>
 #include <math.h>
 #include <float.h>
 #include <errno.h>
diff --git a/newlib/newlib.hin b/newlib/newlib.hin
index 416d0c629..a0999512c 100644
--- a/newlib/newlib.hin
+++ b/newlib/newlib.hin
@@ -96,6 +96,9 @@
 /* Define to use type long for time_t.  */
 #undef _WANT_USE_LONG_TIME_T
 
+/* Define if using gdtoa rather than legacy ldtoa.  */
+#undef _WANT_USE_GDTOA
+
 /*
  * Iconv encodings enabled ("to" direction)
  */
-- 
2.33.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed value is incorrectly rounded
  2021-11-30 20:38                     ` Takashi Yano
@ 2021-11-30 21:17                       ` Takashi Yano
  2021-12-06  9:53                         ` Corinna Vinschen
  0 siblings, 1 reply; 25+ messages in thread
From: Takashi Yano @ 2021-11-30 21:17 UTC (permalink / raw)
  To: newlib

[-- Attachment #1: Type: text/plain, Size: 2175 bytes --]

On Wed, 1 Dec 2021 05:38:01 +0900
Takashi Yano wrote:
> On Tue, 30 Nov 2021 16:09:26 +0100
> Corinna Vinschen wrote:
> > On Nov 30 19:51, Takashi Yano wrote:
> > > On Mon, 29 Nov 2021 16:55:32 +0100
> > > Corinna Vinschen wrote:
> > > > On Nov 29 23:24, Takashi Yano wrote:
> > > > > [...]
> > > > > > > > > I have tried to import gdtoa into newlib from OpenBSD.
> > > > > > > > > [...]
> > > > [...struct __reent stuff...]
> > > Thanks for checking and advice. I have done these.
> > > 
> > > > As for the allocations, how big are those?  If they are comparable with
> > > > the allocation we now perform in _ldtoa_r, it might not be worth to keep
> > > > both functions.  Some users of smaller targets might also complain that
> > > 
> > > I saw max 16404 byte malloc().
> > > 
> > > > using printf now always pulls in both variants of ldtoa, thus raising
> > > > code size unnecessarily.  It might be better to keep the calls separate
> > > > and only use one or the other, per target or per code size constraints,
> > > > perhaps as a configure option.
> > > 
> > > I have added --enable-newlib-use-gdtoa option, which defaults
> > > to 'yes', into newlib/configure.ac. Is this the right thing?
> > 
> > That patch looks good to me, at least as far as Cygwin is concerned.
> 
> Thanks for reviewing.
> 
> > This isn't essential, but it might make sense to rename __ldtoa to
> > _ldtoa_r to avoid an extra function call, which could be time consuming
> > and add stack pressure.  I. e., in gdtoa-ldtoa.c
> > 
> >   #ifdef _USE_GDTOA
> >   // all code in gdtoa-ldtoa.c
> >   #endif
> > 
> > and in ldtoa.c:
> > 
> >   #ifndef _USE_GDTOA
> >   // all code in ldtoa.c
> >   #endif
> > 
> > AFAICS, __ldtoa could easily be changed to take the long double argument
> > by value because it's used in only two places, one of which just checks
> > the value anyway.  But, as I said, not essential.  We can keep in mind
> > for the time being.
> 
> Done.

Removed gdtoa-dtoa.c, which almost duplicates dtoa.c.

> > Could some people with other targets than Cygwin give this patch a try?
> > RTEMS, anybody?
> 
> I would appreciate it.


-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: v4-0001-ldtoa-Import-gdtoa-from-OpenBSD.patch --]
[-- Type: application/octet-stream, Size: 101290 bytes --]

From bd4a209d35aa5e3a7db651a8fd3ad2767f3ad892 Mon Sep 17 00:00:00 2001
From: Takashi Yano <takashi.yano@nifty.ne.jp>
Date: Wed, 1 Dec 2021 06:11:32 +0900
Subject: [PATCH v4] ldtoa: Import gdtoa from OpenBSD.

- This patch uses gdtoa imported from OpenBSD if newlib configure
  option "--enable-newlib-use-gdtoa=no" is NOT specified.  gdtoa
  provides more accurate output and faster conversion than legacy
  ldtoa, while it requires more heap memory.
---
 newlib/README                      |  10 +
 newlib/configure                   | 317 ++++++-----
 newlib/configure.ac                |  15 +
 newlib/libc/include/machine/ieee.h | 127 +++++
 newlib/libc/include/sys/config.h   |   6 +
 newlib/libc/stdlib/Makefile.am     |  10 +-
 newlib/libc/stdlib/Makefile.in     |  51 +-
 newlib/libc/stdlib/gdtoa-dmisc.c   | 230 ++++++++
 newlib/libc/stdlib/gdtoa-gdtoa.c   | 837 +++++++++++++++++++++++++++++
 newlib/libc/stdlib/gdtoa-gmisc.c   |  91 ++++
 newlib/libc/stdlib/gdtoa-ldtoa.c   | 159 ++++++
 newlib/libc/stdlib/gdtoa.h         | 130 ++++-
 newlib/libc/stdlib/gdtoaimp.h      | 206 +++++++
 newlib/libc/stdlib/ldtoa.c         |   6 +
 newlib/libc/stdlib/mprec.h         |   2 +-
 newlib/newlib.hin                  |   3 +
 16 files changed, 2034 insertions(+), 166 deletions(-)
 create mode 100644 newlib/libc/include/machine/ieee.h
 create mode 100644 newlib/libc/stdlib/gdtoa-dmisc.c
 create mode 100644 newlib/libc/stdlib/gdtoa-gdtoa.c
 create mode 100644 newlib/libc/stdlib/gdtoa-gmisc.c
 create mode 100644 newlib/libc/stdlib/gdtoa-ldtoa.c
 create mode 100644 newlib/libc/stdlib/gdtoaimp.h

diff --git a/newlib/README b/newlib/README
index 064c5784c..c82bf8b8c 100644
--- a/newlib/README
+++ b/newlib/README
@@ -352,6 +352,16 @@ One feature can be enabled by specifying `--enable-FEATURE=yes' or
      64-bit integer on most systems.
      Disabled by default.
 
+`--enable-newlib-use-gdtoa'
+     Use gdtoa rather than legacy ldtoa.  gdtoa privides more accurate
+     output and faster conversion than legacy ldtoa, while it requires
+     more heap memory.  gdtoa sometimes requires 16KB heap memory, so
+     if the platform does not have enough heap memory, consider disabling
+     this option. Legacy ldtoa also use heap, however, only 1KB memory
+     is malloc'ed.  In addition, if malloc fails, it still works, with
+     less conversion accuracy.
+     Enabled by default.
+
 `--enable-multilib'
      Build many library versions.
      Enabled by default.
diff --git a/newlib/configure b/newlib/configure
index ce2fb55d2..7ab6e3423 100755
--- a/newlib/configure
+++ b/newlib/configure
@@ -1,11 +1,9 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.68 for newlib 4.1.0.
+# Generated by GNU Autoconf 2.69 for newlib 4.1.0.
 #
 #
-# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
-# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
-# Foundation, Inc.
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
 #
 #
 # This configure script is free software; the Free Software Foundation
@@ -134,6 +132,31 @@ export LANGUAGE
 # CDPATH.
 (unset CDPATH) >/dev/null 2>&1 && unset CDPATH
 
+# Use a proper internal environment variable to ensure we don't fall
+  # into an infinite loop, continuously re-executing ourselves.
+  if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+    _as_can_reexec=no; export _as_can_reexec;
+    # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+  fi
+  # We don't want this to propagate to other subprocesses.
+          { _as_can_reexec=; unset _as_can_reexec;}
 if test "x$CONFIG_SHELL" = x; then
   as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
   emulate sh
@@ -167,7 +190,8 @@ if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
 else
   exitcode=1; echo positional parameters were not saved.
 fi
-test x\$exitcode = x0 || exit 1"
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
   as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
   as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
   eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
@@ -220,21 +244,25 @@ IFS=$as_save_IFS
 
 
       if test "x$CONFIG_SHELL" != x; then :
-  # We cannot yet assume a decent shell, so we have to provide a
-	# neutralization value for shells without unset; and this also
-	# works around shells that cannot unset nonexistent variables.
-	# Preserve -v and -x to the replacement shell.
-	BASH_ENV=/dev/null
-	ENV=/dev/null
-	(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
-	export CONFIG_SHELL
-	case $- in # ((((
-	  *v*x* | *x*v* ) as_opts=-vx ;;
-	  *v* ) as_opts=-v ;;
-	  *x* ) as_opts=-x ;;
-	  * ) as_opts= ;;
-	esac
-	exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"}
+  export CONFIG_SHELL
+             # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
 fi
 
     if test x$as_have_required = xno; then :
@@ -336,6 +364,14 @@ $as_echo X"$as_dir" |
 
 
 } # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
 # as_fn_append VAR VALUE
 # ----------------------
 # Append the text in VALUE to the end of the definition contained in VAR. Take
@@ -457,6 +493,10 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits
   chmod +x "$as_me.lineno" ||
     { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
 
+  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+  # already done that, so ensure we don't try to do so again and fall
+  # in an infinite loop.  This has already happened in practice.
+  _as_can_reexec=no; export _as_can_reexec
   # Don't try to exec as it changes $[0], causing all sort of problems
   # (the dirname of $[0] is not the place where we might find the
   # original and so on.  Autoconf is especially sensitive to this).
@@ -491,16 +531,16 @@ if (echo >conf$$.file) 2>/dev/null; then
     # ... but there are two gotchas:
     # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
     # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
-    # In both cases, we have to default to `cp -p'.
+    # In both cases, we have to default to `cp -pR'.
     ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
-      as_ln_s='cp -p'
+      as_ln_s='cp -pR'
   elif ln conf$$.file conf$$ 2>/dev/null; then
     as_ln_s=ln
   else
-    as_ln_s='cp -p'
+    as_ln_s='cp -pR'
   fi
 else
-  as_ln_s='cp -p'
+  as_ln_s='cp -pR'
 fi
 rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
 rmdir conf$$.dir 2>/dev/null
@@ -512,28 +552,8 @@ else
   as_mkdir_p=false
 fi
 
-if test -x / >/dev/null 2>&1; then
-  as_test_x='test -x'
-else
-  if ls -dL / >/dev/null 2>&1; then
-    as_ls_L_option=L
-  else
-    as_ls_L_option=
-  fi
-  as_test_x='
-    eval sh -c '\''
-      if test -d "$1"; then
-	test -d "$1/.";
-      else
-	case $1 in #(
-	-*)set "./$1";;
-	esac;
-	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
-	???[sx]*):;;*)false;;esac;fi
-    '\'' sh
-  '
-fi
-as_executable_p=$as_test_x
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
 
 # Sed expression to map a string onto a valid CPP name.
 as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
@@ -762,6 +782,7 @@ infodir
 docdir
 oldincludedir
 includedir
+runstatedir
 localstatedir
 sharedstatedir
 sysconfdir
@@ -808,6 +829,7 @@ enable_lite_exit
 enable_newlib_nano_formatted_io
 enable_newlib_retargetable_locking
 enable_newlib_long_time_t
+enable_newlib_use_gdtoa
 enable_multilib
 enable_target_optspace
 enable_malloc_debugging
@@ -877,6 +899,7 @@ datadir='${datarootdir}'
 sysconfdir='${prefix}/etc'
 sharedstatedir='${prefix}/com'
 localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
 includedir='${prefix}/include'
 oldincludedir='/usr/include'
 docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@@ -1129,6 +1152,15 @@ do
   | -silent | --silent | --silen | --sile | --sil)
     silent=yes ;;
 
+  -runstatedir | --runstatedir | --runstatedi | --runstated \
+  | --runstate | --runstat | --runsta | --runst | --runs \
+  | --run | --ru | --r)
+    ac_prev=runstatedir ;;
+  -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+  | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+  | --run=* | --ru=* | --r=*)
+    runstatedir=$ac_optarg ;;
+
   -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
     ac_prev=sbindir ;;
   -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1266,7 +1298,7 @@ fi
 for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
 		datadir sysconfdir sharedstatedir localstatedir includedir \
 		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
-		libdir localedir mandir
+		libdir localedir mandir runstatedir
 do
   eval ac_val=\$$ac_var
   # Remove trailing slashes.
@@ -1294,8 +1326,6 @@ target=$target_alias
 if test "x$host_alias" != x; then
   if test "x$build_alias" = x; then
     cross_compiling=maybe
-    $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.
-    If a cross compiler is detected then cross compile mode will be used" >&2
   elif test "x$build_alias" != "x$host_alias"; then
     cross_compiling=yes
   fi
@@ -1421,6 +1451,7 @@ Fine tuning of the installation directories:
   --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
   --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
   --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --runstatedir=DIR       modifiable per-process data [LOCALSTATEDIR/run]
   --libdir=DIR            object code libraries [EPREFIX/lib]
   --includedir=DIR        C header files [PREFIX/include]
   --oldincludedir=DIR     C header files for non-gcc [/usr/include]
@@ -1483,6 +1514,7 @@ Optional Features:
   --enable-newlib-nano-formatted-io    Use nano version formatted IO
   --enable-newlib-retargetable-locking    Allow locking routines to be retargeted at link time
   --enable-newlib-long-time_t   define time_t to long
+  --enable-newlib-use-gdtoa   Use gdtoa rather than legacy ldtoa
   --enable-multilib         build many library versions (default)
   --enable-target-optspace  optimize for space
   --enable-malloc-debugging indicate malloc debugging requested
@@ -1588,9 +1620,9 @@ test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
 newlib configure 4.1.0
-generated by GNU Autoconf 2.68
+generated by GNU Autoconf 2.69
 
-Copyright (C) 2010 Free Software Foundation, Inc.
+Copyright (C) 2012 Free Software Foundation, Inc.
 This configure script is free software; the Free Software Foundation
 gives unlimited permission to copy, distribute and modify it.
 _ACEOF
@@ -1666,7 +1698,7 @@ $as_echo "$ac_try_echo"; } >&5
 	 test ! -s conftest.err
        } && test -s conftest$ac_exeext && {
 	 test "$cross_compiling" = yes ||
-	 $as_test_x conftest$ac_exeext
+	 test -x conftest$ac_exeext
        }; then :
   ac_retval=0
 else
@@ -1866,7 +1898,7 @@ This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
 It was created by newlib $as_me 4.1.0, which was
-generated by GNU Autoconf 2.68.  Invocation command line was
+generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
 
@@ -2532,6 +2564,19 @@ else
   newlib_long_time_t=no
 fi
 
+# Check whether --enable-newlib-use-gdtoa was given.
+if test "${enable_newlib_use_gdtoa+set}" = set; then :
+  enableval=$enable_newlib_use_gdtoa; if test "${newlib_use_gdtoa+set}" != set; then
+  case "${enableval}" in
+    yes) newlib_use_gdtoa=yes ;;
+    no)  newlib_use_gdtoa=no  ;;
+    *)   as_fn_error $? "bad value ${enableval} for newlib-use-gdtoa option" "$LINENO" 5 ;;
+  esac
+ fi
+else
+  newlib_use_gdtoa=yes
+fi
+
 
 # Make sure we can run config.sub.
 $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
@@ -2643,7 +2688,7 @@ case $as_dir/ in #((
     # by default.
     for ac_prog in ginstall scoinst install; do
       for ac_exec_ext in '' $ac_executable_extensions; do
-	if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+	if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
 	  if test $ac_prog = install &&
 	    grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
 	    # AIX install.  It has an incompatible calling convention.
@@ -2812,7 +2857,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_STRIP="${ac_tool_prefix}strip"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -2852,7 +2897,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_STRIP="strip"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -2903,7 +2948,7 @@ do
   test -z "$as_dir" && as_dir=.
     for ac_prog in mkdir gmkdir; do
 	 for ac_exec_ext in '' $ac_executable_extensions; do
-	   { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue
+	   as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue
 	   case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
 	     'mkdir (GNU coreutils) '* | \
 	     'mkdir (coreutils) '* | \
@@ -2956,7 +3001,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_AWK="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3296,7 +3341,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_CC="gcc"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3464,7 +3509,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
        ac_prog_rejected=yes
        continue
@@ -3642,7 +3687,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_AS="${ac_tool_prefix}as"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3682,7 +3727,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_AS="as"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3734,7 +3779,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_AR="${ac_tool_prefix}ar"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3774,7 +3819,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_AR="ar"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3826,7 +3871,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3866,7 +3911,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_RANLIB="ranlib"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3918,7 +3963,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_READELF="${ac_tool_prefix}readelf"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3958,7 +4003,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_READELF="readelf"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4146,7 +4191,7 @@ do
     for ac_prog in sed gsed; do
     for ac_exec_ext in '' $ac_executable_extensions; do
       ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
-      { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue
+      as_fn_executable_p "$ac_path_SED" || continue
 # Check for GNU ac_path_SED and select it if it is found.
   # Check for GNU $ac_path_SED
 case `"$ac_path_SED" --version 2>&1` in
@@ -4276,7 +4321,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_AWK="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4322,7 +4367,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_AS="${ac_tool_prefix}as"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4362,7 +4407,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_AS="as"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4414,7 +4459,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4454,7 +4499,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_DLLTOOL="dlltool"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4506,7 +4551,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4546,7 +4591,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_OBJDUMP="objdump"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4668,7 +4713,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_CC="${ac_tool_prefix}gcc"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4708,7 +4753,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_CC="gcc"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4761,7 +4806,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_CC="${ac_tool_prefix}cc"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4802,7 +4847,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
        ac_prog_rejected=yes
        continue
@@ -4860,7 +4905,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4904,7 +4949,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_CC="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -5350,8 +5395,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #include <stdarg.h>
 #include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
+struct stat;
 /* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
 struct buf { int x; };
 FILE * (*rcsopen) (struct buf *, struct stat *, int);
@@ -5580,7 +5624,7 @@ do
     for ac_prog in grep ggrep; do
     for ac_exec_ext in '' $ac_executable_extensions; do
       ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
-      { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+      as_fn_executable_p "$ac_path_GREP" || continue
 # Check for GNU ac_path_GREP and select it if it is found.
   # Check for GNU $ac_path_GREP
 case `"$ac_path_GREP" --version 2>&1` in
@@ -5646,7 +5690,7 @@ do
     for ac_prog in egrep; do
     for ac_exec_ext in '' $ac_executable_extensions; do
       ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
-      { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+      as_fn_executable_p "$ac_path_EGREP" || continue
 # Check for GNU ac_path_EGREP and select it if it is found.
   # Check for GNU $ac_path_EGREP
 case `"$ac_path_EGREP" --version 2>&1` in
@@ -5713,7 +5757,7 @@ do
     for ac_prog in fgrep; do
     for ac_exec_ext in '' $ac_executable_extensions; do
       ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
-      { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue
+      as_fn_executable_p "$ac_path_FGREP" || continue
 # Check for GNU ac_path_FGREP and select it if it is found.
   # Check for GNU $ac_path_FGREP
 case `"$ac_path_FGREP" --version 2>&1` in
@@ -5969,7 +6013,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6013,7 +6057,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6353,7 +6397,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6393,7 +6437,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_OBJDUMP="objdump"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6670,7 +6714,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_AR="${ac_tool_prefix}ar"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6710,7 +6754,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_AR="ar"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6775,7 +6819,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_STRIP="${ac_tool_prefix}strip"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6815,7 +6859,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_STRIP="strip"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6874,7 +6918,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6914,7 +6958,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_RANLIB="ranlib"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7504,7 +7548,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7544,7 +7588,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7596,7 +7640,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7636,7 +7680,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_NMEDIT="nmedit"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7688,7 +7732,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7728,7 +7772,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_LIPO="lipo"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7780,7 +7824,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7820,7 +7864,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_OTOOL="otool"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7872,7 +7916,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7912,7 +7956,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_OTOOL64="otool64"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -11855,7 +11899,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11858 "configure"
+#line 11902 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11961,7 +12005,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11964 "configure"
+#line 12008 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12586,6 +12630,13 @@ _ACEOF
 
 fi
 
+if test "${newlib_use_gdtoa}" = "yes"; then
+cat >>confdefs.h <<_ACEOF
+#define _WANT_USE_GDTOA 1
+_ACEOF
+
+fi
+
 
 if test "x${iconv_encodings}" != "x" \
    || test "x${iconv_to_encodings}" != "x" \
@@ -13302,16 +13353,16 @@ if (echo >conf$$.file) 2>/dev/null; then
     # ... but there are two gotchas:
     # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
     # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
-    # In both cases, we have to default to `cp -p'.
+    # In both cases, we have to default to `cp -pR'.
     ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
-      as_ln_s='cp -p'
+      as_ln_s='cp -pR'
   elif ln conf$$.file conf$$ 2>/dev/null; then
     as_ln_s=ln
   else
-    as_ln_s='cp -p'
+    as_ln_s='cp -pR'
   fi
 else
-  as_ln_s='cp -p'
+  as_ln_s='cp -pR'
 fi
 rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
 rmdir conf$$.dir 2>/dev/null
@@ -13371,28 +13422,16 @@ else
   as_mkdir_p=false
 fi
 
-if test -x / >/dev/null 2>&1; then
-  as_test_x='test -x'
-else
-  if ls -dL / >/dev/null 2>&1; then
-    as_ls_L_option=L
-  else
-    as_ls_L_option=
-  fi
-  as_test_x='
-    eval sh -c '\''
-      if test -d "$1"; then
-	test -d "$1/.";
-      else
-	case $1 in #(
-	-*)set "./$1";;
-	esac;
-	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
-	???[sx]*):;;*)false;;esac;fi
-    '\'' sh
-  '
-fi
-as_executable_p=$as_test_x
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
 
 # Sed expression to map a string onto a valid CPP name.
 as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
@@ -13414,7 +13453,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # values after options handling.
 ac_log="
 This file was extended by newlib $as_me 4.1.0, which was
-generated by GNU Autoconf 2.68.  Invocation command line was
+generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
   CONFIG_HEADERS  = $CONFIG_HEADERS
@@ -13480,10 +13519,10 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
 newlib config.status 4.1.0
-configured by $0, generated by GNU Autoconf 2.68,
+configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
-Copyright (C) 2010 Free Software Foundation, Inc.
+Copyright (C) 2012 Free Software Foundation, Inc.
 This config.status script is free software; the Free Software Foundation
 gives unlimited permission to copy, distribute and modify it."
 
@@ -13574,7 +13613,7 @@ fi
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 if \$ac_cs_recheck; then
-  set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
   shift
   \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
   CONFIG_SHELL='$SHELL'
diff --git a/newlib/configure.ac b/newlib/configure.ac
index 49a1b5fdd..25f6d07ed 100644
--- a/newlib/configure.ac
+++ b/newlib/configure.ac
@@ -259,6 +259,17 @@ AC_ARG_ENABLE(newlib-long-time_t,
   esac
  fi], [newlib_long_time_t=no])dnl
 
+dnl Support --enable-newlib-use-gdtoa
+AC_ARG_ENABLE(newlib-use-gdtoa,
+[  --enable-newlib-use-gdtoa   Use gdtoa rather than legacy ldtoa],
+[if test "${newlib_use_gdtoa+set}" != set; then
+  case "${enableval}" in
+    yes) newlib_use_gdtoa=yes ;;
+    no)  newlib_use_gdtoa=no  ;;
+    *)   AC_MSG_ERROR(bad value ${enableval} for newlib-use-gdtoa option) ;;
+  esac
+ fi], [newlib_use_gdtoa=yes])dnl
+
 NEWLIB_CONFIGURE(.)
 
 dnl We have to enable libtool after NEWLIB_CONFIGURE because if we try and
@@ -537,6 +548,10 @@ if test "${newlib_long_time_t}" = "yes"; then
 AC_DEFINE_UNQUOTED(_WANT_USE_LONG_TIME_T)
 fi
 
+if test "${newlib_use_gdtoa}" = "yes"; then
+AC_DEFINE_UNQUOTED(_WANT_USE_GDTOA)
+fi
+
 dnl
 dnl Parse --enable-newlib-iconv-encodings option argument
 dnl
diff --git a/newlib/libc/include/machine/ieee.h b/newlib/libc/include/machine/ieee.h
new file mode 100644
index 000000000..0656909ab
--- /dev/null
+++ b/newlib/libc/include/machine/ieee.h
@@ -0,0 +1,127 @@
+#ifndef _MACHINE_IEEE_H_
+#define _MACHINE_IEEE_H_
+#include <sys/types.h>
+#include <sys/cdefs.h>
+#include <machine/ieeefp.h>
+#include <float.h>
+
+#if LDBL_MANT_DIG == 24
+#define EXT_IMPLICIT_NBIT
+#define EXT_TO_ARRAY32(p, a) do {      \
+    (a)[0] = (p)->ext_frac;  \
+} while (0)
+#ifdef __IEEE_LITTLE_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_frac:23;
+    uint32_t   ext_exp:8;
+    uint32_t   ext_sign:1;
+};
+#endif
+#ifdef __IEEE_BIG_ENDIAN
+struct ieee_ext {
+#ifndef ___IEEE_BYTES_LITTLE_ENDIAN
+    uint32_t   ext_sign:1;
+    uint32_t   ext_exp:8;
+    uint32_t   ext_frac:23;
+#else /* ARMEL without __VFP_FP__ */
+    uint32_t   ext_frac:23;
+    uint32_t   ext_exp:8;
+    uint32_t   ext_sign:1;
+#endif
+};
+#endif
+#elif LDBL_MANT_DIG == 53
+#define EXT_IMPLICIT_NBIT
+#define EXT_TO_ARRAY32(p, a) do {       \
+    (a)[0] = (p)->ext_fracl;  \
+    (a)[1] = (p)->ext_frach;  \
+} while (0)
+#ifdef __IEEE_LITTLE_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_fracl;
+    uint32_t   ext_frach:20;
+    uint32_t   ext_exp:11;
+    uint32_t   ext_sign:1;
+};
+#endif
+#ifdef __IEEE_BIG_ENDIAN
+struct ieee_ext {
+#ifndef ___IEEE_BYTES_LITTLE_ENDIAN
+    uint32_t   ext_sign:1;
+    uint32_t   ext_exp:11;
+    uint32_t   ext_frach:20;
+#else /* ARMEL without __VFP_FP__ */
+    uint32_t   ext_frach:20;
+    uint32_t   ext_exp:11;
+    uint32_t   ext_sign:1;
+#endif
+    uint32_t   ext_fracl;
+};
+#endif
+#elif LDBL_MANT_DIG == 64
+#define EXT_TO_ARRAY32(p, a) do {       \
+    (a)[0] = (p)->ext_fracl;  \
+    (a)[1] = (p)->ext_frach;  \
+} while (0)
+#ifdef __IEEE_LITTLE_ENDIAN /* for Intel CPU */
+struct ieee_ext {
+    uint32_t   ext_fracl;
+    uint32_t   ext_frach;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_sign:1;
+    uint32_t   ext_padl:16;
+    uint32_t   ext_padh;
+};
+#endif
+#ifdef __IEEE_BIG_ENDIAN
+struct ieee_ext {
+#ifndef ___IEEE_BYTES_LITTLE_ENDIAN /* for m68k */
+    uint32_t   ext_sign:1;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_pad:16;
+#else /* ARM FPA10 math coprocessor */
+    uint32_t   ext_exp:15;
+    uint32_t   ext_pad:16;
+    uint32_t   ext_sign:1;
+#endif
+    uint32_t   ext_frach;
+    uint32_t   ext_fracl;
+};
+#endif
+#elif LDBL_MANT_DIG == 113
+#define EXT_IMPLICIT_NBIT
+#define EXT_TO_ARRAY32(p, a) do {        \
+    (a)[0] = (p)->ext_fracl;   \
+    (a)[1] = (p)->ext_fraclm;  \
+    (a)[2] = (p)->ext_frachm;  \
+    (a)[3] = (p)->ext_frach;   \
+} while (0)
+#ifdef __IEEE_LITTLE_ENDIAN
+struct ieee_ext {
+    uint32_t   ext_fracl;
+    uint32_t   ext_fraclm;
+    uint32_t   ext_frachm;
+    uint32_t   ext_frach:16;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_sign:1;
+};
+#endif
+#ifdef __IEEE_BIG_ENDIAN
+struct ieee_ext {
+#ifndef ___IEEE_BYTES_LITTLE_ENDIAN
+    uint32_t   ext_sign:1;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_frach:16;
+#else /* ARMEL without __VFP_FP__ */
+    uint32_t   ext_frach:16;
+    uint32_t   ext_exp:15;
+    uint32_t   ext_sign:1;
+#endif
+    uint32_t   ext_frachm;
+    uint32_t   ext_fraclm;
+    uint32_t   ext_fracl;
+};
+#endif
+#endif
+
+#endif /* _MACHINE_IEEE_H_ */
diff --git a/newlib/libc/include/sys/config.h b/newlib/libc/include/sys/config.h
index b9dff88ff..61a6f95d8 100644
--- a/newlib/libc/include/sys/config.h
+++ b/newlib/libc/include/sys/config.h
@@ -293,6 +293,12 @@
 #endif
 #endif
 
+#ifdef _WANT_USE_GDTOA
+#ifndef _USE_GDTOA
+#define _USE_GDTOA
+#endif
+#endif
+
 /* If _MB_EXTENDED_CHARSETS_ALL is set, we want all of the extended
    charsets.  The extended charsets add a few functions and a couple
    of tables of a few K each. */
diff --git a/newlib/libc/stdlib/Makefile.am b/newlib/libc/stdlib/Makefile.am
index 357e37beb..2f46c837c 100644
--- a/newlib/libc/stdlib/Makefile.am
+++ b/newlib/libc/stdlib/Makefile.am
@@ -38,6 +38,10 @@ GENERAL_SOURCES = \
 	labs.c 		\
 	ldiv.c  	\
 	ldtoa.c		\
+	gdtoa-ldtoa.c	\
+	gdtoa-gdtoa.c	\
+	gdtoa-dmisc.c	\
+	gdtoa-gmisc.c	\
 	malloc.c  	\
 	mblen.c		\
 	mblen_r.c	\
@@ -311,7 +315,11 @@ CHEWOUT_FILES= \
 CHAPTERS = stdlib.tex
 
 $(lpfx)dtoa.$(oext): dtoa.c mprec.h
-$(lpfx)ldtoa.$(oext): ldtoa.c mprec.h
+$(lpfx)ldtoa.$(oext): ldtoa.c mprec.h gdtoa.h
+$(lpfx)gdtoa-ldtoa.$(oext): gdtoa-ldtoa.c mprec.h gdtoaimp.h gdtoa.h
+$(lpfx)gdtoa-gdtoa.$(oext): gdtoa-gdtoa.c mprec.h gdtoaimp.h gdtoa.h
+$(lpfx)gdtoa-dmisc.$(oext): gdtoa-dmisc.c mprec.h gdtoaimp.h gdtoa.h
+$(lpfx)gdtoa-gmisc.$(oext): gdtoa-gmisc.c mprec.h gdtoaimp.h gdtoa.h
 $(lpfx)ecvtbuf.$(oext): ecvtbuf.c mprec.h
 $(lpfx)mbtowc_r.$(oext): mbtowc_r.c mbctype.h
 $(lpfx)mprec.$(oext): mprec.c mprec.h
diff --git a/newlib/libc/stdlib/Makefile.in b/newlib/libc/stdlib/Makefile.in
index a812b6a95..7d3342a67 100644
--- a/newlib/libc/stdlib/Makefile.in
+++ b/newlib/libc/stdlib/Makefile.in
@@ -101,7 +101,9 @@ am__objects_2 = lib_a-__adjust.$(OBJEXT) lib_a-__atexit.$(OBJEXT) \
 	lib_a-getenv_r.$(OBJEXT) lib_a-imaxabs.$(OBJEXT) \
 	lib_a-imaxdiv.$(OBJEXT) lib_a-itoa.$(OBJEXT) \
 	lib_a-labs.$(OBJEXT) lib_a-ldiv.$(OBJEXT) \
-	lib_a-ldtoa.$(OBJEXT) lib_a-malloc.$(OBJEXT) \
+	lib_a-ldtoa.$(OBJEXT) lib_a-gdtoa-ldtoa.$(OBJEXT) \
+	lib_a-gdtoa-gdtoa.$(OBJEXT) lib_a-gdtoa-dmisc.$(OBJEXT) \
+	lib_a-gdtoa-gmisc.$(OBJEXT) lib_a-malloc.$(OBJEXT) \
 	lib_a-mblen.$(OBJEXT) lib_a-mblen_r.$(OBJEXT) \
 	lib_a-mbstowcs.$(OBJEXT) lib_a-mbstowcs_r.$(OBJEXT) \
 	lib_a-mbtowc.$(OBJEXT) lib_a-mbtowc_r.$(OBJEXT) \
@@ -165,6 +167,7 @@ am__objects_9 = __adjust.lo __atexit.lo __call_atexit.lo __exp10.lo \
 	div.lo dtoa.lo dtoastub.lo environ.lo envlock.lo eprintf.lo \
 	exit.lo gdtoa-gethex.lo gdtoa-hexnan.lo getenv.lo getenv_r.lo \
 	imaxabs.lo imaxdiv.lo itoa.lo labs.lo ldiv.lo ldtoa.lo \
+	gdtoa-ldtoa.lo gdtoa-gdtoa.lo gdtoa-dmisc.lo gdtoa-gmisc.lo \
 	malloc.lo mblen.lo mblen_r.lo mbstowcs.lo mbstowcs_r.lo \
 	mbtowc.lo mbtowc_r.lo mlock.lo mprec.lo mstats.lo \
 	on_exit_args.lo quick_exit.lo rand.lo rand_r.lo random.lo \
@@ -354,6 +357,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 shared_machine_dir = @shared_machine_dir@
 sharedstatedir = @sharedstatedir@
@@ -372,13 +376,14 @@ GENERAL_SOURCES = __adjust.c __atexit.c __call_atexit.c __exp10.c \
 	atexit.c atof.c atoff.c atoi.c atol.c calloc.c div.c dtoa.c \
 	dtoastub.c environ.c envlock.c eprintf.c exit.c gdtoa-gethex.c \
 	gdtoa-hexnan.c getenv.c getenv_r.c imaxabs.c imaxdiv.c itoa.c \
-	labs.c ldiv.c ldtoa.c malloc.c mblen.c mblen_r.c mbstowcs.c \
-	mbstowcs_r.c mbtowc.c mbtowc_r.c mlock.c mprec.c mstats.c \
-	on_exit_args.c quick_exit.c rand.c rand_r.c random.c realloc.c \
-	reallocarray.c reallocf.c sb_charsets.c strtod.c strtoimax.c \
-	strtol.c strtoul.c strtoumax.c utoa.c wcstod.c wcstoimax.c \
-	wcstol.c wcstoul.c wcstoumax.c wcstombs.c wcstombs_r.c \
-	wctomb.c wctomb_r.c $(am__append_1)
+	labs.c ldiv.c ldtoa.c gdtoa-ldtoa.c gdtoa-gdtoa.c \
+	gdtoa-dmisc.c gdtoa-gmisc.c malloc.c mblen.c mblen_r.c \
+	mbstowcs.c mbstowcs_r.c mbtowc.c mbtowc_r.c mlock.c mprec.c \
+	mstats.c on_exit_args.c quick_exit.c rand.c rand_r.c random.c \
+	realloc.c reallocarray.c reallocf.c sb_charsets.c strtod.c \
+	strtoimax.c strtol.c strtoul.c strtoumax.c utoa.c wcstod.c \
+	wcstoimax.c wcstol.c wcstoul.c wcstoumax.c wcstombs.c \
+	wcstombs_r.c wctomb.c wctomb_r.c $(am__append_1)
 @NEWLIB_NANO_MALLOC_FALSE@MALIGNR = malignr
 @NEWLIB_NANO_MALLOC_TRUE@MALIGNR = nano-malignr
 @NEWLIB_NANO_MALLOC_FALSE@MALLOPTR = malloptr
@@ -827,6 +832,30 @@ lib_a-ldtoa.o: ldtoa.c
 lib_a-ldtoa.obj: ldtoa.c
 	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-ldtoa.obj `if test -f 'ldtoa.c'; then $(CYGPATH_W) 'ldtoa.c'; else $(CYGPATH_W) '$(srcdir)/ldtoa.c'; fi`
 
+lib_a-gdtoa-ldtoa.o: gdtoa-ldtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-ldtoa.o `test -f 'gdtoa-ldtoa.c' || echo '$(srcdir)/'`gdtoa-ldtoa.c
+
+lib_a-gdtoa-ldtoa.obj: gdtoa-ldtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-ldtoa.obj `if test -f 'gdtoa-ldtoa.c'; then $(CYGPATH_W) 'gdtoa-ldtoa.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-ldtoa.c'; fi`
+
+lib_a-gdtoa-gdtoa.o: gdtoa-gdtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-gdtoa.o `test -f 'gdtoa-gdtoa.c' || echo '$(srcdir)/'`gdtoa-gdtoa.c
+
+lib_a-gdtoa-gdtoa.obj: gdtoa-gdtoa.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-gdtoa.obj `if test -f 'gdtoa-gdtoa.c'; then $(CYGPATH_W) 'gdtoa-gdtoa.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-gdtoa.c'; fi`
+
+lib_a-gdtoa-dmisc.o: gdtoa-dmisc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-dmisc.o `test -f 'gdtoa-dmisc.c' || echo '$(srcdir)/'`gdtoa-dmisc.c
+
+lib_a-gdtoa-dmisc.obj: gdtoa-dmisc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-dmisc.obj `if test -f 'gdtoa-dmisc.c'; then $(CYGPATH_W) 'gdtoa-dmisc.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-dmisc.c'; fi`
+
+lib_a-gdtoa-gmisc.o: gdtoa-gmisc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-gmisc.o `test -f 'gdtoa-gmisc.c' || echo '$(srcdir)/'`gdtoa-gmisc.c
+
+lib_a-gdtoa-gmisc.obj: gdtoa-gmisc.c
+	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-gdtoa-gmisc.obj `if test -f 'gdtoa-gmisc.c'; then $(CYGPATH_W) 'gdtoa-gmisc.c'; else $(CYGPATH_W) '$(srcdir)/gdtoa-gmisc.c'; fi`
+
 lib_a-malloc.o: malloc.c
 	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-malloc.o `test -f 'malloc.c' || echo '$(srcdir)/'`malloc.c
 
@@ -1610,7 +1639,11 @@ $(lpfx)$(MALLOPTR).$(oext): $(MALLOCR).c
 	$(MALLOC_COMPILE) -DDEFINE_MALLOPT -c $(srcdir)/$(MALLOCR).c -o $@
 
 $(lpfx)dtoa.$(oext): dtoa.c mprec.h
-$(lpfx)ldtoa.$(oext): ldtoa.c mprec.h
+$(lpfx)ldtoa.$(oext): ldtoa.c mprec.h gdtoa.h
+$(lpfx)gdtoa-ldtoa.$(oext): gdtoa-ldtoa.c mprec.h gdtoaimp.h gdtoa.h
+$(lpfx)gdtoa-gdtoa.$(oext): gdtoa-gdtoa.c mprec.h gdtoaimp.h gdtoa.h
+$(lpfx)gdtoa-dmisc.$(oext): gdtoa-dmisc.c mprec.h gdtoaimp.h gdtoa.h
+$(lpfx)gdtoa-gmisc.$(oext): gdtoa-gmisc.c mprec.h gdtoaimp.h gdtoa.h
 $(lpfx)ecvtbuf.$(oext): ecvtbuf.c mprec.h
 $(lpfx)mbtowc_r.$(oext): mbtowc_r.c mbctype.h
 $(lpfx)mprec.$(oext): mprec.c mprec.h
diff --git a/newlib/libc/stdlib/gdtoa-dmisc.c b/newlib/libc/stdlib/gdtoa-dmisc.c
new file mode 100644
index 000000000..332023dae
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-dmisc.c
@@ -0,0 +1,230 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include <newlib.h>
+#include <sys/config.h>
+
+#ifdef _USE_GDTOA
+#include "gdtoaimp.h"
+
+#ifndef MULTIPLE_THREADS
+ char *dtoa_result;
+#endif
+
+ char *
+#ifdef KR_headers
+rv_alloc(ptr, i) struct _reent *ptr, int i;
+#else
+rv_alloc(struct _reent *ptr, int i)
+#endif
+{
+	int j, k, *r;
+
+	j = sizeof(ULong);
+	for(k = 0;
+		sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i;
+		j <<= 1)
+			k++;
+	r = (int*)Balloc(ptr, k);
+	if (r == NULL)
+		return (
+#ifndef MULTIPLE_THREADS
+		dtoa_result =
+#endif
+			NULL);
+	*r = k;
+	return
+#ifndef MULTIPLE_THREADS
+	dtoa_result =
+#endif
+		(char *)(r+1);
+	}
+
+ char *
+#ifdef KR_headers
+nrv_alloc(ptr, s, rve, n) struct _reent *ptr, char *s, **rve; int n;
+#else
+nrv_alloc(struct _reent *ptr, char *s, char **rve, int n)
+#endif
+{
+	char *rv, *t;
+
+	t = rv = rv_alloc(ptr, n);
+	if (t == NULL)
+		return (NULL);
+	while((*t = *s++) !=0)
+		t++;
+	if (rve)
+		*rve = t;
+	return rv;
+	}
+
+/* freedtoa(s) must be used to free values s returned by dtoa
+ * when MULTIPLE_THREADS is #defined.  It should be used in all cases,
+ * but for consistency with earlier versions of dtoa, it is optional
+ * when MULTIPLE_THREADS is not defined.
+ */
+
+ void
+#ifdef KR_headers
+freedtoa(ptr, s) struct _reent *ptr, char *s;
+#else
+freedtoa(struct _reent *ptr, char *s)
+#endif
+{
+	Bigint *b = (Bigint *)((int *)s - 1);
+	b->_maxwds = 1 << (b->_k = *(int*)b);
+	Bfree(ptr, b);
+#ifndef MULTIPLE_THREADS
+	if (s == dtoa_result)
+		dtoa_result = 0;
+#endif
+	}
+DEF_STRONG(freedtoa);
+
+ int
+quorem
+#ifdef KR_headers
+	(b, S) Bigint *b, *S;
+#else
+	(Bigint *b, Bigint *S)
+#endif
+{
+	int n;
+	ULong *bx, *bxe, q, *sx, *sxe;
+#ifdef ULLong
+	ULLong borrow, carry, y, ys;
+#else
+	ULong borrow, carry, y, ys;
+#ifdef Pack_32
+	ULong si, z, zs;
+#endif
+#endif
+
+	n = S->_wds;
+#ifdef DEBUG
+	/*debug*/ if (b->_wds > n)
+	/*debug*/	Bug("oversize b in quorem");
+#endif
+	if (b->_wds < n)
+		return 0;
+	sx = S->_x;
+	sxe = sx + --n;
+	bx = b->_x;
+	bxe = bx + n;
+	q = *bxe / (*sxe + 1);	/* ensure q <= true quotient */
+#ifdef DEBUG
+	/*debug*/ if (q > 9)
+	/*debug*/	Bug("oversized quotient in quorem");
+#endif
+	if (q) {
+		borrow = 0;
+		carry = 0;
+		do {
+#ifdef ULLong
+			ys = *sx++ * (ULLong)q + carry;
+			carry = ys >> 32;
+			y = *bx - (ys & 0xffffffffUL) - borrow;
+			borrow = y >> 32 & 1UL;
+			*bx++ = y & 0xffffffffUL;
+#else
+#ifdef Pack_32
+			si = *sx++;
+			ys = (si & 0xffff) * q + carry;
+			zs = (si >> 16) * q + (ys >> 16);
+			carry = zs >> 16;
+			y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			z = (*bx >> 16) - (zs & 0xffff) - borrow;
+			borrow = (z & 0x10000) >> 16;
+			Storeinc(bx, z, y);
+#else
+			ys = *sx++ * q + carry;
+			carry = ys >> 16;
+			y = *bx - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			*bx++ = y & 0xffff;
+#endif
+#endif
+			}
+			while(sx <= sxe);
+		if (!*bxe) {
+			bx = b->_x;
+			while(--bxe > bx && !*bxe)
+				--n;
+			b->_wds = n;
+			}
+		}
+	if (cmp(b, S) >= 0) {
+		q++;
+		borrow = 0;
+		carry = 0;
+		bx = b->_x;
+		sx = S->_x;
+		do {
+#ifdef ULLong
+			ys = *sx++ + carry;
+			carry = ys >> 32;
+			y = *bx - (ys & 0xffffffffUL) - borrow;
+			borrow = y >> 32 & 1UL;
+			*bx++ = y & 0xffffffffUL;
+#else
+#ifdef Pack_32
+			si = *sx++;
+			ys = (si & 0xffff) + carry;
+			zs = (si >> 16) + (ys >> 16);
+			carry = zs >> 16;
+			y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			z = (*bx >> 16) - (zs & 0xffff) - borrow;
+			borrow = (z & 0x10000) >> 16;
+			Storeinc(bx, z, y);
+#else
+			ys = *sx++ + carry;
+			carry = ys >> 16;
+			y = *bx - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			*bx++ = y & 0xffff;
+#endif
+#endif
+			}
+			while(sx <= sxe);
+		bx = b->_x;
+		bxe = bx + n;
+		if (!*bxe) {
+			while(--bxe > bx && !*bxe)
+				--n;
+			b->_wds = n;
+			}
+		}
+	return q;
+	}
+#endif /* _USE_GDTOA */
diff --git a/newlib/libc/stdlib/gdtoa-gdtoa.c b/newlib/libc/stdlib/gdtoa-gdtoa.c
new file mode 100644
index 000000000..da2338c48
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-gdtoa.c
@@ -0,0 +1,837 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998, 1999 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include <newlib.h>
+#include <sys/config.h>
+
+#ifdef _USE_GDTOA
+#include "gdtoaimp.h"
+
+ static Bigint *
+#ifdef KR_headers
+bitstob(ptr, bits, nbits, bbits) ULong *bits;
+struct _reent ptr, int nbits; int *bbits;
+#else
+bitstob(struct _reent *ptr, ULong *bits, int nbits, int *bbits)
+#endif
+{
+	int i, k;
+	Bigint *b;
+	ULong *be, *x, *x0;
+
+	i = ULbits;
+	k = 0;
+	while(i < nbits) {
+		i <<= 1;
+		k++;
+		}
+#ifndef Pack_32
+	if (!k)
+		k = 1;
+#endif
+	b = Balloc(ptr, k);
+	if (b == NULL)
+		return (NULL);
+	be = bits + ((nbits - 1) >> kshift);
+	x = x0 = b->_x;
+	do {
+		*x++ = *bits & ALL_ON;
+#ifdef Pack_16
+		*x++ = (*bits >> 16) & ALL_ON;
+#endif
+		} while(++bits <= be);
+	i = x - x0;
+	while(!x0[--i])
+		if (!i) {
+			b->_wds = 0;
+			*bbits = 0;
+			goto ret;
+			}
+	b->_wds = i + 1;
+	*bbits = i*ULbits + 32 - hi0bits(b->_x[i]);
+ ret:
+	return b;
+	}
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ *	1. Rather than iterating, we use a simple numeric overestimate
+ *	   to determine k = floor(log10(d)).  We scale relevant
+ *	   quantities using O(log2(k)) rather than O(k) multiplications.
+ *	2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ *	   try to generate digits strictly left to right.  Instead, we
+ *	   compute with fewer bits and propagate the carry if necessary
+ *	   when rounding the final digit up.  This is often faster.
+ *	3. Under the assumption that input will be rounded nearest,
+ *	   mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ *	   That is, we allow equality in stopping tests when the
+ *	   round-nearest rule will give the same floating-point value
+ *	   as would satisfaction of the stopping test with strict
+ *	   inequality.
+ *	4. We remove common factors of powers of 2 from relevant
+ *	   quantities.
+ *	5. When converting floating-point integers less than 1e16,
+ *	   we use floating-point arithmetic rather than resorting
+ *	   to multiple-precision integers.
+ *	6. When asked to produce fewer than 15 digits, we first try
+ *	   to get by with floating-point arithmetic; we resort to
+ *	   multiple-precision integer arithmetic only if we cannot
+ *	   guarantee that the floating-point calculation has given
+ *	   the correctly rounded result.  For k requested digits and
+ *	   "uniformly" distributed input, the probability is
+ *	   something like 10^(k-15) that we must resort to the Long
+ *	   calculation.
+ */
+
+ char *
+gdtoa
+#ifdef KR_headers
+	(ptr, fpi, be, bits, kindp, mode, ndigits, decpt, rve)
+	struct _reent *ptr, FPI *fpi; int be; ULong *bits;
+	int *kindp, mode, ndigits, *decpt; char **rve;
+#else
+	(struct _reent *ptr, FPI *fpi, int be, ULong *bits, int *kindp,
+	 int mode, int ndigits, int *decpt, char **rve)
+#endif
+{
+ /*	Arguments ndigits and decpt are similar to the second and third
+	arguments of ecvt and fcvt; trailing zeros are suppressed from
+	the returned string.  If not null, *rve is set to point
+	to the end of the return value.  If d is +-Infinity or NaN,
+	then *decpt is set to 9999.
+	be = exponent: value = (integer represented by bits) * (2 to the power of be).
+
+	mode:
+		0 ==> shortest string that yields d when read in
+			and rounded to nearest.
+		1 ==> like 0, but with Steele & White stopping rule;
+			e.g. with IEEE P754 arithmetic , mode 0 gives
+			1e23 whereas mode 1 gives 9.999999999999999e22.
+		2 ==> max(1,ndigits) significant digits.  This gives a
+			return value similar to that of ecvt, except
+			that trailing zeros are suppressed.
+		3 ==> through ndigits past the decimal point.  This
+			gives a return value similar to that from fcvt,
+			except that trailing zeros are suppressed, and
+			ndigits can be negative.
+		4-9 should give the same return values as 2-3, i.e.,
+			4 <= mode <= 9 ==> same return as mode
+			2 + (mode & 1).  These modes are mainly for
+			debugging; often they run slower but sometimes
+			faster than modes 2-3.
+		4,5,8,9 ==> left-to-right digit generation.
+		6-9 ==> don't try fast floating-point estimate
+			(if applicable).
+
+		Values of mode other than 0-9 are treated as mode 0.
+
+		Sufficient space is allocated to the return value
+		to hold the suppressed trailing zeros.
+	*/
+
+	int bbits, b2, b5, be0, dig, i, ieps, ilim, ilim0, ilim1, inex;
+	int j, j1, k, k0, k_check, kind, leftright, m2, m5, nbits;
+	int rdir, s2, s5, spec_case, try_quick;
+	Long L;
+	Bigint *b, *b1, *delta, *mlo, *mhi, *mhi1, *S;
+	double d2, ds;
+	char *s, *s0;
+	U d, eps;
+
+#ifndef MULTIPLE_THREADS
+	if (dtoa_result) {
+		freedtoa(ptr, dtoa_result);
+		dtoa_result = 0;
+		}
+#endif
+	inex = 0;
+	kind = *kindp &= ~STRTOG_Inexact;
+	switch(kind & STRTOG_Retmask) {
+	  case STRTOG_Zero:
+		goto ret_zero;
+	  case STRTOG_Normal:
+	  case STRTOG_Denormal:
+		break;
+	  case STRTOG_Infinite:
+		*decpt = -32768;
+		return nrv_alloc(ptr, "Infinity", rve, 8);
+	  case STRTOG_NaN:
+		*decpt = -32768;
+		return nrv_alloc(ptr, "NaN", rve, 3);
+	  default:
+		return 0;
+	  }
+	b = bitstob(ptr, bits, nbits = fpi->nbits, &bbits);
+	if (b == NULL)
+		return (NULL);
+	be0 = be;
+	if ( (i = trailz(b)) !=0) {
+		rshift(b, i);
+		be += i;
+		bbits -= i;
+		}
+	if (!b->_wds) {
+		Bfree(ptr, b);
+ ret_zero:
+		*decpt = 1;
+		return nrv_alloc(ptr, "0", rve, 1);
+		}
+
+	dval(d) = b2d(b, &i);
+	i = be + bbits - 1;
+	word0(d) &= Frac_mask1;
+	word0(d) |= Exp_11;
+#ifdef IBM
+	if ( (j = 11 - hi0bits(word0(d) & Frac_mask)) !=0)
+		dval(d) /= 1 << j;
+#endif
+
+	/* log(x)	~=~ log(1.5) + (x-1.5)/1.5
+	 * log10(x)	 =  log(x) / log(10)
+	 *		~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+	 * log10(&d) = (i-Bias)*log(2)/log(10) + log10(d2)
+	 *
+	 * This suggests computing an approximation k to log10(&d) by
+	 *
+	 * k = (i - Bias)*0.301029995663981
+	 *	+ ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+	 *
+	 * We want k to be too large rather than too small.
+	 * The error in the first-order Taylor series approximation
+	 * is in our favor, so we just round up the constant enough
+	 * to compensate for any error in the multiplication of
+	 * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+	 * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+	 * adding 1e-13 to the constant term more than suffices.
+	 * Hence we adjust the constant term to 0.1760912590558.
+	 * (We could get a more accurate k by invoking log10,
+	 *  but this is probably not worthwhile.)
+	 */
+#ifdef IBM
+	i <<= 2;
+	i += j;
+#endif
+	ds = (dval(d)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
+
+	/* correct assumption about exponent range */
+	if ((j = i) < 0)
+		j = -j;
+	if ((j -= 1077) > 0)
+		ds += j * 7e-17;
+
+	k = (int)ds;
+	if (ds < 0. && ds != k)
+		k--;	/* want k = floor(ds) */
+	k_check = 1;
+#ifdef IBM
+	j = be + bbits - 1;
+	if ( (j1 = j & 3) !=0)
+		dval(d) *= 1 << j1;
+	word0(d) += j << Exp_shift - 2 & Exp_mask;
+#else
+	word0(d) += (be + bbits - 1) << Exp_shift;
+#endif
+	if (k >= 0 && k <= Ten_pmax) {
+		if (dval(d) < tens[k])
+			k--;
+		k_check = 0;
+		}
+	j = bbits - i - 1;
+	if (j >= 0) {
+		b2 = 0;
+		s2 = j;
+		}
+	else {
+		b2 = -j;
+		s2 = 0;
+		}
+	if (k >= 0) {
+		b5 = 0;
+		s5 = k;
+		s2 += k;
+		}
+	else {
+		b2 -= k;
+		b5 = -k;
+		s5 = 0;
+		}
+	if (mode < 0 || mode > 9)
+		mode = 0;
+	try_quick = 1;
+	if (mode > 5) {
+		mode -= 4;
+		try_quick = 0;
+		}
+	else if (i >= -4 - Emin || i < Emin)
+		try_quick = 0;
+	leftright = 1;
+	ilim = ilim1 = -1;	/* Values for cases 0 and 1; done here to */
+				/* silence erroneous "gcc -Wall" warning. */
+	switch(mode) {
+		case 0:
+		case 1:
+			i = (int)(nbits * .30103) + 3;
+			ndigits = 0;
+			break;
+		case 2:
+			leftright = 0;
+			/* no break */
+		case 4:
+			if (ndigits <= 0)
+				ndigits = 1;
+			ilim = ilim1 = i = ndigits;
+			break;
+		case 3:
+			leftright = 0;
+			/* no break */
+		case 5:
+			i = ndigits + k + 1;
+			ilim = i;
+			ilim1 = i - 1;
+			if (i <= 0)
+				i = 1;
+		}
+	s = s0 = rv_alloc(ptr, i);
+	if (s == NULL)
+		return (NULL);
+
+	if ( (rdir = fpi->rounding - 1) !=0) {
+		if (rdir < 0)
+			rdir = 2;
+		if (kind & STRTOG_Neg)
+			rdir = 3 - rdir;
+		}
+
+	/* Now rdir = 0 ==> round near, 1 ==> round up, 2 ==> round down. */
+
+	if (ilim >= 0 && ilim <= Quick_max && try_quick && !rdir
+#ifndef IMPRECISE_INEXACT
+		&& k == 0
+#endif
+								) {
+
+		/* Try to get by with floating-point arithmetic. */
+
+		i = 0;
+		d2 = dval(d);
+#ifdef IBM
+		if ( (j = 11 - hi0bits(word0(d) & Frac_mask)) !=0)
+			dval(d) /= 1 << j;
+#endif
+		k0 = k;
+		ilim0 = ilim;
+		ieps = 2; /* conservative */
+		if (k > 0) {
+			ds = tens[k&0xf];
+			j = k >> 4;
+			if (j & Bletch) {
+				/* prevent overflows */
+				j &= Bletch - 1;
+				dval(d) /= bigtens[n_bigtens-1];
+				ieps++;
+				}
+			for(; j; j >>= 1, i++)
+				if (j & 1) {
+					ieps++;
+					ds *= bigtens[i];
+					}
+			}
+		else  {
+			ds = 1.;
+			if ( (j1 = -k) !=0) {
+				dval(d) *= tens[j1 & 0xf];
+				for(j = j1 >> 4; j; j >>= 1, i++)
+					if (j & 1) {
+						ieps++;
+						dval(d) *= bigtens[i];
+						}
+				}
+			}
+		if (k_check && dval(d) < 1. && ilim > 0) {
+			if (ilim1 <= 0)
+				goto fast_failed;
+			ilim = ilim1;
+			k--;
+			dval(d) *= 10.;
+			ieps++;
+			}
+		dval(eps) = ieps*dval(d) + 7.;
+		word0(eps) -= (P-1)*Exp_msk1;
+		if (ilim == 0) {
+			S = mhi = 0;
+			dval(d) -= 5.;
+			if (dval(d) > dval(eps))
+				goto one_digit;
+			if (dval(d) < -dval(eps))
+				goto no_digits;
+			goto fast_failed;
+			}
+#ifndef No_leftright
+		if (leftright) {
+			/* Use Steele & White method of only
+			 * generating digits needed.
+			 */
+			dval(eps) = ds*0.5/tens[ilim-1] - dval(eps);
+			for(i = 0;;) {
+				L = (Long)(dval(d)/ds);
+				dval(d) -= L*ds;
+				*s++ = '0' + (int)L;
+				if (dval(d) < dval(eps)) {
+					if (dval(d))
+						inex = STRTOG_Inexlo;
+					goto ret1;
+					}
+				if (ds - dval(d) < dval(eps))
+					goto bump_up;
+				if (++i >= ilim)
+					break;
+				dval(eps) *= 10.;
+				dval(d) *= 10.;
+				}
+			}
+		else {
+#endif
+			/* Generate ilim digits, then fix them up. */
+			dval(eps) *= tens[ilim-1];
+			for(i = 1;; i++, dval(d) *= 10.) {
+				if ( (L = (Long)(dval(d)/ds)) !=0)
+					dval(d) -= L*ds;
+				*s++ = '0' + (int)L;
+				if (i == ilim) {
+					ds *= 0.5;
+					if (dval(d) > ds + dval(eps))
+						goto bump_up;
+					else if (dval(d) < ds - dval(eps)) {
+						if (dval(d))
+							inex = STRTOG_Inexlo;
+						goto clear_trailing0;
+						}
+					break;
+					}
+				}
+#ifndef No_leftright
+			}
+#endif
+ fast_failed:
+		s = s0;
+		dval(d) = d2;
+		k = k0;
+		ilim = ilim0;
+		}
+
+	/* Do we have a "small" integer? */
+
+	if (be >= 0 && k <= Int_max) {
+		/* Yes. */
+		ds = tens[k];
+		if (ndigits < 0 && ilim <= 0) {
+			S = mhi = 0;
+			if (ilim < 0 || dval(d) <= 5*ds)
+				goto no_digits;
+			goto one_digit;
+			}
+		for(i = 1;; i++, dval(d) *= 10.) {
+			L = dval(d) / ds;
+			dval(d) -= L*ds;
+#ifdef Check_FLT_ROUNDS
+			/* If FLT_ROUNDS == 2, L will usually be high by 1 */
+			if (dval(d) < 0) {
+				L--;
+				dval(d) += ds;
+				}
+#endif
+			*s++ = '0' + (int)L;
+			if (dval(d) == 0.)
+				break;
+			if (i == ilim) {
+				if (rdir) {
+					if (rdir == 1)
+						goto bump_up;
+					inex = STRTOG_Inexlo;
+					goto ret1;
+					}
+				dval(d) += dval(d);
+#ifdef ROUND_BIASED
+				if (dval(d) >= ds)
+#else
+				if (dval(d) > ds || (dval(d) == ds && L & 1))
+#endif
+					{
+ bump_up:
+					inex = STRTOG_Inexhi;
+					while(*--s == '9')
+						if (s == s0) {
+							k++;
+							*s = '0';
+							break;
+							}
+					++*s++;
+					}
+				else {
+					inex = STRTOG_Inexlo;
+ clear_trailing0:
+					while(*--s == '0'){}
+					++s;
+					}
+				break;
+				}
+			}
+		goto ret1;
+		}
+
+	m2 = b2;
+	m5 = b5;
+	mhi = mlo = 0;
+	if (leftright) {
+		i = nbits - bbits;
+		if (be - i++ < fpi->emin && mode != 3 && mode != 5) {
+			/* denormal */
+			i = be - fpi->emin + 1;
+			if (mode >= 2 && ilim > 0 && ilim < i)
+				goto small_ilim;
+			}
+		else if (mode >= 2) {
+ small_ilim:
+			j = ilim - 1;
+			if (m5 >= j)
+				m5 -= j;
+			else {
+				s5 += j -= m5;
+				b5 += j;
+				m5 = 0;
+				}
+			if ((i = ilim) < 0) {
+				m2 -= i;
+				i = 0;
+				}
+			}
+		b2 += i;
+		s2 += i;
+		mhi = i2b(ptr, 1);
+		if (mhi == NULL)
+			return (NULL);
+		}
+	if (m2 > 0 && s2 > 0) {
+		i = m2 < s2 ? m2 : s2;
+		b2 -= i;
+		m2 -= i;
+		s2 -= i;
+		}
+	if (b5 > 0) {
+		if (leftright) {
+			if (m5 > 0) {
+				mhi = pow5mult(ptr, mhi, m5);
+				if (mhi == NULL)
+					return (NULL);
+				b1 = mult(ptr, mhi, b);
+				if (b1 == NULL)
+					return (NULL);
+				Bfree(ptr, b);
+				b = b1;
+				}
+			if ( (j = b5 - m5) !=0) {
+				b = pow5mult(ptr, b, j);
+				if (b == NULL)
+					return (NULL);
+				}
+			}
+		else {
+			b = pow5mult(ptr, b, b5);
+			if (b == NULL)
+				return (NULL);
+			}
+		}
+	S = i2b(ptr, 1);
+	if (S == NULL)
+		return (NULL);
+	if (s5 > 0) {
+		S = pow5mult(ptr, S, s5);
+		if (S == NULL)
+			return (NULL);
+		}
+
+	/* Check for special case that d is a normalized power of 2. */
+
+	spec_case = 0;
+	if (mode < 2) {
+		if (bbits == 1 && be0 > fpi->emin + 1) {
+			/* The special case */
+			b2++;
+			s2++;
+			spec_case = 1;
+			}
+		}
+
+	/* Arrange for convenient computation of quotients:
+	 * shift left if necessary so divisor has 4 leading 0 bits.
+	 *
+	 * Perhaps we should just compute leading 28 bits of S once
+	 * and for all and pass them and a shift to quorem, so it
+	 * can do shifts and ors to compute the numerator for q.
+	 */
+	i = ((s5 ? hi0bits(S->_x[S->_wds-1]) : ULbits - 1) - s2 - 4) & kmask;
+	m2 += i;
+	if ((b2 += i) > 0) {
+		b = lshift(ptr, b, b2);
+		if (b == NULL)
+			return (NULL);
+		}
+	if ((s2 += i) > 0) {
+		S = lshift(ptr, S, s2);
+		if (S == NULL)
+			return (NULL);
+		}
+	if (k_check) {
+		if (cmp(b,S) < 0) {
+			k--;
+			b = multadd(ptr, b, 10, 0); /* we botched the k estimate */
+			if (b == NULL)
+				return (NULL);
+			if (leftright) {
+				mhi = multadd(ptr, mhi, 10, 0);
+				if (mhi == NULL)
+					return (NULL);
+				}
+			ilim = ilim1;
+			}
+		}
+	if (ilim <= 0 && mode > 2) {
+		S = multadd(ptr, S,5,0);
+		if (S == NULL)
+			return (NULL);
+		if (ilim < 0 || cmp(b,S) <= 0) {
+			/* no digits, fcvt style */
+ no_digits:
+			k = -1 - ndigits;
+			inex = STRTOG_Inexlo;
+			goto ret;
+			}
+ one_digit:
+		inex = STRTOG_Inexhi;
+		*s++ = '1';
+		k++;
+		goto ret;
+		}
+	if (leftright) {
+		if (m2 > 0) {
+			mhi = lshift(ptr, mhi, m2);
+			if (mhi == NULL)
+				return (NULL);
+			}
+
+		/* Compute mlo -- check for special case
+		 * that d is a normalized power of 2.
+		 */
+
+		mlo = mhi;
+		if (spec_case) {
+			mhi = Balloc(ptr, mhi->_k);
+			if (mhi == NULL)
+				return (NULL);
+			Bcopy(mhi, mlo);
+			mhi = lshift(ptr, mhi, 1);
+			if (mhi == NULL)
+				return (NULL);
+			}
+
+		for(i = 1;;i++) {
+			dig = quorem(b,S) + '0';
+			/* Do we yet have the shortest decimal string
+			 * that will round to d?
+			 */
+			j = cmp(b, mlo);
+			delta = diff(ptr, S, mhi);
+			if (delta == NULL)
+				return (NULL);
+			j1 = delta->_sign ? 1 : cmp(b, delta);
+			Bfree(ptr, delta);
+#ifndef ROUND_BIASED
+			if (j1 == 0 && !mode && !(bits[0] & 1) && !rdir) {
+				if (dig == '9')
+					goto round_9_up;
+				if (j <= 0) {
+					if (b->_wds > 1 || b->_x[0])
+						inex = STRTOG_Inexlo;
+					}
+				else {
+					dig++;
+					inex = STRTOG_Inexhi;
+					}
+				*s++ = dig;
+				goto ret;
+				}
+#endif
+			if (j < 0 || (j == 0 && !mode
+#ifndef ROUND_BIASED
+							&& !(bits[0] & 1)
+#endif
+					)) {
+				if (rdir && (b->_wds > 1 || b->_x[0])) {
+					if (rdir == 2) {
+						inex = STRTOG_Inexlo;
+						goto accept;
+						}
+					while (cmp(S,mhi) > 0) {
+						*s++ = dig;
+						mhi1 = multadd(ptr, mhi, 10, 0);
+						if (mhi1 == NULL)
+							return (NULL);
+						if (mlo == mhi)
+							mlo = mhi1;
+						mhi = mhi1;
+						b = multadd(ptr, b, 10, 0);
+						if (b == NULL)
+							return (NULL);
+						dig = quorem(b,S) + '0';
+						}
+					if (dig++ == '9')
+						goto round_9_up;
+					inex = STRTOG_Inexhi;
+					goto accept;
+					}
+				if (j1 > 0) {
+					b = lshift(ptr, b, 1);
+					if (b == NULL)
+						return (NULL);
+					j1 = cmp(b, S);
+#ifdef ROUND_BIASED
+					if (j1 >= 0 /*)*/
+#else
+					if ((j1 > 0 || (j1 == 0 && dig & 1))
+#endif
+					&& dig++ == '9')
+						goto round_9_up;
+					inex = STRTOG_Inexhi;
+					}
+				if (b->_wds > 1 || b->_x[0])
+					inex = STRTOG_Inexlo;
+ accept:
+				*s++ = dig;
+				goto ret;
+				}
+			if (j1 > 0 && rdir != 2) {
+				if (dig == '9') { /* possible if i == 1 */
+ round_9_up:
+					*s++ = '9';
+					inex = STRTOG_Inexhi;
+					goto roundoff;
+					}
+				inex = STRTOG_Inexhi;
+				*s++ = dig + 1;
+				goto ret;
+				}
+			*s++ = dig;
+			if (i == ilim)
+				break;
+			b = multadd(ptr, b, 10, 0);
+			if (b == NULL)
+				return (NULL);
+			if (mlo == mhi) {
+				mlo = mhi = multadd(ptr, mhi, 10, 0);
+				if (mlo == NULL)
+					return (NULL);
+				}
+			else {
+				mlo = multadd(ptr, mlo, 10, 0);
+				if (mlo == NULL)
+					return (NULL);
+				mhi = multadd(ptr, mhi, 10, 0);
+				if (mhi == NULL)
+					return (NULL);
+				}
+			}
+		}
+	else
+		for(i = 1;; i++) {
+			*s++ = dig = quorem(b,S) + '0';
+			if (i >= ilim)
+				break;
+			b = multadd(ptr, b, 10, 0);
+			if (b == NULL)
+				return (NULL);
+			}
+
+	/* Round off last digit */
+
+	if (rdir) {
+		if (rdir == 2 || (b->_wds <= 1 && !b->_x[0]))
+			goto chopzeros;
+		goto roundoff;
+		}
+	b = lshift(ptr, b, 1);
+	if (b == NULL)
+		return (NULL);
+	j = cmp(b, S);
+#ifdef ROUND_BIASED
+	if (j >= 0)
+#else
+	if (j > 0 || (j == 0 && dig & 1))
+#endif
+		{
+ roundoff:
+		inex = STRTOG_Inexhi;
+		while(*--s == '9')
+			if (s == s0) {
+				k++;
+				*s++ = '1';
+				goto ret;
+				}
+		++*s++;
+		}
+	else {
+ chopzeros:
+		if (b->_wds > 1 || b->_x[0])
+			inex = STRTOG_Inexlo;
+		while(*--s == '0'){}
+		++s;
+		}
+ ret:
+	Bfree(ptr, S);
+	if (mhi) {
+		if (mlo && mlo != mhi)
+			Bfree(ptr, mlo);
+		Bfree(ptr, mhi);
+		}
+ ret1:
+	Bfree(ptr, b);
+	*s = 0;
+	*decpt = k + 1;
+	if (rve)
+		*rve = s;
+	*kindp |= inex;
+	return s0;
+	}
+DEF_STRONG(gdtoa);
+#endif /* _USE_GDTOA */
diff --git a/newlib/libc/stdlib/gdtoa-gmisc.c b/newlib/libc/stdlib/gdtoa-gmisc.c
new file mode 100644
index 000000000..40c3c2d13
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-gmisc.c
@@ -0,0 +1,91 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+#include <newlib.h>
+#include <sys/config.h>
+
+#ifdef _USE_GDTOA
+#include "gdtoaimp.h"
+
+ void
+#ifdef KR_headers
+rshift(b, k) Bigint *b; int k;
+#else
+rshift(Bigint *b, int k)
+#endif
+{
+	ULong *x, *x1, *xe, y;
+	int n;
+
+	x = x1 = b->_x;
+	n = k >> kshift;
+	if (n < b->_wds) {
+		xe = x + b->_wds;
+		x += n;
+		if (k &= kmask) {
+			n = ULbits - k;
+			y = *x++ >> k;
+			while(x < xe) {
+				*x1++ = (y | (*x << n)) & ALL_ON;
+				y = *x++ >> k;
+				}
+			if ((*x1 = y) !=0)
+				x1++;
+			}
+		else
+			while(x < xe)
+				*x1++ = *x++;
+		}
+	if ((b->_wds = x1 - b->_x) == 0)
+		b->_x[0] = 0;
+	}
+
+ int
+#ifdef KR_headers
+trailz(b) Bigint *b;
+#else
+trailz(Bigint *b)
+#endif
+{
+	ULong L, *x, *xe;
+	int n = 0;
+
+	x = b->_x;
+	xe = x + b->_wds;
+	for(n = 0; x < xe && !*x; x++)
+		n += ULbits;
+	if (x < xe) {
+		L = *x;
+		n += lo0bits(&L);
+		}
+	return n;
+	}
+#endif /* _USE_GDTOA */
diff --git a/newlib/libc/stdlib/gdtoa-ldtoa.c b/newlib/libc/stdlib/gdtoa-ldtoa.c
new file mode 100644
index 000000000..14b99042c
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoa-ldtoa.c
@@ -0,0 +1,159 @@
+/*	$OpenBSD: ldtoa.c,v 1.4 2016/03/09 16:28:47 deraadt Exp $	*/
+/*-
+ * Copyright (c) 2003 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <newlib.h>
+#include <sys/config.h>
+
+#ifdef _USE_GDTOA
+#include <sys/types.h>
+#include <machine/ieee.h>
+#include <float.h>
+#include <stdint.h>
+#include <limits.h>
+#include <math.h>
+#include <stdlib.h>
+#include "gdtoaimp.h"
+
+#if (LDBL_MANT_DIG > DBL_MANT_DIG)
+
+/*
+ * ldtoa() is a wrapper for gdtoa() that makes it smell like dtoa(),
+ * except that the floating point argument is passed by reference.
+ * When dtoa() is passed a NaN or infinity, it sets expt to 9999.
+ * However, a long double could have a valid exponent of 9999, so we
+ * use INT_MAX in ldtoa() instead.
+ */
+char *
+_ldtoa_r(struct _reent *ptr,
+    long double ld, int mode, int ndigits, int *decpt, int *sign, char **rve)
+{
+	FPI fpi = {
+		LDBL_MANT_DIG,			/* nbits */
+		LDBL_MIN_EXP - LDBL_MANT_DIG,	/* emin */
+		LDBL_MAX_EXP - LDBL_MANT_DIG,	/* emax */
+		FLT_ROUNDS,	       		/* rounding */
+#ifdef Sudden_Underflow	/* unused, but correct anyway */
+		1
+#else
+		0
+#endif
+	};
+	int be, kind;
+	char *ret;
+	struct ieee_ext *p = (struct ieee_ext *)&ld;
+	uint32_t bits[(LDBL_MANT_DIG + 31) / 32];
+	void *vbits = bits;
+
+	_REENT_CHECK_MP (ptr);
+
+	/* reentrancy addition to use mprec storage pool */
+	if (_REENT_MP_RESULT (ptr)) {
+		_REENT_MP_RESULT (ptr)->_k = _REENT_MP_RESULT_K (ptr);
+		_REENT_MP_RESULT (ptr)->_maxwds = 1 << _REENT_MP_RESULT_K (ptr);
+		Bfree (ptr, _REENT_MP_RESULT (ptr));
+		_REENT_MP_RESULT (ptr) = 0;
+	}
+
+	/*
+	 * gdtoa doesn't know anything about the sign of the number, so
+	 * if the number is negative, we need to swap rounding modes of
+	 * 2 (upwards) and 3 (downwards).
+	 */
+	*sign = p->ext_sign;
+	fpi.rounding ^= (fpi.rounding >> 1) & p->ext_sign;
+
+	be = p->ext_exp - (LDBL_MAX_EXP - 1) - (LDBL_MANT_DIG - 1);
+	EXT_TO_ARRAY32(p, bits);
+
+	switch (fpclassify(ld)) {
+	case FP_NORMAL:
+		kind = STRTOG_Normal;
+#ifdef EXT_IMPLICIT_NBIT
+		bits[LDBL_MANT_DIG / 32] |= 1 << ((LDBL_MANT_DIG - 1) % 32);
+#endif /* EXT_IMPLICIT_NBIT */
+		break;
+	case FP_ZERO:
+		kind = STRTOG_Zero;
+		break;
+	case FP_SUBNORMAL:
+		kind = STRTOG_Denormal;
+		be++;
+		break;
+	case FP_INFINITE:
+		kind = STRTOG_Infinite;
+		break;
+	case FP_NAN:
+		kind = STRTOG_NaN;
+		break;
+	default:
+		abort();
+	}
+
+	ret = gdtoa(ptr, &fpi, be, vbits, &kind, mode, ndigits, decpt, rve);
+	if (*decpt == -32768)
+		*decpt = INT_MAX;
+	return ret;
+}
+DEF_STRONG(_ldtoa_r);
+
+#else   /* (LDBL_MANT_DIG == DBL_MANT_DIG) */
+
+char *
+_ldtoa_r(struct _reent *ptr,
+    long double ld, int mode, int ndigits, int *decpt, int *sign,
+    char **rve)
+{
+	char *ret;
+
+	ret = _dtoa_r(ptr, (double)ld, mode, ndigits, decpt, sign, rve);
+	if (*decpt == 9999)
+		*decpt = INT_MAX;
+	return ret;
+}
+DEF_STRONG(_ldtoa_r);
+
+#endif  /* (LDBL_MANT_DIG == DBL_MANT_DIG) */
+
+/* Routine used to tell if long double is NaN or Infinity or regular number.
+   Returns:  0 = regular number
+             1 = Nan
+             2 = Infinity
+*/
+int
+_ldcheck (long double *d)
+{
+	switch (fpclassify(*d)) {
+	case FP_NAN:
+		return 1;
+	case FP_INFINITE:
+		return 2;
+	default:
+		return 0;
+	}
+}
+
+#endif /* _USE_GDTOA */
diff --git a/newlib/libc/stdlib/gdtoa.h b/newlib/libc/stdlib/gdtoa.h
index 07506aac1..f4d2a56db 100644
--- a/newlib/libc/stdlib/gdtoa.h
+++ b/newlib/libc/stdlib/gdtoa.h
@@ -32,25 +32,55 @@ THIS SOFTWARE.
 #ifndef GDTOA_H_INCLUDED
 #define GDTOA_H_INCLUDED
 
+#include <stddef.h> /* for size_t */
+#include <reent.h>
+
+#define PROTO_NORMAL(x)
+#define __BEGIN_HIDDEN_DECLS
+#define __END_HIDDEN_DECLS
+#define DEF_STRONG(x)
+
+#ifndef ULong
+#define ULong __ULong
+#endif
+
+#ifndef ANSI
+#ifdef KR_headers
+#define ANSI(x) ()
+#define Void /*nothing*/
+#else
+#define ANSI(x) x
+#define Void void
+#endif
+#endif /* ANSI */
+
+#ifndef CONST
+#ifdef KR_headers
+#define CONST /* blank */
+#else
+#define CONST const
+#endif
+#endif /* CONST */
 
  enum {	/* return values from strtodg */
-	STRTOG_Zero	= 0,
-	STRTOG_Normal	= 1,
-	STRTOG_Denormal	= 2,
-	STRTOG_Infinite	= 3,
-	STRTOG_NaN	= 4,
-	STRTOG_NaNbits	= 5,
-	STRTOG_NoNumber	= 6,
-	STRTOG_Retmask	= 7,
+	STRTOG_Zero	= 0x000,
+	STRTOG_Normal	= 0x001,
+	STRTOG_Denormal	= 0x002,
+	STRTOG_Infinite	= 0x003,
+	STRTOG_NaN	= 0x004,
+	STRTOG_NaNbits	= 0x005,
+	STRTOG_NoNumber	= 0x006,
+	STRTOG_NoMemory = 0x007,
+	STRTOG_Retmask	= 0x00f,
 
 	/* The following may be or-ed into one of the above values. */
 
-	STRTOG_Neg	= 0x08,
-	STRTOG_Inexlo	= 0x10,
-	STRTOG_Inexhi	= 0x20,
-	STRTOG_Inexact	= 0x30,
-	STRTOG_Underflow= 0x40,
-	STRTOG_Overflow	= 0x80
+	STRTOG_Inexlo	= 0x010, /* returned result rounded toward zero */
+	STRTOG_Inexhi	= 0x020, /* returned result rounded away from zero */
+	STRTOG_Inexact	= 0x030,
+	STRTOG_Underflow= 0x040,
+	STRTOG_Overflow	= 0x080,
+	STRTOG_Neg	= 0x100 /* does not affect STRTOG_Inexlo or STRTOG_Inexhi */
 	};
 
  typedef struct
@@ -69,6 +99,74 @@ enum {	/* FPI.rounding values: same as FLT_ROUNDS */
 	FPI_Round_down = 3
 	};
 
-#endif /* GDTOA_H_INCLUDED */
-
 typedef unsigned short __UShort;
+typedef struct _Bigint Bigint;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char* __dtoa  ANSI((struct _reent *ptr,
+			double d, int mode, int ndigits, int *decpt,
+			int *sign, char **rve));
+extern char* __gdtoa ANSI((struct _reent *ptr,
+			FPI *fpi, int be, ULong *bits, int *kindp,
+			int mode, int ndigits, int *decpt, char **rve));
+extern void __freedtoa ANSI((struct _reent *, char*));
+extern float  strtof ANSI((CONST char *, char **));
+extern double strtod ANSI((CONST char *, char **));
+extern int __strtodg ANSI((CONST char*, char**, FPI*, Long*, ULong*));
+char	*__hdtoa(double, const char *, int, int *, int *, char **);
+char	*__hldtoa(long double, const char *, int, int *, int *, char **);
+char	*__ldtoa(struct _reent *ptr,
+		 long double *, int, int, int *, int *, char **);
+
+PROTO_NORMAL(__dtoa);
+PROTO_NORMAL(__gdtoa);
+PROTO_NORMAL(__freedtoa);
+PROTO_NORMAL(__hdtoa);
+PROTO_NORMAL(__hldtoa);
+PROTO_NORMAL(__ldtoa);
+
+__BEGIN_HIDDEN_DECLS
+extern char*	__g_ddfmt  ANSI((char*, double*, int, size_t));
+extern char*	__g_dfmt   ANSI((char*, double*, int, size_t));
+extern char*	__g_ffmt   ANSI((char*, float*,  int, size_t));
+extern char*	__g_Qfmt   ANSI((char*, void*,   int, size_t));
+extern char*	__g_xfmt   ANSI((char*, void*,   int, size_t));
+extern char*	__g_xLfmt  ANSI((char*, void*,   int, size_t));
+
+extern int	__strtoId  ANSI((CONST char*, char**, double*, double*));
+extern int	__strtoIdd ANSI((CONST char*, char**, double*, double*));
+extern int	__strtoIf  ANSI((CONST char*, char**, float*, float*));
+extern int	__strtoIQ  ANSI((CONST char*, char**, void*, void*));
+extern int	__strtoIx  ANSI((CONST char*, char**, void*, void*));
+extern int	__strtoIxL ANSI((CONST char*, char**, void*, void*));
+extern int	__strtord  ANSI((CONST char*, char**, int, double*));
+extern int	__strtordd ANSI((CONST char*, char**, int, double*));
+extern int	__strtorf  ANSI((CONST char*, char**, int, float*));
+extern int	__strtorQ  ANSI((CONST char*, char**, int, void*));
+extern int	__strtorx  ANSI((CONST char*, char**, int, void*));
+extern int	__strtorxL ANSI((CONST char*, char**, int, void*));
+#if 1
+extern int	__strtodI  ANSI((CONST char*, char**, double*));
+extern int	__strtopd  ANSI((CONST char*, char**, double*));
+extern int	__strtopdd ANSI((CONST char*, char**, double*));
+extern int	__strtopf  ANSI((CONST char*, char**, float*));
+extern int	__strtopQ  ANSI((CONST char*, char**, void*));
+extern int	__strtopx  ANSI((CONST char*, char**, void*));
+extern int	__strtopxL ANSI((CONST char*, char**, void*));
+#else
+#define __strtopd(s,se,x) strtord(s,se,1,x)
+#define __strtopdd(s,se,x) strtordd(s,se,1,x)
+#define __strtopf(s,se,x) strtorf(s,se,1,x)
+#define __strtopQ(s,se,x) strtorQ(s,se,1,x)
+#define __strtopx(s,se,x) strtorx(s,se,1,x)
+#define __strtopxL(s,se,x) strtorxL(s,se,1,x)
+#endif
+__END_HIDDEN_DECLS
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* GDTOA_H_INCLUDED */
diff --git a/newlib/libc/stdlib/gdtoaimp.h b/newlib/libc/stdlib/gdtoaimp.h
new file mode 100644
index 000000000..f2da3fc67
--- /dev/null
+++ b/newlib/libc/stdlib/gdtoaimp.h
@@ -0,0 +1,206 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998-2000 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+****************************************************************/
+
+/* This is a variation on dtoa.c that converts arbitary binary
+   floating-point formats to and from decimal notation.  It uses
+   double-precision arithmetic internally, so there are still
+   various #ifdefs that adapt the calculations to the native
+   double-precision arithmetic (any of IEEE, VAX D_floating,
+   or IBM mainframe arithmetic).
+
+   Please send bug reports to David M. Gay (dmg at acm dot org,
+   with " at " changed at "@" and " dot " changed to ".").
+ */
+
+/* On a machine with IEEE extended-precision registers, it is
+ * necessary to specify double-precision (53-bit) rounding precision
+ * before invoking strtod or dtoa.  If the machine uses (the equivalent
+ * of) Intel 80x87 arithmetic, the call
+ *	_control87(PC_53, MCW_PC);
+ * does this with many compilers.  Whether this or another call is
+ * appropriate depends on the compiler; for this to work, it may be
+ * necessary to #include "float.h" or another system-dependent header
+ * file.
+ */
+
+/* strtod for IEEE-, VAX-, and IBM-arithmetic machines.
+ *
+ * This strtod returns a nearest machine number to the input decimal
+ * string (or sets errno to ERANGE).  With IEEE arithmetic, ties are
+ * broken by the IEEE round-even rule.  Otherwise ties are broken by
+ * biased rounding (add half and chop).
+ *
+ * Inspired loosely by William D. Clinger's paper "How to Read Floating
+ * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ *
+ *	1. We only require IEEE, IBM, or VAX double-precision
+ *		arithmetic (not IEEE double-extended).
+ *	2. We get by with floating-point arithmetic in a case that
+ *		Clinger missed -- when we're computing d * 10^n
+ *		for a small integer d and the integer n is not too
+ *		much larger than 22 (the maximum integer k for which
+ *		we can represent 10^k exactly), we may be able to
+ *		compute (d*10^k) * 10^(e-k) with just one roundoff.
+ *	3. Rather than a bit-at-a-time adjustment of the binary
+ *		result in the hard case, we use floating-point
+ *		arithmetic to determine the adjustment to within
+ *		one bit; only in really hard cases do we need to
+ *		compute a second residual.
+ *	4. Because of 3., we don't need a large table of powers of 10
+ *		for ten-to-e (just some small tables, e.g. of 10^k
+ *		for 0 <= k <= 22).
+ */
+
+/*
+ * #define IEEE_8087 for IEEE-arithmetic machines where the least
+ *	significant byte has the lowest address.
+ * #define IEEE_MC68k for IEEE-arithmetic machines where the most
+ *	significant byte has the lowest address.
+ * #define Long int on machines with 32-bit ints and 64-bit longs.
+ * #define Sudden_Underflow for IEEE-format machines without gradual
+ *	underflow (i.e., that flush to zero on underflow).
+ * #define IBM for IBM mainframe-style floating-point arithmetic.
+ * #define VAX for VAX-style floating-point arithmetic (D_floating).
+ * #define No_leftright to omit left-right logic in fast floating-point
+ *	computation of dtoa and gdtoa.  This will cause modes 4 and 5 to be
+ *	treated the same as modes 2 and 3 for some inputs.
+ * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3.
+ * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines
+ *	that use extended-precision instructions to compute rounded
+ *	products and quotients) with IBM.
+ * #define ROUND_BIASED for IEEE-format with biased rounding and arithmetic
+ *	that rounds toward +Infinity.
+ * #define ROUND_BIASED_without_Round_Up for IEEE-format with biased
+ *	rounding when the underlying floating-point arithmetic uses
+ *	unbiased rounding.  This prevent using ordinary floating-point
+ *	arithmetic when the result could be computed with one rounding error.
+ * #define Inaccurate_Divide for IEEE-format with correctly rounded
+ *	products but inaccurate quotients, e.g., for Intel i860.
+ * #define NO_LONG_LONG on machines that do not have a "long long"
+ *	integer type (of >= 64 bits).  On such machines, you can
+ *	#define Just_16 to store 16 bits per 32-bit Long when doing
+ *	high-precision integer arithmetic.  Whether this speeds things
+ *	up or slows things down depends on the machine and the number
+ *	being converted.  If long long is available and the name is
+ *	something other than "long long", #define Llong to be the name,
+ *	and if "unsigned Llong" does not work as an unsigned version of
+ *	Llong, #define #ULLong to be the corresponding unsigned type.
+ * #define KR_headers for old-style C function headers.
+ * #define Bad_float_h if your system lacks a float.h or if it does not
+ *	define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP,
+ *	FLT_RADIX, FLT_ROUNDS, and DBL_MAX.
+ * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n)
+ *	if memory is available and otherwise does something you deem
+ *	appropriate.  If MALLOC is undefined, malloc will be invoked
+ *	directly -- and assumed always to succeed.  Similarly, if you
+ *	want something other than the system's free() to be called to
+ *	recycle memory acquired from MALLOC, #define FREE to be the
+ *	name of the alternate routine.  (FREE or free is only called in
+ *	pathological cases, e.g., in a gdtoa call after a gdtoa return in
+ *	mode 3 with thousands of digits requested.)
+ * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making
+ *	memory allocations from a private pool of memory when possible.
+ *	When used, the private pool is PRIVATE_MEM bytes long:  2304 bytes,
+ *	unless #defined to be a different length.  This default length
+ *	suffices to get rid of MALLOC calls except for unusual cases,
+ *	such as decimal-to-binary conversion of a very long string of
+ *	digits.  When converting IEEE double precision values, the
+ *	longest string gdtoa can return is about 751 bytes long.  For
+ *	conversions by strtod of strings of 800 digits and all gdtoa
+ *	conversions of IEEE doubles in single-threaded executions with
+ *	8-byte pointers, PRIVATE_MEM >= 7400 appears to suffice; with
+ *	4-byte pointers, PRIVATE_MEM >= 7112 appears adequate.
+ * #define NO_INFNAN_CHECK if you do not wish to have INFNAN_CHECK
+ *	#defined automatically on IEEE systems.  On such systems,
+ *	when INFNAN_CHECK is #defined, strtod checks
+ *	for Infinity and NaN (case insensitively).
+ *	When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined,
+ *	strtodg also accepts (case insensitively) strings of the form
+ *	NaN(x), where x is a string of hexadecimal digits (optionally
+ *	preceded by 0x or 0X) and spaces; if there is only one string
+ *	of hexadecimal digits, it is taken for the fraction bits of the
+ *	resulting NaN; if there are two or more strings of hexadecimal
+ *	digits, each string is assigned to the next available sequence
+ *	of 32-bit words of fractions bits (starting with the most
+ *	significant), right-aligned in each sequence.
+ *	Unless GDTOA_NON_PEDANTIC_NANCHECK is #defined, input "NaN(...)"
+ *	is consumed even when ... has the wrong form (in which case the
+ *	"(...)" is consumed but ignored).
+ * #define MULTIPLE_THREADS if the system offers preemptively scheduled
+ *	multiple threads.  In this case, you must provide (or suitably
+ *	#define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed
+ *	by FREE_DTOA_LOCK(n) for n = 0 or 1.  (The second lock, accessed
+ *	in pow5mult, ensures lazy evaluation of only one copy of high
+ *	powers of 5; omitting this lock would introduce a small
+ *	probability of wasting memory, but would otherwise be harmless.)
+ *	You must also invoke freedtoa(s) to free the value s returned by
+ *	dtoa.  You may do so whether or not MULTIPLE_THREADS is #defined.
+ * #define IMPRECISE_INEXACT if you do not care about the setting of
+ *	the STRTOG_Inexact bits in the special case of doing IEEE double
+ *	precision conversions (which could also be done by the strtod in
+ *	dtoa.c).
+ * #define NO_HEX_FP to disable recognition of C9x's hexadecimal
+ *	floating-point constants.
+ * #define -DNO_ERRNO to suppress setting errno (in strtod.c and
+ *	strtodg.c).
+ * #define NO_STRING_H to use private versions of memcpy.
+ *	On some K&R systems, it may also be necessary to
+ *	#define DECLARE_SIZE_T in this case.
+ * #define USE_LOCALE to use the current locale's decimal_point value.
+ */
+
+#ifndef GDTOAIMP_H_INCLUDED
+#define GDTOAIMP_H_INCLUDED
+#include "mprec.h"
+#include "gdtoa.h"
+
+#ifndef __SINGLE_THREAD__
+#define MULTIPLE_THREADS
+#endif
+
+#define dtoa __dtoa
+#define gdtoa __gdtoa
+#define freedtoa __freedtoa
+
+#define dtoa_result __dtoa_result_D2A
+#define nrv_alloc __nrv_alloc_D2A
+#define quorem __quorem_D2A
+#define rshift __rshift_D2A
+#define rv_alloc __rv_alloc_D2A
+#define trailz __trailz_D2A
+
+extern char *dtoa_result;
+extern char *nrv_alloc ANSI((struct _reent *, char*, char **, int));
+extern int quorem ANSI((Bigint*, Bigint*));
+extern void rshift ANSI((Bigint*, int));
+extern char *rv_alloc ANSI((struct _reent *, int));
+extern int trailz ANSI((Bigint*));
+
+#endif /* GDTOAIMP_H_INCLUDED */
diff --git a/newlib/libc/stdlib/ldtoa.c b/newlib/libc/stdlib/ldtoa.c
index 26c61948b..36613faad 100644
--- a/newlib/libc/stdlib/ldtoa.c
+++ b/newlib/libc/stdlib/ldtoa.c
@@ -2,6 +2,10 @@
   * This program has been placed in the public domain.
   */
 
+#include <newlib.h>
+#include <sys/config.h>
+
+#ifndef _USE_GDTOA
 #include <_ansi.h>
 #include <reent.h>
 #include <string.h>
@@ -3900,3 +3904,5 @@ enan (short unsigned int *nan, int size)
   for (i = 0; i < n; i++)
     *nan++ = *p++;
 }
+
+#endif /* !_USE_GDTOA */
diff --git a/newlib/libc/stdlib/mprec.h b/newlib/libc/stdlib/mprec.h
index a1492aa38..83de932c2 100644
--- a/newlib/libc/stdlib/mprec.h
+++ b/newlib/libc/stdlib/mprec.h
@@ -26,7 +26,7 @@
 	dmg@research.att.com or research!dmg
  */
 
-#include <ieeefp.h>
+#include <machine/ieeefp.h>
 #include <math.h>
 #include <float.h>
 #include <errno.h>
diff --git a/newlib/newlib.hin b/newlib/newlib.hin
index 416d0c629..a0999512c 100644
--- a/newlib/newlib.hin
+++ b/newlib/newlib.hin
@@ -96,6 +96,9 @@
 /* Define to use type long for time_t.  */
 #undef _WANT_USE_LONG_TIME_T
 
+/* Define if using gdtoa rather than legacy ldtoa.  */
+#undef _WANT_USE_GDTOA
+
 /*
  * Iconv encodings enabled ("to" direction)
  */
-- 
2.33.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed value is incorrectly rounded
  2021-11-30 15:09                   ` Corinna Vinschen
  2021-11-30 20:38                     ` Takashi Yano
@ 2021-12-01 12:05                     ` Takashi Yano
  1 sibling, 0 replies; 25+ messages in thread
From: Takashi Yano @ 2021-12-01 12:05 UTC (permalink / raw)
  To: newlib

On Tue, 30 Nov 2021 16:09:26 +0100
Corinna Vinschen wrote:
> Could some people with other targets than Cygwin give this patch a try?
> RTEMS, anybody?

I have confirmed new gdtoa code works with a simple printf test
for the following two platforms.

- aarch64 (128bit long double with little endian)
- armv7l (64bit long double with little endian)

Actually, LDBL_MANT_DIG == DBL_MANT_DIG in armv7l platform, so
gdtoa code would not be used. To make gdtoa code be used forcibly,
a simple patch was applied for vfprintf.c and gdtoa-ldtoa.c.
Without this patch, _dtoa_r is used even for long double, which
also works as expected.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed value is incorrectly rounded
  2021-11-30 21:17                       ` Takashi Yano
@ 2021-12-06  9:53                         ` Corinna Vinschen
  2021-12-06 10:26                           ` Takashi Yano
  0 siblings, 1 reply; 25+ messages in thread
From: Corinna Vinschen @ 2021-12-06  9:53 UTC (permalink / raw)
  To: newlib

On Dec  1 06:17, Takashi Yano wrote:
> On Wed, 1 Dec 2021 05:38:01 +0900
> Takashi Yano wrote:
> > On Tue, 30 Nov 2021 16:09:26 +0100
> > Corinna Vinschen wrote:
> > > On Nov 30 19:51, Takashi Yano wrote:
> > > > On Mon, 29 Nov 2021 16:55:32 +0100
> > > > Corinna Vinschen wrote:
> > > > > On Nov 29 23:24, Takashi Yano wrote:
> > > > > > [...]
> > > > > > > > > > I have tried to import gdtoa into newlib from OpenBSD.
> > > > > > > > > > [...]
> > > > > [...struct __reent stuff...]
> > > > Thanks for checking and advice. I have done these.
> > > > 
> > > > > As for the allocations, how big are those?  If they are comparable with
> > > > > the allocation we now perform in _ldtoa_r, it might not be worth to keep
> > > > > both functions.  Some users of smaller targets might also complain that
> > > > 
> > > > I saw max 16404 byte malloc().
> > > > 
> > > > > using printf now always pulls in both variants of ldtoa, thus raising
> > > > > code size unnecessarily.  It might be better to keep the calls separate
> > > > > and only use one or the other, per target or per code size constraints,
> > > > > perhaps as a configure option.
> > > > 
> > > > I have added --enable-newlib-use-gdtoa option, which defaults
> > > > to 'yes', into newlib/configure.ac. Is this the right thing?
> > > 
> > > That patch looks good to me, at least as far as Cygwin is concerned.
> > 
> > Thanks for reviewing.
> > 
> > > This isn't essential, but it might make sense to rename __ldtoa to
> > > _ldtoa_r to avoid an extra function call, which could be time consuming
> > > and add stack pressure.  I. e., in gdtoa-ldtoa.c
> > > 
> > >   #ifdef _USE_GDTOA
> > >   // all code in gdtoa-ldtoa.c
> > >   #endif
> > > 
> > > and in ldtoa.c:
> > > 
> > >   #ifndef _USE_GDTOA
> > >   // all code in ldtoa.c
> > >   #endif
> > > 
> > > AFAICS, __ldtoa could easily be changed to take the long double argument
> > > by value because it's used in only two places, one of which just checks
> > > the value anyway.  But, as I said, not essential.  We can keep in mind
> > > for the time being.
> > 
> > Done.
> 
> Removed gdtoa-dtoa.c, which almost duplicates dtoa.c.
> 
> > > Could some people with other targets than Cygwin give this patch a try?
> > > RTEMS, anybody?
> > 
> > I would appreciate it.

Doesn't look like it, so please push, Takashi.


Thanks,
Corinna



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed value is incorrectly rounded
  2021-12-06  9:53                         ` Corinna Vinschen
@ 2021-12-06 10:26                           ` Takashi Yano
  0 siblings, 0 replies; 25+ messages in thread
From: Takashi Yano @ 2021-12-06 10:26 UTC (permalink / raw)
  To: newlib

On Mon, 6 Dec 2021 10:53:42 +0100
Corinna Vinschen wrote:
> On Dec  1 06:17, Takashi Yano wrote:
> > On Wed, 1 Dec 2021 05:38:01 +0900
> > Takashi Yano wrote:
> > > On Tue, 30 Nov 2021 16:09:26 +0100
> > > Corinna Vinschen wrote:
> > > > On Nov 30 19:51, Takashi Yano wrote:
> > > > > On Mon, 29 Nov 2021 16:55:32 +0100
> > > > > Corinna Vinschen wrote:
> > > > > > On Nov 29 23:24, Takashi Yano wrote:
> > > > > > > [...]
> > > > > > > > > > > I have tried to import gdtoa into newlib from OpenBSD.
> > > > > > > > > > > [...]
> > > > > > [...struct __reent stuff...]
> > > > > Thanks for checking and advice. I have done these.
> > > > > 
> > > > > > As for the allocations, how big are those?  If they are comparable with
> > > > > > the allocation we now perform in _ldtoa_r, it might not be worth to keep
> > > > > > both functions.  Some users of smaller targets might also complain that
> > > > > 
> > > > > I saw max 16404 byte malloc().
> > > > > 
> > > > > > using printf now always pulls in both variants of ldtoa, thus raising
> > > > > > code size unnecessarily.  It might be better to keep the calls separate
> > > > > > and only use one or the other, per target or per code size constraints,
> > > > > > perhaps as a configure option.
> > > > > 
> > > > > I have added --enable-newlib-use-gdtoa option, which defaults
> > > > > to 'yes', into newlib/configure.ac. Is this the right thing?
> > > > 
> > > > That patch looks good to me, at least as far as Cygwin is concerned.
> > > 
> > > Thanks for reviewing.
> > > 
> > > > This isn't essential, but it might make sense to rename __ldtoa to
> > > > _ldtoa_r to avoid an extra function call, which could be time consuming
> > > > and add stack pressure.  I. e., in gdtoa-ldtoa.c
> > > > 
> > > >   #ifdef _USE_GDTOA
> > > >   // all code in gdtoa-ldtoa.c
> > > >   #endif
> > > > 
> > > > and in ldtoa.c:
> > > > 
> > > >   #ifndef _USE_GDTOA
> > > >   // all code in ldtoa.c
> > > >   #endif
> > > > 
> > > > AFAICS, __ldtoa could easily be changed to take the long double argument
> > > > by value because it's used in only two places, one of which just checks
> > > > the value anyway.  But, as I said, not essential.  We can keep in mind
> > > > for the time being.
> > > 
> > > Done.
> > 
> > Removed gdtoa-dtoa.c, which almost duplicates dtoa.c.
> > 
> > > > Could some people with other targets than Cygwin give this patch a try?
> > > > RTEMS, anybody?
> > > 
> > > I would appreciate it.
> 
> Doesn't look like it, so please push, Takashi.

OK, I'll push the patch.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2021-12-06 10:26 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <CAL9Mx1uMOz2wfqbMpD_xfA=D9JkpFzVz6AR_DKHK34AvrGOP6w@mail.gmail.com>
2021-11-03 21:26 ` Fwd: gcc 11.1.0: printf("%.43f\n", 0x1.52f8a8e32e982p-140): printed value is incorrectly rounded Pavel M
2021-11-04 12:24   ` Corinna Vinschen
2021-11-04 16:48     ` Keith Packard
2021-11-04 17:27       ` Dave Nadler
2021-11-04 17:58         ` Keith Packard
2021-11-04 21:28           ` Brian Inglis
2021-11-05  2:54             ` Keith Packard
2021-11-05 16:00               ` Steven Abner
2021-11-06 12:06                 ` Steven Abner
2021-11-06 23:25                   ` Steven Abner
2021-11-08  9:57               ` Corinna Vinschen
2021-11-04 20:57       ` Corinna Vinschen
2021-11-28  7:43     ` Takashi Yano
2021-11-28 12:38       ` Takashi Yano
2021-11-28 13:16         ` Takashi Yano
2021-11-29 10:56           ` Takashi Yano
2021-11-29 14:24             ` Takashi Yano
2021-11-29 15:55               ` Corinna Vinschen
2021-11-30 10:51                 ` Takashi Yano
2021-11-30 15:09                   ` Corinna Vinschen
2021-11-30 20:38                     ` Takashi Yano
2021-11-30 21:17                       ` Takashi Yano
2021-12-06  9:53                         ` Corinna Vinschen
2021-12-06 10:26                           ` Takashi Yano
2021-12-01 12:05                     ` Takashi Yano

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).