FREQUENCIES: Fix bug when combining HISTOGRAM with PERCENTILES.
[pspp] / src / language / stats / frequencies.c
index 7bda6a13e050d6d46b4f0fb485289ade8779326a..17e03130923bab5888580f0493d39f8decd712e3 100644 (file)
@@ -82,6 +82,14 @@ ptile_3way (const void *_p1, const void *_p2)
   if (p1->p < p2->p)
     return -1;
 
+  if (p1->p == p2->p)
+    {
+      if (p1->show > p2->show)
+       return -1;
+
+      return (p1->show < p2->show);
+    }
+
   return (p1->p > p2->p);
 }
 
@@ -286,6 +294,7 @@ dump_freq_table (const struct var_freqs *vf, const struct variable *wv)
 
   n_categories = ft->n_valid + ft->n_missing;
   t = tab_create (6, n_categories + 2);
+  tab_set_format (t, RC_WEIGHT, wfmt);
   tab_headers (t, 0, 0, 1, 0);
 
   for (x = 0; x < 6; x++)
@@ -308,10 +317,10 @@ dump_freq_table (const struct var_freqs *vf, const struct variable *wv)
         tab_text (t, 0, r, TAB_LEFT, label);
 
       tab_value (t, 1, r, TAB_NONE, &f->value, vf->var, NULL);
-      tab_double (t, 2, r, TAB_NONE, f->count, wfmt);
-      tab_double (t, 3, r, TAB_NONE, percent, NULL);
-      tab_double (t, 4, r, TAB_NONE, valid_percent, NULL);
-      tab_double (t, 5, r, TAB_NONE, cum_total, NULL);
+      tab_double (t, 2, r, TAB_NONE, f->count, NULL, RC_WEIGHT);
+      tab_double (t, 3, r, TAB_NONE, percent, NULL, RC_OTHER);
+      tab_double (t, 4, r, TAB_NONE, valid_percent, NULL, RC_OTHER);
+      tab_double (t, 5, r, TAB_NONE, cum_total, NULL, RC_OTHER);
       r++;
     }
   for (; f < &ft->valid[n_categories]; f++)
@@ -325,9 +334,9 @@ dump_freq_table (const struct var_freqs *vf, const struct variable *wv)
         tab_text (t, 0, r, TAB_LEFT, label);
 
       tab_value (t, 1, r, TAB_NONE, &f->value, vf->var, NULL);
-      tab_double (t, 2, r, TAB_NONE, f->count, wfmt);
+      tab_double (t, 2, r, TAB_NONE, f->count, NULL, RC_WEIGHT);
       tab_double (t, 3, r, TAB_NONE,
-                    f->count / ft->total_cases * 100.0, NULL);
+                 f->count / ft->total_cases * 100.0, NULL, RC_OTHER);
       tab_text (t, 4, r, TAB_NONE, _("Missing"));
       r++;
     }
@@ -337,9 +346,9 @@ dump_freq_table (const struct var_freqs *vf, const struct variable *wv)
   tab_hline (t, TAL_2, 0, 5, r);
   tab_joint_text (t, 0, r, 1, r, TAB_RIGHT | TAT_TITLE, _("Total"));
   tab_vline (t, TAL_0, 1, r, r);
-  tab_double (t, 2, r, TAB_NONE, cum_freq, wfmt);
-  tab_fixed (t, 3, r, TAB_NONE, 100.0, 5, 1);
-  tab_fixed (t, 4, r, TAB_NONE, 100.0, 5, 1);
+  tab_double (t, 2, r, TAB_NONE, cum_freq, NULL, RC_WEIGHT);
+  tab_double (t, 3, r, TAB_NONE, 100.0, &F_5_1, RC_OTHER);
+  tab_double (t, 4, r, TAB_NONE, 100.0, &F_5_1, RC_OTHER);
 
   tab_title (t, "%s", var_to_string (vf->var));
   tab_submit (t);
@@ -366,13 +375,9 @@ calc_percentiles (const struct frq_proc *frq, const struct var_freqs *vf)
   const struct freq_tab *ft = &vf->tab;
   double W = ft->valid_cases;
   const struct freq *f;
