Add g_strtod & co.
authorAlex Larsson <alexl@redhat.com>
Wed, 24 Oct 2001 18:00:11 +0000 (18:00 +0000)
committerAlexander Larsson <alexl@src.gnome.org>
Wed, 24 Oct 2001 18:00:11 +0000 (18:00 +0000)
2001-10-24  Alex Larsson  <alexl@redhat.com>

* docs/reference/glib/glib-sections.txt:
Add g_strtod & co.

* docs/reference/glib/tmpl/string_utils.sgml:
Add docs for G_ASCII_DTOSTR_BUF_SIZE.

* glib/gstrfuncs.[ch]:
Added g_ascii_strtod, g_ascii_dtostr and g_ascii_formatd.

* tests/Makefile.am:
* tests/strtod-test.c:
Add tests for g_ascii_strtod & co.

14 files changed:
ChangeLog
ChangeLog.pre-2-0
ChangeLog.pre-2-10
ChangeLog.pre-2-12
ChangeLog.pre-2-2
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
docs/reference/glib/glib-sections.txt
docs/reference/glib/tmpl/string_utils.sgml
glib/gstrfuncs.c
glib/gstrfuncs.h
tests/Makefile.am
tests/strtod-test.c [new file with mode: 0644]

index 97a5475..0817d37 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2001-10-24  Alex Larsson  <alexl@redhat.com>
+
+       * docs/reference/glib/glib-sections.txt:
+       Add g_strtod & co.
+
+       * docs/reference/glib/tmpl/string_utils.sgml:
+       Add docs for G_ASCII_DTOSTR_BUF_SIZE.
+
+       * glib/gstrfuncs.[ch]:
+       Added g_ascii_strtod, g_ascii_dtostr and g_ascii_formatd.
+
+       * tests/Makefile.am:
+       * tests/strtod-test.c:
+       Add tests for g_ascii_strtod & co.
+
 2001-10-23  Tor Lillqvist  <tml@iki.fi>
 
        * config.h.win32.in: Typo: GLIB_MICRO_VERSION and
index 97a5475..0817d37 100644 (file)
@@ -1,3 +1,18 @@
+2001-10-24  Alex Larsson  <alexl@redhat.com>
+
+       * docs/reference/glib/glib-sections.txt:
+       Add g_strtod & co.
+
+       * docs/reference/glib/tmpl/string_utils.sgml:
+       Add docs for G_ASCII_DTOSTR_BUF_SIZE.
+
+       * glib/gstrfuncs.[ch]:
+       Added g_ascii_strtod, g_ascii_dtostr and g_ascii_formatd.
+
+       * tests/Makefile.am:
+       * tests/strtod-test.c:
+       Add tests for g_ascii_strtod & co.
+
 2001-10-23  Tor Lillqvist  <tml@iki.fi>
 
        * config.h.win32.in: Typo: GLIB_MICRO_VERSION and
index 97a5475..0817d37 100644 (file)
@@ -1,3 +1,18 @@
+2001-10-24  Alex Larsson  <alexl@redhat.com>
+
+       * docs/reference/glib/glib-sections.txt:
+       Add g_strtod & co.
+
+       * docs/reference/glib/tmpl/string_utils.sgml:
+       Add docs for G_ASCII_DTOSTR_BUF_SIZE.
+
+       * glib/gstrfuncs.[ch]:
+       Added g_ascii_strtod, g_ascii_dtostr and g_ascii_formatd.
+
+       * tests/Makefile.am:
+       * tests/strtod-test.c:
+       Add tests for g_ascii_strtod & co.
+
 2001-10-23  Tor Lillqvist  <tml@iki.fi>
 
        * config.h.win32.in: Typo: GLIB_MICRO_VERSION and
index 97a5475..0817d37 100644 (file)
@@ -1,3 +1,18 @@
+2001-10-24  Alex Larsson  <alexl@redhat.com>
+
+       * docs/reference/glib/glib-sections.txt:
+       Add g_strtod & co.
+
+       * docs/reference/glib/tmpl/string_utils.sgml:
+       Add docs for G_ASCII_DTOSTR_BUF_SIZE.
+
+       * glib/gstrfuncs.[ch]:
+       Added g_ascii_strtod, g_ascii_dtostr and g_ascii_formatd.
+
+       * tests/Makefile.am:
+       * tests/strtod-test.c:
+       Add tests for g_ascii_strtod & co.
+
 2001-10-23  Tor Lillqvist  <tml@iki.fi>
 
        * config.h.win32.in: Typo: GLIB_MICRO_VERSION and
