pivot-table: Implement SET SMALL.
authorBen Pfaff <blp@cs.stanford.edu>
Thu, 7 Jan 2021 04:27:54 +0000 (20:27 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Thu, 7 Jan 2021 04:29:38 +0000 (20:29 -0800)
doc/utilities.texi
src/data/settings.c
src/data/settings.h
src/language/utilities/set.q
src/output/pivot-table.c
src/output/pivot-table.h
src/output/spv/spv-writer.c
tests/language/stats/examine.at
tests/language/stats/factor.at
tests/language/stats/logistic.at
tests/output/pivot-table.at

index 0ddbcbb06ce56b7a8430ffbee917a5ea2e4259fc..1c75baa6026fc2653441bc6de1827f1b0c7ac8e6 100644 (file)
@@ -510,6 +510,7 @@ SET
         /CC@{A,B,C,D,E@}=@{'@var{npre},@var{pre},@var{suf},@var{nsuf}','@var{npre}.@var{pre}.@var{suf}.@var{nsuf}'@}
         /DECIMAL=@{DOT,COMMA@}
         /FORMAT=@var{fmt_spec}
+        /SMALL=@var{number}
         /WIB=@{NATIVE,MSBFIRST,LSBFIRST,VAX@}
         /WRB=@{NATIVE,ISL,ISB,IDL,IDB,VF,VD,VG,ZS,ZL@}
 
@@ -752,6 +753,14 @@ The default @subcmd{DOT} setting causes the decimal point character to be
 Allows the default numeric input/output format to be specified.  The
 default is F8.2.  @xref{Input and Output Formats}.
 
+@item SMALL
+This controls how @pspp{} formats small numbers in pivot tables, in
+cases where @pspp{} does not otherwise have a well-defined format for
+the numbers.  When such a number has a magnitude less than the value
+set here, @pspp{} formats the number in scientific notation;
+otherwise, it formats it in standard notation.  The default is 0.0001.
+Set a value of 0 to disable scientific notation.
+
 @item WIB
 @anchor{SET WIB}
 
index 6a336af6a02896ed2d0f8b18ca76ac15ae0e5977..1b48299446d777491fbf9fad5cc087204481bb22 100644 (file)
@@ -71,6 +71,7 @@ struct settings
   int syntax;
 
   struct fmt_settings styles;
+  double small;
 
   enum settings_output_devices output_routing[SETTINGS_N_OUTPUT_TYPES];
 
@@ -111,6 +112,7 @@ static struct settings the_settings = {
   ENHANCED,                     /* global_algorithm */
   ENHANCED,                     /* syntax */
   FMT_SETTINGS_INIT,            /* styles */
+  .0001,                        /* small */
 
   /* output_routing */
   {SETTINGS_DEVICE_LISTING | SETTINGS_DEVICE_TERMINAL,
@@ -551,6 +553,18 @@ settings_get_fmt_settings (void)
   return &the_settings.styles;
 }
 
+double
+settings_get_small (void)
+{
+  return the_settings.small;
+}
+
+void
+settings_set_small (double small)
+{
+  the_settings.small = small;
+}
+
 /* Returns a string of the form "$#,###.##" according to FMT,
    which must be of type FMT_DOLLAR.  The caller must free the
    string. */
index f485ce152cf8e22cf90a40fb75b53ad3f408ac57..39bac54430f7764a26dafeb9d7bdb57f8e7692d9 100644 (file)
@@ -146,6 +146,9 @@ void settings_set_decimal_char (char decimal);
 
 const struct fmt_settings *settings_get_fmt_settings (void);
 
+double settings_get_small (void);
+void settings_set_small (double);
+
 char * settings_dollar_template (const struct fmt_spec *fmt);
 
 /* Routing of different kinds of output. */
index 159c9bef6b1bebdc5ccc6c25f11dcfdf10fecd49..aa7f8b803444220802fc025e10f1829e51c27b65 100644 (file)
@@ -110,6 +110,7 @@ int tgetnum (const char *);
      scompression=scompress:on/off;
      scripttab=string;
      seed=custom;
+     small=double;
      tnumbers=custom;
      tvars=custom;
      tb1=string;
@@ -195,6 +196,8 @@ cmd_set (struct lexer *lexer, struct dataset *ds)
     settings_set_safer_mode ();
   if (cmd.sbc_scompression)
     settings_set_scompression (cmd.scompress == STC_ON);
+  if (cmd.sbc_small)
+    settings_set_small (cmd.n_small[0]);
   if (cmd.sbc_undefined)
     settings_set_undefined (cmd.undef == STC_WARN);
   if (cmd.sbc_wib)
index 22cd20de1339b1103f545d0873b05a8b3243325f..b3d6c399dae6ccd142559837252e887f16d75286 100644 (file)
@@ -18,6 +18,7 @@
 
 #include "output/pivot-table.h"
 
+#include <math.h>
 #include <stdlib.h>
 
 #include "data/data-out.h"
@@ -45,8 +46,8 @@
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 
-static const struct fmt_spec *pivot_table_get_format (
-  const struct pivot_table *, const char *s);
+static void pivot_table_use_rc (const struct pivot_table *, const char *s,
+                                struct fmt_spec *, bool *honor_small);
 \f
 /* Pivot table display styling. */
 
@@ -394,17 +395,19 @@ pivot_axis_iterator_next (size_t *indexes, const struct pivot_axis *axis)
 static void
 pivot_category_set_rc (struct pivot_category *category, const char *s)
 {
-  const struct fmt_spec *format = pivot_table_get_format (
-    category->dimension->table, s);
-  if (format)
-    category->format = *format;
+  if (!s)
+    return;
+
+  pivot_table_use_rc (category->dimension->table, s,
+                      &category->format, &category->honor_small);
 
   /* Ensure that the category itself, in addition to the cells within it, takes
      the format.  (It's kind of rare for a category to have a numeric format
      though.) */
   struct pivot_value *name = category->name;
   if (name->type == PIVOT_VALUE_NUMERIC && !name->numeric.format.w)
-    name->numeric.format = format ? *format : *settings_get_format ();
+    pivot_table_use_rc (category->dimension->table, s,
+                        &name->numeric.format, &name->numeric.honor_small);
 }
 
 static void
@@ -764,19 +767,35 @@ pivot_result_class_find (const char *s)
   return NULL;
 }
 
-static const struct fmt_spec *
-pivot_table_get_format (const struct pivot_table *table, const char *s)
+static void
+pivot_table_use_rc (const struct pivot_table *table, const char *s,
+                    struct fmt_spec *format, bool *honor_small)
 {
-  if (!s)
-    return NULL;
-  else if (!strcmp (s, PIVOT_RC_OTHER))
-    return settings_get_format ();
-  else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format)
-    return &table->weight_format;
-  else
+  if (s)
     {
-      const struct result_class *rc = pivot_result_class_find (s);
-      return rc ? &rc->format : NULL;
+      if (!strcmp (s, PIVOT_RC_OTHER))
+        {
+          *format = *settings_get_format ();
+          *honor_small = true;
+        }
+      else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format)
+        {
+          *format = table->weight_format;
+          *honor_small = false;
+        }
+      else
+        {
+          const struct result_class *rc = pivot_result_class_find (s);
+          if (rc)
+            {
+              *format = rc->format;
+              *honor_small = false;
+            }
+          else
+            {
+              printf ("unknown class %s\n", s);
+            }
+        }
     }
 }
 