-  int percentile_idx;
-  double rank;
-
-  assert (ft->n_valid > 0);
+  int percentile_idx = 0;
+  double  rank = 0;
 
-  rank = 0;
-  percentile_idx = 0;
   for (f = ft->valid; f < ft->missing; f++)
     {
       rank += f->count;
@@ -625,6 +630,7 @@ cmd_frequencies (struct lexer *lexer, struct dataset *ds)
   for (i = 0; i < frq.n_vars; ++i)
     {
       frq.vars[i].var = vars[i];
+      frq.vars[i].width = var_get_width (vars[i]);
     }
 
   while (lex_token (lexer) != T_ENDCMD)
@@ -633,10 +639,18 @@ cmd_frequencies (struct lexer *lexer, struct dataset *ds)
 
       if (lex_match_id (lexer, "STATISTICS"))
        {
-         lex_match (lexer, T_EQUALS);
-
-         frq.stats = 0;
-         frq.n_stats = 0;
+         frq.stats = BIT_INDEX (FRQ_ST_MEAN) 
+           | BIT_INDEX (FRQ_ST_STDDEV) 
+           | BIT_INDEX (FRQ_ST_MINIMUM)
+           | BIT_INDEX (FRQ_ST_MAXIMUM);
+         
+         frq.n_stats = 4;
+
+         if (lex_match (lexer, T_EQUALS))
+           {
+             frq.n_stats = 0;
+             frq.stats = 0;
+           }
 
          while (lex_token (lexer) != T_ENDCMD
                 && lex_token (lexer) != T_SLASH)
@@ -760,6 +774,7 @@ cmd_frequencies (struct lexer *lexer, struct dataset *ds)
                  lex_error (lexer, NULL);
                  goto error;
                }
+              lex_match (lexer, T_COMMA);
            }
        }
       else if (lex_match_id (lexer, "FORMAT"))
@@ -889,7 +904,7 @@ cmd_frequencies (struct lexer *lexer, struct dataset *ds)
                          hi_pcnt = lex_integer (lexer);
                          if (hi_pcnt <= 0)
                            {
-                             lex_error (lexer, _("Histogram percentaage must be greater than zero."));
+                             lex_error (lexer, _("Histogram percentage must be greater than zero."));
                            }
                          lex_get (lexer);
                          lex_force_match (lexer, T_RPAREN);
@@ -992,7 +1007,7 @@ cmd_frequencies (struct lexer *lexer, struct dataset *ds)
         }
     }
 