index 97a5475..0817d37 100644 (file)
@@ -1,3 +1,18 @@
+2001-10-24  Alex Larsson  <alexl@redhat.com>
+
+       * docs/reference/glib/glib-sections.txt:
+       Add g_strtod & co.
+
+       * docs/reference/glib/tmpl/string_utils.sgml:
+       Add docs for G_ASCII_DTOSTR_BUF_SIZE.
+
+       * glib/gstrfuncs.[ch]:
+       Added g_ascii_strtod, g_ascii_dtostr and g_ascii_formatd.
+
+       * tests/Makefile.am:
+       * tests/strtod-test.c:
+       Add tests for g_ascii_strtod & co.
+
 2001-10-23  Tor Lillqvist  <tml@iki.fi>
 
        * config.h.win32.in: Typo: GLIB_MICRO_VERSION and
index 97a5475..0817d37 100644 (file)
@@ -1,3 +1,18 @@
+2001-10-24  Alex Larsson  <alexl@redhat.com>
+
+       * docs/reference/glib/glib-sections.txt:
+       Add g_strtod & co.
+
+       * docs/reference/glib/tmpl/string_utils.sgml:
+       Add docs for G_ASCII_DTOSTR_BUF_SIZE.
+
+       * glib/gstrfuncs.[ch]:
+       Added g_ascii_strtod, g_ascii_dtostr and g_ascii_formatd.
+
+       * tests/Makefile.am:
+       * tests/strtod-test.c:
+       Add tests for g_ascii_strtod & co.
+
 2001-10-23  Tor Lillqvist  <tml@iki.fi>
 
        * config.h.win32.in: Typo: GLIB_MICRO_VERSION and
index 97a5475..0817d37 100644 (file)
@@ -1,3 +1,18 @@
+2001-10-24  Alex Larsson  <alexl@redhat.com>
+
+       * docs/reference/glib/glib-sections.txt:
+       Add g_strtod & co.
+
+       * docs/reference/glib/tmpl/string_utils.sgml:
+       Add docs for G_ASCII_DTOSTR_BUF_SIZE.
+
+       * glib/gstrfuncs.[ch]:
+       Added g_ascii_strtod, g_ascii_dtostr and g_ascii_formatd.
+
+       * tests/Makefile.am:
+       * tests/strtod-test.c:
+       Add tests for g_ascii_strtod & co.
+
 2001-10-23  Tor Lillqvist  <tml@iki.fi>
 
        * config.h.win32.in: Typo: GLIB_MICRO_VERSION and
index 97a5475..0817d37 100644 (file)
@@ -1,3 +1,18 @@
+2001-10-24  Alex Larsson  <alexl@redhat.com>
+
+       * docs/reference/glib/glib-sections.txt:
+       Add g_strtod & co.
+
+       * docs/reference/glib/tmpl/string_utils.sgml:
+       Add docs for G_ASCII_DTOSTR_BUF_SIZE.
+
+       * glib/gstrfuncs.[ch]:
+       Added g_ascii_strtod, g_ascii_dtostr and g_ascii_formatd.
+
+       * tests/Makefile.am:
+       * tests/strtod-test.c:
+       Add tests for g_ascii_strtod & co.
+
 2001-10-23  Tor Lillqvist  <tml@iki.fi>
 
        * config.h.win32.in: Typo: GLIB_MICRO_VERSION and
index d42467a..34d5112 100644 (file)
@@ -922,6 +922,12 @@ g_strncasecmp
 
 <SUBSECTION>
 g_strreverse
+
+<SUBSECTION>
+G_ASCII_DTOSTR_BUF_SIZE
+g_ascii_strtod
+g_ascii_dtostr
+g_ascii_formatd
 g_strtod
 
 <SUBSECTION>
index 065b0b4..0135b3b 100644 (file)
@@ -562,19 +562,68 @@ For example, g_strreverse ("abcdef") will result in "fedcba".
 @Returns: the same pointer passed in as @string.
 
 
