Allow users to set the precision of output statistics.
[pspp-builds.git] / src / language / stats / examine.q
index abbf9fc3890aada913b5b771fb57353d2362dd4d..febb60fedeeb5d5146253c5b3c434bece64ff79e 100644 (file)
@@ -1,21 +1,18 @@
-/* PSPP - EXAMINE data for normality . -*-c-*-
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2004, 2009 Free Software Foundation, Inc.
 
-Copyright (C) 2004 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
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
 
-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 the Free Software Foundation; either version 2 of the
-License, or (at your option) any later version.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA. */
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
 
@@ -26,18 +23,18 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 #include <stdlib.h>
 
 #include <data/case.h>
-#include <data/casefile.h>
+#include <data/casegrouper.h>
+#include <data/casereader.h>
 #include <data/dictionary.h>
 #include <data/procedure.h>
 #include <data/value-labels.h>
 #include <data/variable.h>
+#include <data/format.h>
 #include <language/command.h>
 #include <language/dictionary/split-file.h>
 #include <language/lexer/lexer.h>
-#include <libpspp/alloc.h>
 #include <libpspp/compiler.h>
 #include <libpspp/hash.h>
-#include <libpspp/magic.h>
 #include <libpspp/message.h>
 #include <libpspp/misc.h>
 #include <libpspp/str.h>
@@ -50,6 +47,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 #include <output/table.h>
 
 #include "minmax.h"
+#include "xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -84,7 +82,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 
 static struct cmd_examine cmd;
 
-static struct variable **dependent_vars;
+static const struct variable **dependent_vars;
 
 static size_t n_dependent_vars;
 