@@ -854,6 +873,7 @@ pivot_table_create__ (struct pivot_value *title, const char *subtype)
   table->command_c = output_get_command_name ();
   table->look = pivot_table_look_ref (pivot_table_look_get_default ());
   table->settings = fmt_settings_copy (settings_get_fmt_settings ());
+  table->small = settings_get_small ();
 
   hmap_init (&table->cells);
 
@@ -1414,11 +1434,13 @@ pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
               if (c->format.w)
                 {
                   value->numeric.format = c->format;
+                  value->numeric.honor_small = c->honor_small;
                   goto done;
                 }
             }
         }
       value->numeric.format = *settings_get_format ();
+      value->numeric.honor_small = true;
 
     done:;
     }
@@ -2288,8 +2310,17 @@ pivot_value_format_body (const struct pivot_value *value,
                              value->numeric.value_label != NULL);
       if (show & SETTINGS_VALUE_SHOW_VALUE)
         {
+          const struct fmt_spec *f = &value->numeric.format;
+          const struct fmt_spec *format
+            = (f->type == FMT_F
+               && value->numeric.honor_small
+               && value->numeric.x != 0
+               && fabs (value->numeric.x) < pt->small
+               ? &(struct fmt_spec) { .type = FMT_E, .w = 40, .d = f->d }
+               : f);
+
           char *s = data_out (&(union value) { .f = value->numeric.x },
-                              "UTF-8", &value->numeric.format, &pt->settings);
+                              "UTF-8", format, &pt->settings);
           ds_put_cstr (out, s + strspn (s, " "));
           free (s);
         }