+<!-- ##### MACRO G_ASCII_DTOSTR_BUF_SIZE ##### -->
+<para>
+A good size for a buffer to be passed into <function>g_ascii_dtostr</function>.
+It is guaranteed to be enough for all output of that function on systems with
+ 64bit IEEE compatible doubles.
+</para>
+<para>
+The typical usage would be something like:
+</para>
+<para>
+<literal>
+  char buf[G_ASCII_DTOSTR_BUF_SIZE];
+
+  fprintf (out, "value=%s\n", g_ascii_dtostr (buf, sizeof (buf), value));
+</literal>
+</para>
+
+
+
+<!-- ##### FUNCTION g_ascii_strtod ##### -->
+<para>
+
+</para>
+
+@nptr: 
+@endptr: 
+@Returns: 
+
+
+<!-- ##### FUNCTION g_ascii_dtostr ##### -->
+<para>
+
+</para>
+
+@buffer: 
+@buf_len: 
+@d: 
+@Returns: 
+<!-- # Unused Parameters # -->
+@format: 
+
+
+<!-- ##### FUNCTION g_ascii_formatd ##### -->
+<para>
+
+</para>
+
+@buffer: 
+@buf_len: 
+@format: 
+@d: 
+@Returns: 
+
+
 <!-- ##### FUNCTION g_strtod ##### -->
 <para>
-Converts a string to a gdouble value.
-It calls the standard <function>strtod()</function> function
-to handle the conversion, but if the string is not completely converted
-it attempts the conversion again in the "C" locale, and returns the best
-match.
+
 </para>
 
-@nptr: the string to convert to a numeric value.
-@endptr: if non-NULL, it returns the character after the last character used
-in the conversion.
-@Returns: the gdouble value.
+@nptr: 
+@endptr: 
+@Returns: 
 
 
 <!-- ##### FUNCTION g_strchug ##### -->
index d05360a..e53f59d 100644 (file)
@@ -39,6 +39,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <locale.h>
+#include <errno.h>
 #include <ctype.h>             /* For tolower() */
 #if !defined (HAVE_STRSIGNAL) || !defined(NO_SYS_SIGLIST_DECL)
 #include <signal.h>
@@ -253,9 +254,29 @@ g_strconcat (const gchar *string1, ...)
   return concat;
 }
 
