Use new Gnulib function dtoastr() to format short, accurate real numbers.
authorBen Pfaff <blp@cs.stanford.edu>
Mon, 14 Feb 2011 06:20:45 +0000 (22:20 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Tue, 15 Feb 2011 21:11:15 +0000 (13:11 -0800)
%.*g with DBL_DIG + 1 as argument is simple but in rare cases it fails to
accurately format a real number.  The recently added Gnulib routine
dtoastr() always formats a real number accurately, so switch to using it
for these cases.

Smake
src/data/csv-file-writer.c
src/ui/syntax-gen.c

diff --git a/Smake b/Smake
index 5e05933dfafd9a4d85f1439d64d72d0cfa30179d..6d54f5b730ca0f212c67f670f7407b98ebeec728 100644 (file)
--- a/Smake
+++ b/Smake
@@ -17,6 +17,7 @@ GNULIB_MODULES = \
        crypto/md4 \
        crypto/md5 \
        dirname \
+       dtoastr \
        environ \
        fatal-signal \
        fcntl \
index 70568c3e1d4dfe35fc10857d0aaf6ee1fe654c72..11b7429cbb60c0b32b8692a29173a8219e420d33 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2010 Free Software Foundation, Inc.
+   Copyright (C) 2010, 2011 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -45,6 +45,8 @@
 #include "libpspp/message.h"
 #include "libpspp/str.h"
 
+#include "gl/ftoastr.h"
+#include "gl/minmax.h"
 #include "gl/unlocked-io.h"
 #include "gl/xalloc.h"
 
@@ -280,7 +282,7 @@ csv_write_var__ (struct csv_writer *w, const struct csv_var *cv,
     csv_output_format (w, cv, value);
   else
     {
-      char s[128];
+      char s[MAX (DBL_STRLEN_BOUND, 128)];
 
       switch (cv->format.type)
         {
@@ -306,7 +308,7 @@ csv_write_var__ (struct csv_writer *w, const struct csv_var *cv,
         case FMT_RBHEX:
         case FMT_WKDAY:
         case FMT_MONTH:
-          snprintf (s, sizeof s, "%.*g", DBL_DIG + 1, value->f);
+          dtoastr (s, sizeof s, 0, 0, value->f);
           if (w->opts.decimal != '.')
             {
               char *cp = strchr (s, '.');
index 35de44da0dc9dfe71e1ba9cb3ae2a19883b47192..9221eae4d6a554c09e87275884ab496d35980ba8 100644 (file)
@@ -30,6 +30,8 @@
 #include "libpspp/message.h"
 #include "libpspp/str.h"
 
+#include "gl/ftoastr.h"
+
 /* Appends to OUTPUT a pair of hex digits for each byte in IN. */
 static void
 syntax_gen_hex_digits (struct string *output, struct substring in)
@@ -172,18 +174,10 @@ syntax_gen_number (struct string *output,
     ds_put_cstr (output, "SYSMIS");
   else
     {
-      /* FIXME: This should consistently yield precisely the same
-         value as NUMBER on input, but its results for values
-         cannot be exactly represented in decimal are ugly: many
-         of them will have far more decimal digits than are
-         needed.  The free-format floating point output routine
-         from Steele and White, "How to Print Floating-Point
-         Numbers Accurately" is really what we want.  The MPFR
-         library has an implementation of this, or equivalent
-         functionality, in its mpfr_strtofr routine, but it would
-         not be nice to make PSPP depend on this.  Probably, we
-         should implement something equivalent to it. */
-      ds_put_format (output, "%.*g", DBL_DIG + 1, number);
+      char s[DBL_BUFSIZE_BOUND];
+
+      dtoastr (s, sizeof s, 0, 0, number);
+      ds_put_cstr (output, s);
     }
 }