-  if (frq.stats & FRQ_ST_MEDIAN)
+  if (frq.stats & BIT_INDEX (FRQ_ST_MEDIAN))
     {
        frq.percentiles =
          xrealloc (frq.percentiles, 
@@ -1295,14 +1310,10 @@ calc_stats (const struct var_freqs *vf, double d[FRQ_ST_count])
   double W = ft->valid_cases;
   const struct freq *f;
   struct moments *m;
-  int most_often;
-  double X_mode;
-
-  assert (ft->n_valid > 0);
+  int most_often = -1;
+  double X_mode = SYSMIS;
 
   /* Calculate the mode. */
-  most_often = -1;
-  X_mode = SYSMIS;
   for (f = ft->valid; f < ft->missing; f++)
     {
       if (most_often < f->count)
@@ -1328,7 +1339,7 @@ calc_stats (const struct var_freqs *vf, double d[FRQ_ST_count])
                      &d[FRQ_ST_SKEWNESS], &d[FRQ_ST_KURTOSIS]);
   moments_destroy (m);
 
-  /* Formulas below are taken from _SPSS Statistical Algorithms_. */
+  /* Formulae below are taken from _SPSS Statistical Algorithms_. */
   d[FRQ_ST_MINIMUM] = ft->valid[0].value.f;
   d[FRQ_ST_MAXIMUM] = ft->valid[ft->n_valid - 1].value.f;
   d[FRQ_ST_MODE] = X_mode;
@@ -1349,30 +1360,22 @@ dump_statistics (const struct frq_proc *frq, const struct var_freqs *vf,
   const struct freq_tab *ft = &vf->tab;
   double stat_value[FRQ_ST_count];
   struct tab_table *t;
-  int i, r;
+  int i, r = 2; /* N missing and N valid are always dumped */
 
   if (var_is_alpha (vf->var))
     return;
 
-  if (ft->n_valid == 0)
-    {
-      msg (SW, _("No valid data for variable %s; statistics not displayed."),
-          var_get_name (vf->var));
-      return;
-    }
   calc_stats (vf, stat_value);
 
-  t = tab_create (3, ((frq->stats & FRQ_ST_MEDIAN) ? frq->n_stats - 1 : frq->n_stats)
-                 + frq->n_show_percentiles + 2);
+  t = tab_create (3, ((frq->stats & BIT_INDEX (FRQ_ST_MEDIAN)) ? frq->n_stats - 1 : frq->n_stats)
+                               + frq->n_show_percentiles + 2);
 
+  tab_set_format (t, RC_WEIGHT, wfmt);
   tab_box (t, TAL_1, TAL_1, -1, -1 , 0 , 0 , 2, tab_nr(t) - 1) ;
 
-
   tab_vline (t, TAL_1 , 2, 0, tab_nr(t) - 1);
   tab_vline (t, TAL_GAP , 1, 0, tab_nr(t) - 1 ) ;
 
-  r = 2; /* N missing and N valid are always dumped */
-
   for (i = 0; i < FRQ_ST_count; i++)
     {
       if (FRQ_ST_MEDIAN == i)
@@ -1382,7 +1385,11 @@ dump_statistics (const struct frq_proc *frq, const struct var_freqs *vf,
       {
        tab_text (t, 0, r, TAB_LEFT | TAT_TITLE,
                      gettext (st_name[i]));
-       tab_double (t, 2, r, TAB_NONE, stat_value[i], NULL);
+
+       if (vf->tab.n_valid <= 0 && r >= 2)
+         tab_text (t, 2, r, 0,   ".");
+       else
+         tab_double (t, 2, r, TAB_NONE, stat_value[i], NULL, RC_OTHER);
        r++;
       }
     }
@@ -1391,8 +1398,8 @@ dump_statistics (const struct frq_proc *frq, const struct var_freqs *vf,
   tab_text (t, 1, 0, TAB_LEFT | TAT_TITLE, _("Valid"));
   tab_text (t, 1, 1, TAB_LEFT | TAT_TITLE, _("Missing"));
 
-  tab_double (t, 2, 0, TAB_NONE, ft->valid_cases, wfmt);
-  tab_double (t, 2, 1, TAB_NONE, ft->total_cases - ft->valid_cases, wfmt);
+  tab_double (t, 2, 0, TAB_NONE, ft->valid_cases, NULL, RC_WEIGHT);
+  tab_double (t, 2, 1, TAB_NONE, ft->total_cases - ft->valid_cases, NULL, RC_WEIGHT);
 
   for (i = 0; i < frq->n_percentiles; i++)
     {
@@ -1406,13 +1413,21 @@ dump_statistics (const struct frq_proc *frq, const struct var_freqs *vf,
          tab_text (t, 0, r, TAB_LEFT | TAT_TITLE, _("Percentiles"));
        }
 
+      if (vf->tab.n_valid <= 0)
+       {
+         tab_text (t, 2, r, 0,   ".");
+         ++r;
+         continue;
+       }
+
       if (pc->p == 0.5)
         tab_text (t, 1, r, TAB_LEFT, _("50 (Median)"));
       else
-        tab_fixed (t, 1, r, TAB_LEFT, pc->p * 100, 3, 0);
+        tab_double (t, 1, r, TAB_LEFT, pc->p * 100, NULL, RC_INTEGER);
       tab_double (t, 2, r, TAB_NONE, pc->value,
-                  var_get_print_format (vf->var));
-      r++;
+                  var_get_print_format (vf->var), RC_OTHER);
+
+      ++r;
     }
 
   tab_title (t, "%s", var_to_string (vf->var));