+/**
+ * g_strtod:
+ * @nptr:    the string to convert to a numeric value.
+ * @endptr:  if non-NULL, it returns the character after
+ *           the last character used in the conversion.
+ * 
+ * Converts a string to a gdouble value.
+ * It calls the standard strtod() function to handle the conversion, but
+ * if the string is not completely converted it attempts the conversion
+ * again with @g_ascii_strtod, and returns the best match.
+ *
+ * This function should seldom be used. The normal situation when reading
+ * numbers not for human consumption is to use @g_ascii_strtod(). Only when
+ * you know that you must expect both locale formated and C formated numbers
+ * should you use this. Make sure that you don't pass strings such as comma
+ * separated lists of values, since the commas may be interpreted as a decimal
+ * point in some locales, causing unexpected results.
+ * 
+ * Return value: the gdouble value.
+ **/
 gdouble
 g_strtod (const gchar *nptr,
-         gchar **endptr)
+         gchar      **endptr)
 {
   gchar *fail_pos_1;
   gchar *fail_pos_2;
@@ -270,15 +291,7 @@ g_strtod (const gchar *nptr,
   val_1 = strtod (nptr, &fail_pos_1);
 
   if (fail_pos_1 && fail_pos_1[0] != 0)
-    {
-      gchar *old_locale;
-
-      old_locale = g_strdup (setlocale (LC_NUMERIC, NULL));
-      setlocale (LC_NUMERIC, "C");
-      val_2 = strtod (nptr, &fail_pos_2);
-      setlocale (LC_NUMERIC, old_locale);
-      g_free (old_locale);
-    }
+    val_2 = g_ascii_strtod (nptr, &fail_pos_2);
 
   if (!fail_pos_1 || fail_pos_1[0] == 0 || fail_pos_1 >= fail_pos_2)
     {
@@ -294,6 +307,278 @@ g_strtod (const gchar *nptr,
     }
 }
 
+/**
+ * g_ascii_strtod:
+ * @nptr:    the string to convert to a numeric value.
+ * @endptr:  if non-NULL, it returns the character after
+ *           the last character used in the conversion.
+ * 
+ * Converts a string to a gdouble value.
+ * This function behaves like the standard strtod() function
+ * does in the C locale. It does this without actually
+ * changing the current locale, since that would not be
+ * thread-safe.
+ *
+ * This function is typically used when reading configuration
+ * files or other non-user input that should be locale dependent.
+ * To handle input from the user you should normally use the
+ * locale-sensitive system strtod function.
+ *
+ * To convert from a string to double in a locale-insensitive
+ * way, use @g_ascii_dtostr.
+ *
+ * If the correct value would cause overflow, plus or minus HUGE_VAL
+ * is returned (according to the sign of the value), and ERANGE is
+ * stored in errno. If the correct value would cause underflow,
+ * zero is returned and ERANGE is stored in errno.
+ * 
+ * This function resets errno before calling strtod() so that
+ * you can reliably detect overflow and underflow.
+ *
+ * Return value: the gdouble value.
+ **/
+gdouble
+g_ascii_strtod (const gchar *nptr,
+               gchar      **endptr)
+{
+  gchar *fail_pos;
+  gdouble val;
+  struct lconv *locale_data;
+  const char *decimal_point;
+  int decimal_point_len;
+  const char *p, *decimal_point_pos;
+  const char *end = NULL; /* Silence gcc */
+
+  g_return_val_if_fail (nptr != NULL, 0);
+
+  fail_pos = NULL;
+
+  locale_data = localeconv ();
+  decimal_point = locale_data->decimal_point;
+  decimal_point_len = strlen (decimal_point);
+
+  g_assert (decimal_point_len != 0);
+  
+  decimal_point_pos = NULL;
+  if (decimal_point[0] != '.' ||
+      decimal_point[1] != 0)
+    {
+      p = nptr;
+      /* Skip leading space */
+      while (isspace ((guchar)*p))
+       p++;
+      
+      /* Skip leading optional sign */
+      if (*p == '+' || *p == '-')
+       p++;
+      
+      if (p[0] == '0' &&
+         (p[1] == 'x' || p[1] == 'X'))
+       {
+         p += 2;
+         /* HEX - find the (optional) decimal point */
+         
+         while (isxdigit ((guchar)*p))
+           p++;
+         
+         if (*p == '.')
+           {
+             decimal_point_pos = p++;
+             
+             while (isxdigit ((guchar)*p))
+               p++;
+             
+             if (*p == 'p' || *p == 'P')
+               p++;
+             if (*p == '+' || *p == '-')
+               p++;
+             while (isdigit ((guchar)*p))
+               p++;
+             end = p;
+           }
+       }
+      else
+       {
+         while (isdigit ((guchar)*p))
+           p++;
+         
+         if (*p == '.')
+           {
+             decimal_point_pos = p++;
+             
+             while (isdigit ((guchar)*p))
+               p++;
+             
+             if (*p == 'e' || *p == 'E')
+               p++;
+             if (*p == '+' || *p == '-')
+               p++;
+             while (isdigit ((guchar)*p))
+               p++;
+             end = p;
+           }
+       }
+      /* For the other cases, we need not convert the decimal point */
+    }
+
+  /* Set errno to zero, so that we can distinguish zero results
+     and underflows */
+  errno = 0;
+  
+  if (decimal_point_pos)
+    {
+      char *copy, *c;
+
+      /* We need to convert the '.' to the locale specific decimal point */
+      copy = g_malloc (end - nptr + 1 + decimal_point_len);
+      
+      c = copy;
+      memcpy (c, nptr, decimal_point_pos - nptr);
+      c += decimal_point_pos - nptr;
+      memcpy (c, decimal_point, decimal_point_len);
+      c += decimal_point_len;
+      memcpy (c, decimal_point_pos + 1, end - (decimal_point_pos + 1));
+      c += end - (decimal_point_pos + 1);
+      *c = 0;
+
+      val = strtod (copy, &fail_pos);
+
+      if (fail_pos)
+       {
+         if (fail_pos > decimal_point_pos)
+           fail_pos = (char *)nptr + (fail_pos - copy) - (decimal_point_len - 1);
+         else
+           fail_pos = (char *)nptr + (fail_pos - copy);
+       }
+      
+      g_free (copy);
+         
+    }
+  else
+    val = strtod (nptr, &fail_pos);
+
+  if (endptr)
+    *endptr = fail_pos;
+  
+  return val;
+}
+
+/**
+ * g_ascii_dtostr:
+ * @buffer: A buffer to place the resulting string in
+ * @buf_len: The length of the buffer.
+ * @d: The double to convert
+ *
+ * Converts a double to a string, using the '.' as
+ * decimal_point. 
+ * 
+ * This functions generates enough precision that converting
+ * the string back using @g_strtod gives the same machine-number
+ * (on machines with IEEE compatible 64bit doubles). It is
+ * guaranteed that the size of the resulting string will never
+ * be larger than @G_ASCII_DTOSTR_BUF_SIZE bytes.
+ *
+ * Return value: The pointer to the buffer with the converted string.
+ **/
+gchar *
+g_ascii_dtostr (gchar       *buffer,
+               gint         buf_len,
+               gdouble      d)
+{
+  return g_ascii_formatd (buffer, buf_len, "%.17g", d);
+}
+
+/**
+ * g_ascii_formatd:
+ * @buffer: A buffer to place the resulting string in
+ * @buf_len: The length of the buffer.
+ * @format: The printf-style format to use for the
+ *          code to use for converting. 
+ * @d: The double to convert
+ *
+ * Converts a double to a string, using the '.' as
+ * decimal_point. To format the number you pass in
+ * a printf-style formating string. Allowed conversion
+ * specifiers are eEfFgG. 
+ * 
+ * If you just want to want to serialize the value into a
+ * string, use @g_ascii_dtostr.
+ *
+ * Return value: The pointer to the buffer with the converted string.
+ **/
+gchar *
+g_ascii_formatd (gchar       *buffer,
+                gint         buf_len,
+                const gchar *format,
+                gdouble      d)
+{
+  struct lconv *locale_data;
+  const char *decimal_point;
+  int decimal_point_len;
+  gchar *p;
+  int rest_len;
+  gchar format_char;
+
+  g_return_val_if_fail (buffer != NULL, NULL);
+  g_return_val_if_fail (format[0] == '%', NULL);
+  g_return_val_if_fail (strpbrk (format + 1, "'l%") == NULL, NULL);
+  format_char = format[strlen (format) - 1];
+  
+  g_return_val_if_fail (format_char == 'e' || format_char == 'E' ||
+                       format_char == 'f' || format_char == 'F' ||
+                       format_char == 'g' || format_char == 'G',
+                       NULL);
+
+  if (format[0] != '%')
+    return NULL;
+
+  if (strpbrk (format + 1, "'l%"))
+    return NULL;
+
+  if (!(format_char == 'e' || format_char == 'E' ||
+       format_char == 'f' || format_char == 'F' ||
+       format_char == 'g' || format_char == 'G'))
+    return NULL;
+
+      
+  g_snprintf (buffer, buf_len, format, d);
+
+  locale_data = localeconv ();
+  decimal_point = locale_data->decimal_point;
+  decimal_point_len = strlen (decimal_point);
+
+  g_assert (decimal_point_len != 0);
+
+  if (decimal_point[0] != '.' ||
+      decimal_point[1] != 0)
+    {
+      p = buffer;
+
+      if (*p == '+' || *p == '-')
+       p++;
+
+      while (isdigit ((guchar)*p))
+       p++;
+
+      if (strncmp (p, decimal_point, decimal_point_len) == 0)
+       {
+         *p = '.';
+         p++;
+         if (decimal_point_len > 1) {
+           rest_len = strlen (p + (decimal_point_len-1));
+           memmove (p, p + (decimal_point_len-1),
+                    rest_len);
+           p[rest_len] = 0;
+           
+         }
+       }
+    }
+  
+  return buffer;
+}
+
+
 G_CONST_RETURN gchar*
 g_strerror (gint errnum)
 {
index 7aedde1..0c4f59e 100644 (file)
@@ -93,13 +93,11 @@ gint                  g_ascii_xdigit_value (gchar    c) G_GNUC_CONST;
  */
 #define         G_STR_DELIMITERS       "_-|> <."
 gchar*               g_strdelimit     (gchar        *string,
-                                       const gchar *delimiters,
+                                       const gchar  *delimiters,
                                        gchar         new_delimiter);
-gchar*               g_strcanon       (gchar       *string,
-                                       const gchar *valid_chars,
-                                       gchar        substitutor);
-gdouble                      g_strtod         (const gchar *nptr,
-                                       gchar       **endptr);
+gchar*               g_strcanon       (gchar        *string,
+                                       const gchar  *valid_chars,
+                                       gchar         substitutor);
 G_CONST_RETURN gchar* g_strerror       (gint         errnum) G_GNUC_CONST;
 G_CONST_RETURN gchar* g_strsignal      (gint         signum) G_GNUC_CONST;
 gchar*               g_strreverse     (gchar        *string);
@@ -118,6 +116,24 @@ gchar *               g_strrstr_len    (const gchar  *haystack,
                                        gssize        haystack_len,
                                        const gchar  *needle);
 
+/* String to/from double conversion functions */
+
+gdouble                      g_strtod         (const gchar  *nptr,
+                                       gchar       **endptr);
+gdouble                      g_ascii_strtod   (const gchar  *nptr,
+                                       gchar       **endptr);
+/* 29 bytes should enough for all possible values that
+ * g_ascii_dtostr can produce.
+ * Then add 10 for good measure */
+#define G_ASCII_DTOSTR_BUF_SIZE (29 + 10)
+gchar *               g_ascii_dtostr   (gchar        *buffer,
+                                       gint          buf_len,
+                                       gdouble       d);
+gchar *               g_ascii_formatd  (gchar        *buffer,
+                                       gint          buf_len,
+                                       const gchar  *format,
+                                       gdouble       d);
+
 /* removes leading spaces */
 gchar*                g_strchug        (gchar        *string);
 /* removes trailing spaces */
index 5a2910d..5160be6 100644 (file)
@@ -72,6 +72,7 @@ test_programs =                                       \
        spawn-test                              \
        strfunc-test                            \
        string-test                             \
+       strtod-test                             \
        thread-test                             \
        threadpool-test                         \
        tree-test                               \
@@ -114,6 +115,7 @@ slist_test_LDADD = $(progs_LDADD)
 spawn_test_LDADD = $(progs_LDADD)
 strfunc_test_LDADD = $(progs_LDADD)
 string_test_LDADD = $(progs_LDADD)
+strtod_test_LDADD = $(progs_LDADD) -lm
 thread_test_LDADD = $(thread_LDADD)
 threadpool_test_LDADD = $(thread_LDADD)
 tree_test_LDADD = $(progs_LDADD)
diff --git a/tests/strtod-test.c b/tests/strtod-test.c
new file mode 100644 (file)
index 0000000..bdb7017
--- /dev/null
@@ -0,0 +1,53 @@
+#include <glib.h>
+#include <locale.h>
+#include <string.h>
+#include <math.h>
+
+void
+test_string (char *number, double res)
+{
+  gdouble d;
+  char *locales[] = {"sv_SE", "en_US", "fa_IR", "C"};
+  int l;
+  char *end;
+
+  for (l = 0; l < G_N_ELEMENTS (locales); l++)
+    {
+      setlocale (LC_NUMERIC, locales[l]);
+      d = g_ascii_strtod (number, &end);
+      if (d != res)
+       g_print ("g_ascii_strtod for locale %s failed\n", locales[l]);
+      if (*end != 0)
+       g_print ("g_ascii_strtod for locale %s endptr was wrong\n", locales[l]);
+    }
+}
+
+
+int 
+main ()
+{
+  gdouble d;
+  char buffer[G_ASCII_DTOSTR_BUF_SIZE];
+
+  test_string ("123.123", 123.123);
+  test_string ("123.123e2", 123.123e2);
+  test_string ("123.123e-2", 123.123e-2);
+  test_string ("-123.123", -123.123);
+  test_string ("-123.123e2", -123.123e2);
+  test_string ("-123.123e-2", -123.123e-2);
+  
+  d = 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0;
+  g_assert (d == g_ascii_strtod (g_ascii_dtostr (buffer, sizeof (buffer), d), NULL));
+
+  d = -179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0;
+  g_assert (d == g_ascii_strtod (g_ascii_dtostr (buffer, sizeof (buffer), d), NULL));
+  
+  d = pow (2.0, -1024.1);
+  g_assert (d == g_ascii_strtod (g_ascii_dtostr (buffer, sizeof (buffer), d), NULL));
+  
+  d = -pow (2.0, -1024.1);
+  g_assert (d == g_ascii_strtod (g_ascii_dtostr (buffer, sizeof (buffer), d), NULL));
+  
+
+  return 0;
+}