@@ -2817,10 +2848,7 @@ pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
                     const char *rc)
 {
   if (value->type == PIVOT_VALUE_NUMERIC)
-    {
-      const struct fmt_spec *f = pivot_table_get_format (table, rc);
-      if (f)
-        value->numeric.format = *f;
-    }
+    pivot_table_use_rc (table, rc,
+                        &value->numeric.format, &value->numeric.honor_small);
 }
 
index 343d7a3c09042011f9727a37cd0721840a9eb5ec..e7537e781bc52574affc49500bdf002afa007a57 100644 (file)
@@ -307,10 +307,11 @@ struct pivot_category
     bool show_label_in_corner;
 
     /* Leaf only. */
-    struct fmt_spec format;
     size_t group_index;        /* In ->parent->subs[]. */
     size_t data_index;         /* In ->dimension->data_leaves[]. */
     size_t presentation_index; /* In ->dimension->presentation_leaves[]. */
+    struct fmt_spec format;    /* Default format for values in this category. */
+    bool honor_small;          /* Honor pivot_table 'small' setting? */
   };
 
 static inline bool
@@ -660,6 +661,7 @@ struct pivot_value
             char *var_name;           /* May be NULL. */
             char *value_label;        /* May be NULL. */
             enum settings_value_show show; /* Show value or label or both? */
+            bool honor_small;         /* Honor value of pivot table 'small'? */
           }
         numeric;
 
index b8a4768fc00e300818b772e183cc7e2fab963960..19ea047afab51cfbbf20a46e4f55548b0c114efa 100644 (file)
@@ -555,9 +555,10 @@ put_value_mod (struct buf *buf, const struct pivot_value *value,
 }
 
 static void
-put_format (struct buf *buf, const struct fmt_spec *f)
+put_format (struct buf *buf, const struct fmt_spec *f, bool honor_small)
 {
-  put_u32 (buf, (fmt_to_io (f->type) << 16) | (f->w << 8) | f->d);
+  int type = f->type == FMT_F && honor_small ? 40 : fmt_to_io (f->type);
+  put_u32 (buf, (type << 16) | (f->w << 8) | f->d);
 }
 
 static int
@@ -585,7 +586,7 @@ put_value (struct buf *buf, const struct pivot_value *value)
         {
           put_byte (buf, 2);
           put_value_mod (buf, value, NULL);
-          put_format (buf, &value->numeric.format);
+          put_format (buf, &value->numeric.format, value->numeric.honor_small);
           put_double (buf, value->numeric.x);
           put_string (buf, value->numeric.var_name);
           put_string (buf, value->numeric.value_label);
@@ -595,7 +596,7 @@ put_value (struct buf *buf, const struct pivot_value *value)
         {
           put_byte (buf, 1);
           put_value_mod (buf, value, NULL);
-          put_format (buf, &value->numeric.format);
+          put_format (buf, &value->numeric.format, value->numeric.honor_small);
           put_double (buf, value->numeric.x);
         }
       break;
@@ -604,7 +605,8 @@ put_value (struct buf *buf, const struct pivot_value *value)
       put_byte (buf, 4);
       put_value_mod (buf, value, NULL);
       put_format (buf,
-                  &(struct fmt_spec) { FMT_A, strlen (value->string.s), 0 });
+                  &(struct fmt_spec) { FMT_A, strlen (value->string.s), 0 },
+                  false);
       put_string (buf, value->string.value_label);
       put_string (buf, value->string.var_name);
       put_show_values (buf, value->string.show);
index 6c76b62d6da04079236f72dfa6fd3590db48a9b4..4e7d6f4d8fec7c3db954f287450a9a15a5d20af0 100644 (file)
@@ -726,6 +726,7 @@ begin data.
 300 threehundred
 end data.
 
+set small=0.
 examine x
        /statistics = extreme
        /id = y
index 334b4ba72c81dff7073f9c6a32d4d6a5063b3dab..c066dae52b14ea580ad79b1174295679f112a45b 100644 (file)
@@ -1831,6 +1831,7 @@ BEGIN DATA
 9 7 9 9 7
 END DATA
 
+SET SMALL=0.
 FACTOR /VARIABLES=TRAIT1 TO TRAIT5
     /ROTATION=NOROTATE /* NOROTATE may have caused the problem. */
     /EXTRACTION=PC