@@ -116,19 +114,20 @@ static int examine_parse_independent_vars (struct lexer *lexer, const struct dic
 
 
 /* Output functions */
-static void show_summary (struct variable **dependent_var, int n_dep_var,
-                        const struct factor *f);
+static void show_summary (const struct variable **dependent_var, int n_dep_var,
+                         const struct dictionary *dict,
+                         const struct factor *f);
 
-static void show_extremes (struct variable **dependent_var,
-                         int n_dep_var,
-                         const struct factor *factor,
-                         int n_extremities);
+static void show_extremes (const struct variable **dependent_var,
+                          int n_dep_var,
+                          const struct factor *factor,
+                          int n_extremities);
 
-static void show_descriptives (struct variable **dependent_var,
+static void show_descriptives (const struct variable **dependent_var,
                              int n_dep_var,
                              struct factor *factor);
 
-static void show_percentiles (struct variable **dependent_var,
+static void show_percentiles (const struct variable **dependent_var,
                             int n_dep_var,
                             struct factor *factor);
 
@@ -152,28 +151,30 @@ void box_plot_variables (const struct factor *fctr,
 
 
 /* Per Split function */
-static bool run_examine (const struct ccase *,
-                        const struct casefile *cf, void *cmd_, const struct dataset *);
+static void run_examine (struct cmd_examine *, struct casereader *,
+                         struct dataset *);
 
-static void output_examine (void);
+static void output_examine (const struct dictionary *dict);
 
 
 void factor_calc (const struct ccase *c, int case_no,
-                 double weight, int case_missing);
+                 double weight, bool case_missing);
 
 
 /* Represent a factor as a string, so it can be
    printed in a human readable fashion */
-const char * factor_to_string (const struct factor *fctr,
+static void factor_to_string (const struct factor *fctr,
                               const struct factor_statistics *fs,
-                              const struct variable *var);
-
+                             const struct variable *var,
+                             struct string *str
+                             );
 
 /* Represent a factor as a string, so it can be
    printed in a human readable fashion,
    but sacrificing some readablility for the sake of brevity */
-const char *factor_to_string_concise (const struct factor *fctr,
-                                    struct factor_statistics *fs);
+static void factor_to_string_concise (const struct factor *fctr,
+                                     const struct factor_statistics *fs,
+                                     struct string *);
 
 
 
@@ -193,6 +194,8 @@ static short sbc_percentile;
 int
 cmd_examine (struct lexer *lexer, struct dataset *ds)
 {
+  struct casegrouper *grouper;
+  struct casereader *group;
   bool ok;
 
   subc_list_double_create (&percentile_list);
@@ -222,7 +225,11 @@ cmd_examine (struct lexer *lexer, struct dataset *ds)
       subc_list_double_push (&percentile_list, 75);
     }
 
-  ok = multipass_procedure_with_splits (ds, run_examine, &cmd);
+  grouper = casegrouper_create_splits (proc_open (ds), dataset_dict (ds));
+  while (casegrouper_get_next_group (grouper, &group))
+    run_examine (&cmd, group, ds);
+  ok = casegrouper_destroy (grouper);
+  ok = proc_commit (ds) && ok;
 
   if ( totals )
     {
@@ -255,14 +262,14 @@ cmd_examine (struct lexer *lexer, struct dataset *ds)
 
 /* Show all the appropriate tables */
 static void
-output_examine (void)
+output_examine (const struct dictionary *dict)
 {
   struct factor *fctr;
 
   /* Show totals if appropriate */
   if ( ! cmd.sbc_nototal || factors == 0 )
     {
-      show_summary (dependent_vars, n_dependent_vars, 0);
+      show_summary (dependent_vars, n_dependent_vars, dict, 0);
 
       if ( cmd.sbc_statistics )
        {
@@ -329,7 +336,7 @@ output_examine (void)
   fctr = factors;
   while ( fctr )
     {
-      show_summary (dependent_vars, n_dependent_vars, fctr);
+      show_summary (dependent_vars, n_dependent_vars, dict, fctr);
 
       if ( cmd.sbc_statistics )
        {
@@ -367,10 +374,12 @@ output_examine (void)
 
              for ( fs = fctr->fs ; *fs ; ++fs )
                {
-                 const char *s = factor_to_string (fctr, *fs, dependent_vars[v]);
+                 struct string str;
+                 ds_init_empty (&str);
+                 factor_to_string (fctr, *fs, dependent_vars[v], &str);
 
                  if ( cmd.a_plot[XMN_PLT_NPPLOT] )
-                   np_plot (& (*fs)->m[v], s);
+                   np_plot (& (*fs)->m[v], ds_cstr (&str));
 
                  if ( cmd.a_plot[XMN_PLT_HISTOGRAM] )
                    {
@@ -381,9 +390,11 @@ output_examine (void)
                      normal.stddev = (*fs)->m[v].stddev;
 
                      histogram_plot ((*fs)->m[v].histogram,
-                                    s,  &normal, 0);
+                                    ds_cstr (&str) ,  &normal, 0);
                    }
 
+                 ds_destroy (&str);
+
                } /* for ( fs .... */
 
            } /* for ( v = 0 ..... */
@@ -525,7 +536,7 @@ xmn_custom_variables (struct lexer *lexer, struct dataset *ds, struct cmd_examin
       return 2;
     }
 
-  if (!parse_variables (lexer, dict, &dependent_vars, &n_dependent_vars,
+  if (!parse_variables_const (lexer, dict, &dependent_vars, &n_dependent_vars,
                        PV_NO_DUPLICATE | PV_NUMERIC | PV_NO_SCRATCH) )
     {
       free (dependent_vars);
@@ -612,28 +623,28 @@ examine_parse_independent_vars (struct lexer *lexer, const struct dictionary *di
 
 
 
-void populate_percentiles (struct tab_table *tbl, int col, int row,
-                         const struct metrics *m);
-
-void populate_descriptives (struct tab_table *t, int col, int row,
-                          const struct metrics *fs);
-
-void populate_extremes (struct tab_table *t, int col, int row, int n,
-                      const struct metrics *m);
+static void populate_percentiles (struct tab_table *tbl, int col, int row,
+                                 const struct metrics *m);
 
-void populate_summary (struct tab_table *t, int col, int row,
-                     const struct metrics *m);
+static void populate_descriptives (struct tab_table *t, int col, int row,
+                                  const struct variable *,
+                                  const struct metrics *fs);
 
+static void populate_extremes (struct tab_table *t, int col, int row, int n,
+                              const struct variable *var,
+                              const struct metrics *m);
 
+static void populate_summary (struct tab_table *t, int col, int row,
+                             const struct dictionary *dict,
+                             const struct metrics *m);
 
 
-static bool bad_weight_warn = true;
 
 
 /* Perform calculations for the sub factors */
 void
 factor_calc (const struct ccase *c, int case_no, double weight,
-            int case_missing)
+            bool case_missing)
 {
   size_t v;
   struct factor *fctr = factors;
@@ -694,7 +705,7 @@ factor_calc (const struct ccase *c, int case_no, double weight,
          if (case_missing || var_is_value_missing (var, val, exclude_values))
            {
              free (val);
-             continue;
+             val = NULL;
            }
 
          metrics_calc ( & (*foo)->m[v], val, weight, case_no);
@@ -706,23 +717,31 @@ factor_calc (const struct ccase *c, int case_no, double weight,
     }
 }
 
-static bool
-run_examine (const struct ccase *first, const struct casefile *cf,
-           void *cmd_, const struct dataset *ds)
+static void
+run_examine (struct cmd_examine *cmd, struct casereader *input,
+             struct dataset *ds)
 {
   struct dictionary *dict = dataset_dict (ds);
-  struct casereader *r;
+  casenumber case_no;
   struct ccase c;
   int v;
-
-  const struct cmd_examine *cmd = (struct cmd_examine *) cmd_;
+  bool ok;
 
   struct factor *fctr;
 
-  output_split_file_values (ds, first);
+  if (!casereader_peek (input, 0, &c))
+    {
+      casereader_destroy (input);
+      return;
+    }
+  output_split_file_values (ds, &c);
+  case_destroy (&c);
+
+  input = casereader_create_filter_weight (input, dict, NULL, NULL);
+  input = casereader_create_counter (input, &case_no, 0);
 
   /* Make sure we haven't got rubbish left over from a
-     previous split */
+     previous split. */
   fctr = factors;
   while (fctr)
     {
@@ -738,15 +757,10 @@ run_examine (const struct ccase *first, const struct casefile *cf,
   for ( v = 0 ; v < n_dependent_vars ; ++v )
     metrics_precalc (&totals[v]);
 
-  for (r = casefile_get_reader (cf, NULL);
-      casereader_read (r, &c) ;
-      case_destroy (&c) )
+  for (; casereader_read (input, &c); case_destroy (&c))
     {
-      int case_missing=0;
-      const int case_no = casereader_cnum (r);
-
-      const double weight =
-       dict_get_case_weight (dict, &c, &bad_weight_warn);
+      bool case_missing = false;
+      const double weight = dict_get_case_weight (dict, &c, NULL);
 
       if ( cmd->miss == XMN_LISTWISE )
        {
@@ -759,7 +773,7 @@ run_examine (const struct ccase *first, const struct casefile *cf,
                                                  );
 
              if ( var_is_value_missing (var, val, exclude_values))
-               case_missing = 1;
+               case_missing = true;
 
              free (val);
            }
@@ -777,7 +791,7 @@ run_examine (const struct ccase *first, const struct casefile *cf,
                || case_missing )
            {
              free (val) ;
-             continue ;
+             val = NULL;
            }
 
          metrics_calc (&totals[v], val, weight, case_no);
@@ -787,6 +801,7 @@ run_examine (const struct ccase *first, const struct casefile *cf,
 
       factor_calc (&c, case_no, weight, case_missing);
     }
+  ok = casereader_destroy (input);
 
   for ( v = 0 ; v < n_dependent_vars ; ++v)
     {
@@ -825,17 +840,17 @@ run_examine (const struct ccase *first, const struct casefile *cf,
       struct hsh_iterator hi1;
       struct factor_statistics *fs;
 
-      struct hsh_table *idh0=0;
-      struct hsh_table *idh1=0;
-      union value *val0;
-      union value *val1;
+      struct hsh_table *idh0 = NULL;
+      struct hsh_table *idh1 = NULL;
+      union value **val0;
+      union value **val1;
 
-      idh0 = hsh_create (4, (hsh_compare_func *) compare_values,
-                        (hsh_hash_func *) hash_value,
+      idh0 = hsh_create (4, (hsh_compare_func *) compare_ptr_values,
+                        (hsh_hash_func *) hash_ptr_value,
                        0,0);
 
-      idh1 = hsh_create (4, (hsh_compare_func *) compare_values,
-                        (hsh_hash_func *) hash_value,
+      idh1 = hsh_create (4, (hsh_compare_func *) compare_ptr_values,
+                        (hsh_hash_func *) hash_ptr_value,
                        0,0);
 
 
@@ -843,8 +858,8 @@ run_examine (const struct ccase *first, const struct casefile *cf,
            fs != 0 ;
            fs = hsh_next (fctr->fstats, &hi))
        {
-         hsh_insert (idh0, (void *) &fs->id[0]);
-         hsh_insert (idh1, (void *) &fs->id[1]);
+         hsh_insert (idh0, &fs->id[0]);
+         hsh_insert (idh1, &fs->id[1]);
        }
 
       /* Ensure that the factors combination is complete */
@@ -857,17 +872,17 @@ run_examine (const struct ccase *first, const struct casefile *cf,
                val1 = hsh_next (idh1, &hi1))
            {
              struct factor_statistics **ffs;
-             union value key[2];
+             union value *key[2];
              key[0] = *val0;
              key[1] = *val1;
 
              ffs = (struct factor_statistics **)
-               hsh_probe (fctr->fstats, (void *) &key );
+               hsh_probe (fctr->fstats, &key );
 
              if ( !*ffs ) {
                size_t i;
                 (*ffs) = create_factor_statistics (n_dependent_vars,
-                                                  &key[0], &key[1]);
+                                                  key[0], key[1]);
                for ( i = 0 ; i < n_dependent_vars ; ++i )
                  metrics_precalc ( & (*ffs)->m[i]);
              }
@@ -882,7 +897,8 @@ run_examine (const struct ccase *first, const struct casefile *cf,
       fctr = fctr->next;
     }
 
-  output_examine ();
+  if (ok)
+    output_examine (dict);
 
 
   if ( totals )
@@ -893,14 +909,13 @@ run_examine (const struct ccase *first, const struct casefile *cf,
          metrics_destroy (&totals[i]);
        }
     }
-
-  return true;
 }
 
 
 static void
-show_summary (struct variable **dependent_var, int n_dep_var,
-            const struct factor *fctr)
+show_summary (const struct variable **dependent_var, int n_dep_var,
+             const struct dictionary *dict,
+             const struct factor *fctr)
 {
   static const char *subtitle[]=
     {
@@ -966,7 +981,6 @@ show_summary (struct variable **dependent_var, int n_dep_var,
 
   tab_title (tbl, _ ("Case Processing Summary"));
 
-
   tab_joint_text (tbl, heading_columns, 0,
                 n_cols -1, 0,
                 TAB_CENTER | TAT_TITLE,
@@ -981,22 +995,21 @@ show_summary (struct variable **dependent_var, int n_dep_var,
 
   for ( i = 0 ; i < 3 ; ++i )
     {
-      tab_text (tbl, heading_columns + i*2 , 2, TAB_CENTER | TAT_TITLE,
+      tab_text (tbl, heading_columns + i * 2 , 2, TAB_CENTER | TAT_TITLE,
                _ ("N"));
 
-      tab_text (tbl, heading_columns + i*2 + 1, 2, TAB_CENTER | TAT_TITLE,
+      tab_text (tbl, heading_columns + i * 2 + 1, 2, TAB_CENTER | TAT_TITLE,
                _ ("Percent"));
 
       tab_joint_text (tbl, heading_columns + i*2 , 1,
-                    heading_columns + i*2 + 1, 1,
+                    heading_columns + i * 2 + 1, 1,
                     TAB_CENTER | TAT_TITLE,
                     subtitle[i]);
 
       tab_box (tbl, -1, -1,
               TAL_0, TAL_0,
-              heading_columns + i*2, 1,
-              heading_columns + i*2 + 1, 1);
-
+              heading_columns + i * 2, 1,
+              heading_columns + i * 2 + 1, 1);
     }
 
 
@@ -1011,7 +1024,6 @@ show_summary (struct variable **dependent_var, int n_dep_var,
          tab_text (tbl, 2, heading_rows - 1, TAB_CENTER | TAT_TITLE,
                    var_to_string (fctr->indep_var[1]));
        }
-
     }
 
 
@@ -1021,7 +1033,6 @@ show_summary (struct variable **dependent_var, int n_dep_var,
       if ( fctr )
        n_factors = hsh_count (fctr->fstats);
 
-
       if ( i > 0 )
        tab_hline (tbl, TAL_1, 0, n_cols -1 , i * n_factors + heading_rows);
 
@@ -1031,13 +1042,11 @@ show_summary (struct variable **dependent_var, int n_dep_var,
                var_to_string (dependent_var[i])
                );
 
-
       if ( !fctr )
        populate_summary (tbl, heading_columns,
                         (i * n_factors) + heading_rows,
+                         dict,
                         &totals[i]);
-
-
       else
        {
          struct factor_statistics **fs = fctr->fs;
@@ -1050,37 +1059,49 @@ show_summary (struct variable **dependent_var, int n_dep_var,
                   0 != compare_values (prev, (*fs)->id[0],
                                   var_get_width (fctr->indep_var[0])))
                {
+                 struct string vstr;
+                 ds_init_empty (&vstr);
+                 var_append_value_name (fctr->indep_var[0],
+                                     (*fs)->id[0], &vstr);
+
                  tab_text (tbl,
                            1,
                            (i * n_factors ) + count +
                            heading_rows,
                            TAB_LEFT | TAT_TITLE,
-                           var_get_value_name (fctr->indep_var[0],
-                                                (*fs)->id[0])
+                           ds_cstr (&vstr)
                            );
 
+                 ds_destroy (&vstr);
+
                  if (fctr->indep_var[1] && count > 0 )
                    tab_hline (tbl, TAL_1, 1, n_cols - 1,
                              (i * n_factors ) + count + heading_rows);
-
                }
 
              prev = (*fs)->id[0];
 
-
              if ( fctr->indep_var[1])
-               tab_text (tbl,
-                         2,
-                         (i * n_factors ) + count +
-                         heading_rows,
-                         TAB_LEFT | TAT_TITLE,
-                         var_get_value_name (fctr->indep_var[1], (*fs)->id[1])
-                         );
+               {
+                 struct string vstr;
+                 ds_init_empty (&vstr);
+                 var_append_value_name (fctr->indep_var[1],
+                                        (*fs)->id[1], &vstr);
+                 tab_text (tbl,
+                           2,
+                           (i * n_factors ) + count +
+                           heading_rows,
+                           TAB_LEFT | TAT_TITLE,
+                           ds_cstr (&vstr)
+                           );
+                 ds_destroy (&vstr);
+               }
 
              populate_summary (tbl, heading_columns,
-                              (i * n_factors) + count
-                              + heading_rows,
-                              & (*fs)->m[i]);
+                               (i * n_factors) + count
+                               + heading_rows,
+                               dict,
+                               & (*fs)->m[i]);
 
              count++ ;
              fs++;
@@ -1092,16 +1113,22 @@ show_summary (struct variable **dependent_var, int n_dep_var,
 }
 
 
-void
+static void
 populate_summary (struct tab_table *t, int col, int row,
-                const struct metrics *m)
+                 const struct dictionary *dict,
+                 const struct metrics *m)
 
 {
   const double total = m->n + m->n_missing ;
 
-  tab_float (t, col + 0, row + 0, TAB_RIGHT, m->n, 8, 0);
-  tab_float (t, col + 2, row + 0, TAB_RIGHT, m->n_missing, 8, 0);
-  tab_float (t, col + 4, row + 0, TAB_RIGHT, total, 8, 0);
+  const struct variable *wv = dict_get_weight (dict);
+  const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : & F_8_0;
+
+  tab_double (t, col + 0, row + 0, TAB_RIGHT, m->n, wfmt);
+
+  tab_double (t, col + 2, row + 0, TAB_RIGHT, m->n_missing, wfmt);
+
+  tab_double (t, col + 4, row + 0, TAB_RIGHT, total, wfmt);
 
 
   if ( total > 0 ) {
@@ -1114,18 +1141,15 @@ populate_summary (struct tab_table *t, int col, int row,
     /* This seems a bit pointless !!! */
     tab_text (t, col + 5, row + 0, TAB_RIGHT | TAT_PRINTF, "%2.0f%%",
              100.0 * total / total );
-
-
   }
-
-
 }
 
 
 
 static void
-show_extremes (struct variable **dependent_var, int n_dep_var,
-             const struct factor *fctr, int n_extremities)
+show_extremes (const struct variable **dependent_var, int n_dep_var,
+              const struct factor *fctr,
+              int n_extremities)
 {
   int i;
   int heading_columns ;
@@ -1133,6 +1157,8 @@ show_extremes (struct variable **dependent_var, int n_dep_var,
   const int heading_rows = 1;
   struct tab_table *tbl;
 
+
+
   int n_factors = 1;
   int n_rows ;
 
@@ -1205,9 +1231,10 @@ show_extremes (struct variable **dependent_var, int n_dep_var,
 
       if ( !fctr )
        populate_extremes (tbl, heading_columns - 2,
-                         i * 2 * n_extremities * n_factors  + heading_rows,
-                         n_extremities, &totals[i]);
-
+                          i * 2 * n_extremities * n_factors  + heading_rows,
+                          n_extremities,
+                          dependent_var[i],
+                          &totals[i]);
       else
        {
          struct factor_statistics **fs = fctr->fs;
@@ -1223,6 +1250,10 @@ show_extremes (struct variable **dependent_var, int n_dep_var,
              if ( !prev || 0 != compare_values (prev, (*fs)->id[0],
                                         var_get_width (fctr->indep_var[0])))
                {
+                 struct string vstr;
+                 ds_init_empty (&vstr);
+                 var_append_value_name (fctr->indep_var[0],
+                                     (*fs)->id[0], &vstr);
 
                  if ( count > 0 )
                    tab_hline (tbl, TAL_1, 1, n_cols - 1, row);
@@ -1230,9 +1261,10 @@ show_extremes (struct variable **dependent_var, int n_dep_var,
                  tab_text (tbl,
                            1, row,
                            TAB_LEFT | TAT_TITLE,
-                           var_get_value_name (fctr->indep_var[0],
-                                                (*fs)->id[0])
+                           ds_cstr (&vstr)
                            );
+
+                 ds_destroy (&vstr);
                }
 
              prev = (*fs)->id[0];
@@ -1241,14 +1273,23 @@ show_extremes (struct variable **dependent_var, int n_dep_var,
                tab_hline (tbl, TAL_1, 2, n_cols - 1, row);
 
              if ( fctr->indep_var[1])
+               {
+                 struct string vstr;
+                 ds_init_empty (&vstr);
+                 var_append_value_name (fctr->indep_var[1], (*fs)->id[1], &vstr);
+
                tab_text (tbl, 2, row,
                          TAB_LEFT | TAT_TITLE,
-                         var_get_value_name (fctr->indep_var[1], (*fs)->id[1])
+                           ds_cstr (&vstr)
                          );
 
+                 ds_destroy (&vstr);
+               }
+
              populate_extremes (tbl, heading_columns - 2,
-                               row, n_extremities,
-                               & (*fs)->m[i]);
+                                row, n_extremities,
+                                dependent_var[i],
+                                & (*fs)->m[i]);
 
              count++ ;
              fs++;
@@ -1262,14 +1303,15 @@ show_extremes (struct variable **dependent_var, int n_dep_var,
 
 
 /* Fill in the extremities table */
-void
+static void
 populate_extremes (struct tab_table *t,
-                 int col, int row, int n, const struct metrics *m)
+                  int col, int row, int n,
+                  const struct variable *var,
+                  const struct metrics *m)
 {
   int extremity;
   int idx=0;
 
-
   tab_text (t, col, row,
           TAB_RIGHT | TAT_TITLE ,
           _ ("Highest")
@@ -1286,13 +1328,13 @@ populate_extremes (struct tab_table *t,
   for (extremity = 0; extremity < n ; ++extremity )
     {
       /* Highest */
-      tab_float (t, col + 1, row + extremity,
+      tab_fixed (t, col + 1, row + extremity,
                TAB_RIGHT,
                extremity + 1, 8, 0);
 
 
       /* Lowest */
-      tab_float (t, col + 1, row + extremity + n,
+      tab_fixed (t, col + 1, row + extremity + n,
                TAB_RIGHT,
                extremity + 1, 8, 0);
 
@@ -1312,13 +1354,13 @@ populate_extremes (struct tab_table *t,
          if ( extremity + j >= n )
            break ;
 
-         tab_float (t, col + 3, row + extremity + j  + n,
-                   TAB_RIGHT,
-                   wv->v.f, 8, 2);
+         tab_value (t, col + 3, row + extremity + j  + n,
+                    TAB_RIGHT,
+                    &wv->v, var_get_print_format (var));
 
-         tab_float (t, col + 2, row + extremity + j  + n,
-                   TAB_RIGHT,
-                   cn->num, 8, 0);
+         tab_fixed (t, col + 2, row + extremity + j  + n,
+                     TAB_RIGHT,
+                     cn->num, 10, 0);
 
          if ( cn->next )
            cn = cn->next;
@@ -1341,13 +1383,13 @@ populate_extremes (struct tab_table *t,
          if ( extremity + j >= n )
            break ;
 
-         tab_float (t, col + 3, row + extremity + j,
-                   TAB_RIGHT,
-                   wv->v.f, 8, 2);
+         tab_value (t, col + 3, row + extremity + j,
+                    TAB_RIGHT,
+                    &wv->v, var_get_print_format (var));
 
-         tab_float (t, col + 2, row + extremity + j,
+         tab_fixed (t, col + 2, row + extremity + j,
                    TAB_RIGHT,
-                   cn->num, 8, 0);
+                     cn->num, 10, 0);
 
          if ( cn->next )
            cn = cn->next;
@@ -1361,7 +1403,7 @@ populate_extremes (struct tab_table *t,
 
 /* Show the descriptives table */
 void
-show_descriptives (struct variable **dependent_var,
+show_descriptives (const struct variable **dependent_var,
                  int n_dep_var,
                  struct factor *fctr)
 {
@@ -1461,6 +1503,10 @@ show_descriptives (struct variable **dependent_var,
              if ( !prev || 0 != compare_values (prev, (*fs)->id[0],
                                         var_get_width (fctr->indep_var[0])))
                {
+                 struct string vstr;
+                 ds_init_empty (&vstr);
+                 var_append_value_name (fctr->indep_var[0],
+                                     (*fs)->id[0], &vstr);
 
                  if ( count > 0 )
                    tab_hline (tbl, TAL_1, 1, n_cols - 1, row);
@@ -1468,9 +1514,10 @@ show_descriptives (struct variable **dependent_var,
                  tab_text (tbl,
                            1, row,
                            TAB_LEFT | TAT_TITLE,
-                           var_get_value_name (fctr->indep_var[0],
-                                                (*fs)->id[0])
+                           ds_cstr (&vstr)
                            );
+
+                 ds_destroy (&vstr);
                }
 
              prev = (*fs)->id[0];
@@ -1479,13 +1526,23 @@ show_descriptives (struct variable **dependent_var,
                tab_hline (tbl, TAL_1, 2, n_cols - 1, row);
 
              if ( fctr->indep_var[1])
+               {
+                 struct string vstr;
+                 ds_init_empty (&vstr);
+                 var_append_value_name (fctr->indep_var[1], (*fs)->id[1], &vstr);
+
                tab_text (tbl, 2, row,
                          TAB_LEFT | TAT_TITLE,
-                         var_get_value_name (fctr->indep_var[1], (*fs)->id[1])
+                           ds_cstr (&vstr)
                          );
 
+                 ds_destroy (&vstr);
+               }
+
              populate_descriptives (tbl, heading_columns - 2,
-                                   row, & (*fs)->m[i]);
+                                    row,
+                                    dependent_var[i],
+                                    & (*fs)->m[i]);
 
              count++ ;
              fs++;
@@ -1497,44 +1554,41 @@ show_descriptives (struct variable **dependent_var,
        {
 
          populate_descriptives (tbl, heading_columns - 2,
-                               i * n_stat_rows * n_factors  + heading_rows,
-                               &totals[i]);
+                                i * n_stat_rows * n_factors  + heading_rows,
+                                dependent_var[i],
+                                &totals[i]);
        }
     }
 
   tab_submit (tbl);
-
 }
 
 
-
-
 /* Fill in the descriptives data */
-void
+static void
 populate_descriptives (struct tab_table *tbl, int col, int row,
-                     const struct metrics *m)
+                      const struct variable *var,
+                      const struct metrics *m)
 {
-
-  const double t = gsl_cdf_tdist_Qinv (1 - cmd.n_cinterval[0]/100.0/2.0, \
-                                     m->n -1);
-
+  const double t = gsl_cdf_tdist_Qinv ((1 - cmd.n_cinterval[0] / 100.0)/2.0,
+                                      m->n -1);
 
   tab_text (tbl, col,
            row,
            TAB_LEFT | TAT_TITLE,
            _ ("Mean"));
 
-  tab_float (tbl, col + 2,
-            row,
-            TAB_CENTER,
-            m->mean,
-            8,2);
+  tab_double (tbl, col + 2,
+             row,
+             TAB_CENTER,
+             m->mean,
+             NULL);
 
-  tab_float (tbl, col + 3,
-            row,
-            TAB_CENTER,
-            m->se_mean,
-            8,3);
+  tab_double (tbl, col + 3,
+             row,
+             TAB_CENTER,
+             m->se_mean,
+             NULL);
 
 
   tab_text (tbl, col,
@@ -1548,11 +1602,11 @@ populate_descriptives (struct tab_table *tbl, int col, int row,
            TAB_LEFT | TAT_TITLE,
            _ ("Lower Bound"));
 
-  tab_float (tbl, col + 2,
-            row + 1,
-            TAB_CENTER,
-            m->mean - t * m->se_mean,
-            8,3);
+  tab_double (tbl, col + 2,
+             row + 1,
+             TAB_CENTER,
+             m->mean - t * m->se_mean,
+             NULL);
 
   tab_text (tbl, col + 1,
            row + 2,
@@ -1560,22 +1614,22 @@ populate_descriptives (struct tab_table *tbl, int col, int row,
            _ ("Upper Bound"));
 
 
-  tab_float (tbl, col + 2,
-            row + 2,
-            TAB_CENTER,
-            m->mean + t * m->se_mean,
-            8,3);
+  tab_double (tbl, col + 2,
+             row + 2,
+             TAB_CENTER,
+             m->mean + t * m->se_mean,
+             NULL);
 
   tab_text (tbl, col,
            row + 3,
            TAB_LEFT | TAT_TITLE | TAT_PRINTF,
            _ ("5%% Trimmed Mean"));
 
-  tab_float (tbl, col + 2,
-            row + 3,
-            TAB_CENTER,
-            m->trimmed_mean,
-            8,2);
+  tab_double (tbl, col + 2,
+             row + 3,
+             TAB_CENTER,
+             m->trimmed_mean,
+             NULL);
 
   tab_text (tbl, col,
            row + 4,
@@ -1591,11 +1645,11 @@ populate_descriptives (struct tab_table *tbl, int col, int row,
     assert (p);
 
 
-    tab_float (tbl, col + 2,
-              row + 4,
-              TAB_CENTER,
-              p->v,
-              8, 2);
+    tab_double (tbl, col + 2,
+               row + 4,
+               TAB_CENTER,
+               p->v,
+               NULL);
   }
 
 
@@ -1604,11 +1658,11 @@ populate_descriptives (struct tab_table *tbl, int col, int row,
            TAB_LEFT | TAT_TITLE,
            _ ("Variance"));
 
-  tab_float (tbl, col + 2,
-            row + 5,
-            TAB_CENTER,
-            m->var,
-            8,3);
+  tab_double (tbl, col + 2,
+             row + 5,
+             TAB_CENTER,
+             m->var,
+             NULL);
 
 
   tab_text (tbl, col,
@@ -1617,11 +1671,11 @@ populate_descriptives (struct tab_table *tbl, int col, int row,
            _ ("Std. Deviation"));
 
 
-  tab_float (tbl, col + 2,
-            row + 6,
-            TAB_CENTER,
-            m->stddev,
-            8,3);
+  tab_double (tbl, col + 2,
+             row + 6,
+             TAB_CENTER,
+             m->stddev,
+             NULL);
 
 
   tab_text (tbl, col,
@@ -1629,23 +1683,20 @@ populate_descriptives (struct tab_table *tbl, int col, int row,
            TAB_LEFT | TAT_TITLE,
            _ ("Minimum"));
 
-  tab_float (tbl, col + 2,
-            row + 7,
-            TAB_CENTER,
-            m->min,
-            8,3);
+  tab_double (tbl, col + 2,
+             row + 7,
+             TAB_CENTER,
+             m->min, var_get_print_format (var));
 
   tab_text (tbl, col,
            row + 8,
            TAB_LEFT | TAT_TITLE,
            _ ("Maximum"));
 
-  tab_float (tbl, col + 2,
-            row + 8,
-            TAB_CENTER,
-            m->max,
-            8,3);
-
+  tab_double (tbl, col + 2,
+             row + 8,
+             TAB_CENTER,
+             m->max, var_get_print_format (var));
 
   tab_text (tbl, col,
            row + 9,
@@ -1653,11 +1704,11 @@ populate_descriptives (struct tab_table *tbl, int col, int row,
            _ ("Range"));
 
 
-  tab_float (tbl, col + 2,
-            row + 9,
-            TAB_CENTER,
-            m->max - m->min,
-            8,3);
+  tab_double (tbl, col + 2,
+             row + 9,
+             TAB_CENTER,
+             m->max - m->min,
+             NULL);
 
   tab_text (tbl, col,
            row + 10,
@@ -1677,34 +1728,31 @@ populate_descriptives (struct tab_table *tbl, int col, int row,
     assert (p1);
     assert (p2);
 
-    tab_float (tbl, col + 2,
-              row + 10,
-              TAB_CENTER,
-              p1->v - p2->v,
-              8, 2);
+    tab_double (tbl, col + 2,
+               row + 10,
+               TAB_CENTER,
+               p1->v - p2->v,
+               NULL);
   }
 
-
-
   tab_text (tbl, col,
            row + 11,
            TAB_LEFT | TAT_TITLE,
            _ ("Skewness"));
 
 
-  tab_float (tbl, col + 2,
-            row + 11,
-            TAB_CENTER,
-            m->skewness,
-            8,3);
+  tab_double (tbl, col + 2,
+             row + 11,
+             TAB_CENTER,
+             m->skewness,
+             NULL);
 
   /* stderr of skewness */
-  tab_float (tbl, col + 3,
-            row + 11,
-            TAB_CENTER,
-            calc_seskew (m->n),
-            8,3);
-
+  tab_double (tbl, col + 3,
+             row + 11,
+             TAB_CENTER,
+             calc_seskew (m->n),
+             NULL);
 
   tab_text (tbl, col,
            row + 12,
@@ -1712,20 +1760,18 @@ populate_descriptives (struct tab_table *tbl, int col, int row,
            _ ("Kurtosis"));
 
 
-  tab_float (tbl, col + 2,
-            row + 12,
-            TAB_CENTER,
-            m->kurtosis,
-            8,3);
+  tab_double (tbl, col + 2,
+             row + 12,
+             TAB_CENTER,
+             m->kurtosis,
+             NULL);
 
   /* stderr of kurtosis */
-  tab_float (tbl, col + 3,
-            row + 12,
-            TAB_CENTER,
-            calc_sekurt (m->n),
-            8,3);
-
-
+  tab_double (tbl, col + 3,
+             row + 12,
+             TAB_CENTER,
+             calc_sekurt (m->n),
+             NULL);
 }
 
 
@@ -1747,12 +1793,14 @@ box_plot_variables (const struct factor *fctr,
 
   for ( fs = fctr->fs ; *fs ; ++fs )
     {
+      struct string str;
       double y_min = DBL_MAX;
       double y_max = -DBL_MAX;
       struct chart *ch = chart_create ();
-      const char *s = factor_to_string (fctr, *fs, 0 );
+      ds_init_empty (&str);
+      factor_to_string (fctr, *fs, 0, &str );
 
-      chart_write_title (ch, s);
+      chart_write_title (ch, ds_cstr (&str));
 
       for ( i = 0 ; i < n_vars ; ++i )
        {
@@ -1780,7 +1828,7 @@ box_plot_variables (const struct factor *fctr,
        }
 
       chart_submit (ch);
-
+      ds_destroy (&str);
     }
 }
 
@@ -1819,19 +1867,21 @@ box_plot_group (const struct factor *fctr,
 
          for ( fs = fctr->fs ; *fs ; ++fs )
            {
-
-             const char *s = factor_to_string_concise (fctr, *fs);
-
+             struct string str;
              const double box_width = (ch->data_right - ch->data_left)
                / (n_factors * 2.0 ) ;
 
              const double box_centre = ( f++ * 2 + 1) * box_width
                + ch->data_left;
 
+             ds_init_empty (&str);
+             factor_to_string_concise (fctr, *fs, &str);
+
              boxplot_draw_boxplot (ch,
                                   box_centre, box_width,
                                   & (*fs)->m[i],
-                                  s);
+                                  ds_cstr (&str));
+              ds_destroy (&str);
            }
        }
       else if ( ch )
@@ -1947,7 +1997,7 @@ np_plot (const struct metrics *m, const char *factorname)
 
 /* Show the percentiles */
 void
-show_percentiles (struct variable **dependent_var,
+show_percentiles (const struct variable **dependent_var,
                 int n_dep_var,
                 struct factor *fctr)
 {
@@ -2041,10 +2091,10 @@ show_percentiles (struct variable **dependent_var,
     i = 0;
     while ( (*p)  )
       {
-       tab_float (tbl, n_heading_columns + i++ , 1,
-                 TAB_CENTER,
-                 (*p)->p, 8, 0);
-
+       tab_fixed (tbl, n_heading_columns + i++ , 1,
+                   TAB_CENTER,
+                   (*p)->p,
+                   8, 0);
        p++;
       }
 
@@ -2088,6 +2138,11 @@ show_percentiles (struct variable **dependent_var,
              if ( !prev || 0 != compare_values (prev, (*fs)->id[0],
                                         var_get_width (fctr->indep_var[0])))
                {
+                 struct string vstr;
+                 ds_init_empty (&vstr);
+                 var_append_value_name (fctr->indep_var[0],
+                                     (*fs)->id[0], &vstr);
+
 
                  if ( count > 0 )
                    tab_hline (tbl, TAL_1, 1, n_cols - 1, row);
@@ -2095,11 +2150,10 @@ show_percentiles (struct variable **dependent_var,
                  tab_text (tbl,
                            1, row,
                            TAB_LEFT | TAT_TITLE,
-                           var_get_value_name (fctr->indep_var[0],
-                                                (*fs)->id[0])
+                           ds_cstr (&vstr)
                            );
 
-
+                 ds_destroy (&vstr);
                }
 
              prev = (*fs)->id[0];
@@ -2108,14 +2162,23 @@ show_percentiles (struct variable **dependent_var,
                tab_hline (tbl, TAL_1, 2, n_cols - 1, row);
 
              if ( fctr->indep_var[1])
+               {
+                 struct string vstr;
+                 ds_init_empty (&vstr);
+                 var_append_value_name (fctr->indep_var[1], (*fs)->id[1], &vstr);
+
                tab_text (tbl, 2, row,
                          TAB_LEFT | TAT_TITLE,
-                         var_get_value_name (fctr->indep_var[1], (*fs)->id[1])
+                           ds_cstr (&vstr)
                          );
 
+                 ds_destroy (&vstr);
+               }
+
 
              populate_percentiles (tbl, n_heading_columns - 1,
-                                  row, & (*fs)->m[i]);
+                                   row,
+                                   & (*fs)->m[i]);
 
 
              count++ ;
@@ -2127,25 +2190,21 @@ show_percentiles (struct variable **dependent_var,
       else
        {
          populate_percentiles (tbl, n_heading_columns - 1,
-                              i * n_stat_rows * n_factors  + n_heading_rows,
-                              &totals[i]);
+                               i * n_stat_rows * n_factors  + n_heading_rows,
+                               &totals[i]);
        }
-
-
     }
 
 
   tab_submit (tbl);
-
-
 }
 
 
 
 
-void
+static void
 populate_percentiles (struct tab_table *tbl, int col, int row,
-                    const struct metrics *m)
+                     const struct metrics *m)
 {
   int i;
 
@@ -2167,93 +2226,86 @@ populate_percentiles (struct tab_table *tbl, int col, int row,
   i = 0;
   while ( (*p)  )
     {
-      tab_float (tbl, col + i + 1 , row,
-               TAB_CENTER,
-                (*p)->v, 8, 2);
-      if ( (*p)->p == 25 )
-       tab_float (tbl, col + i + 1 , row + 1,
+      tab_double (tbl, col + i + 1 , row,
                  TAB_CENTER,
-                 m->hinge[0], 8, 2);
+                 (*p)->v,
+                 NULL);
 
-      if ( (*p)->p == 50 )
-       tab_float (tbl, col + i + 1 , row + 1,
-                 TAB_CENTER,
-                 m->hinge[1], 8, 2);
+      if ( (*p)->p == 25 )
+       tab_double (tbl, col + i + 1 , row + 1,
+                   TAB_CENTER,
+                   m->hinge[0],
+                   NULL);
 
-      if ( (*p)->p == 75 )
-       tab_float (tbl, col + i + 1 , row + 1,
-                 TAB_CENTER,
-                 m->hinge[2], 8, 2);
+      if ( (*p)->p == 50 )
+       tab_double (tbl, col + i + 1 , row + 1,
+                   TAB_CENTER,
+                   m->hinge[1],
+                   NULL);
 
 
+      if ( (*p)->p == 75 )
+       tab_double (tbl, col + i + 1 , row + 1,
+                   TAB_CENTER,
+                   m->hinge[2],
+                   NULL);
       i++;
-
       p++;
     }
-
 }
 
-
-
-const char *
+static void
 factor_to_string (const struct factor *fctr,
                  const struct factor_statistics *fs,
-                 const struct variable *var)
+                 const struct variable *var,
+                 struct string *str
+                 )
 {
-
-  static char buf1[100];
-  char buf2[100];
-
-  strcpy (buf1,"");
-
   if (var)
-    sprintf (buf1, "%s (",var_to_string (var) );
+    ds_put_format (str, "%s (",var_to_string (var) );
 
 
-  snprintf (buf2, 100, "%s = %s",
-          var_to_string (fctr->indep_var[0]),
-           var_get_value_name (fctr->indep_var[0], fs->id[0]));
+  ds_put_format (str,  "%s = ",
+                var_to_string (fctr->indep_var[0]));
 
-  strcat (buf1, buf2);
+  var_append_value_name (fctr->indep_var[0], fs->id[0], str);
 
   if ( fctr->indep_var[1] )
     {
-      sprintf (buf2, "; %s = %s)",
-             var_to_string (fctr->indep_var[1]),
-              var_get_value_name (fctr->indep_var[1], fs->id[1]));
-      strcat (buf1, buf2);
+      ds_put_format (str, "; %s = )",
+                    var_to_string (fctr->indep_var[1]));
+
+      var_append_value_name (fctr->indep_var[1], fs->id[1], str);
     }
   else
     {
       if ( var )
-       strcat (buf1, ")");
+       ds_put_cstr (str, ")");
     }
-
-  return buf1;
 }
 
 
-
-const char *
+static void
 factor_to_string_concise (const struct factor *fctr,
-                        struct factor_statistics *fs)
+                         const struct factor_statistics *fs,
+                         struct string *str
+                         )
 
 {
-
-  static char buf[100];
-
-  char buf2[100];
-
-  snprintf (buf, 100, "%s",
-            var_get_value_name (fctr->indep_var[0], fs->id[0]));
+  var_append_value_name (fctr->indep_var[0], fs->id[0], str);
 
   if ( fctr->indep_var[1] )
     {
-      sprintf (buf2, ",%s)", var_get_value_name (fctr->indep_var[1],
-                                                 fs->id[1]) );
-      strcat (buf, buf2);
-    }
+      ds_put_cstr (str, ",");
 
+      var_append_value_name (fctr->indep_var[1],fs->id[1], str);
 
-  return buf;
+      ds_put_cstr (str, ")");
+    }
 }
+
+/*
+  Local Variables:
+  mode: c
+  End:
+*/