index cf413ea6e0c57d3a0acde1e3d126c2bac8c3ddd4..93882d336c02802750c6fe80f5f947155a436ce0 100644 (file)
@@ -1011,7 +1011,7 @@ AT_DATA([lr-cat2.data], [dnl
 ])
 
 AT_DATA([stringcat.sps], [dnl
-set format=F20.3.
+set format=F20.3 /small=0.
 data list notable file='lr-cat2.data' list /read honcomp wiz science *.
 
 string ses(a1).
index bc66c828f421d639031b75ee8cb243ad7d834f7a..19b1930ccc013dbfafe8e2f6c92d701b17dc8104 100644 (file)
@@ -539,3 +539,75 @@ d3    │c1     54│55┊56│57│58┊59│60│61┊62
       │   ┊c3 72│73┊74│75│76┊77│78│79┊80
 ])
 AT_CLEANUP
+
+AT_SETUP([pivot table - small numbers])
+AT_DATA([pivot.txt], [[
+/title "small numbers"
+/row "exponent"*("0", "-1", "-2", "-3", "-4", "-5", "-6", "-7", "-8", "-9")
+/col "sign"*("positive", "negative")
+/col "result class"*("general" RC_OTHER, "specific" RC_RESIDUAL)
+/cell[0, 0, 0] = 1
+/cell[1, 0, 0] = .1
+/cell[2, 0, 0] = .01
+/cell[3, 0, 0] = .001
+/cell[4, 0, 0] = .0001
+/cell[5, 0, 0] = .00001
+/cell[6, 0, 0] = .000001
+/cell[7, 0, 0] = .0000001
+/cell[8, 0, 0] = .00000001
+/cell[9, 0, 0] = .000000001
+/cell[0, 0, 1] = -1
+/cell[1, 0, 1] = -.1
+/cell[2, 0, 1] = -.01
+/cell[3, 0, 1] = -.001
+/cell[4, 0, 1] = -.0001
+/cell[5, 0, 1] = -.00001
+/cell[6, 0, 1] = -.000001
+/cell[7, 0, 1] = -.0000001
+/cell[8, 0, 1] = -.00000001
+/cell[9, 0, 1] = -.000000001
+/cell[0, 1, 0] = 1
+/cell[1, 1, 0] = .1
+/cell[2, 1, 0] = .01
+/cell[3, 1, 0] = .001
+/cell[4, 1, 0] = .0001
+/cell[5, 1, 0] = .00001
+/cell[6, 1, 0] = .000001
+/cell[7, 1, 0] = .0000001
+/cell[8, 1, 0] = .00000001
+/cell[9, 1, 0] = .000000001
+/cell[0, 1, 1] = -1
+/cell[1, 1, 1] = -.1
+/cell[2, 1, 1] = -.01
+/cell[3, 1, 1] = -.001
+/cell[4, 1, 1] = -.0001
+/cell[5, 1, 1] = -.00001
+/cell[6, 1, 1] = -.000001
+/cell[7, 1, 1] = -.0000001
+/cell[8, 1, 1] = -.00000001
+/cell[9, 1, 1] = -.000000001
+]])
+AT_CHECK([pivot-table-test --table-look $srcdir/output/look.stt pivot.txt --box unicode], [0], [dnl
+small numbers
+╭────────┬─────────────────────────────────────╮
+│        │             result class            │
+│        ├───────────────────┬─────────────────┤
+│        │      general      │     specific    │
+│        ├───────────────────┼─────────────────┤
+│        │        sign       │       sign      │
+│        ├─────────┬─────────┼────────┬────────┤
+│exponent│ positive│ negative│positive│negative│
+├────────┼─────────┼─────────┼────────┼────────┤
+│0       │     1.00│     1.00│   -1.00│   -1.00│
+│-1      │      .10│      .10│    -.10│    -.10│
+│-2      │      .01│      .01│    -.01│    -.01│
+│-3      │      .00│      .00│     .00│     .00│
+│-4      │      .00│      .00│     .00│     .00│
+│-5      │1.00E-005│1.00E-005│     .00│     .00│
+│-6      │1.00E-006│1.00E-006│     .00│     .00│
+│-7      │1.00E-007│1.00E-007│     .00│     .00│
+│-8      │1.00E-008│1.00E-008│     .00│     .00│
+│-9      │1.00E-009│1.00E-009│     .00│     .00│
+╰────────┴─────────┴─────────┴────────┴────────╯
+])
+AT_CLEANUP
\ No newline at end of file