Add ptile support (untested).
[pspp] / src / language / stats / ctables.c
index 5f9d2584c809649d527cf0bd59a0f879cd38eefb..2edd40d5d39d78cfc46a86e1dd6bdfad9df0b0ff 100644 (file)
@@ -35,6 +35,7 @@
 #include "libpspp/hmap.h"
 #include "libpspp/message.h"
 #include "libpspp/string-array.h"
+#include "math/mode.h"
 #include "math/moments.h"
 #include "math/percentiles.h"
 #include "math/sort.h"
@@ -1685,14 +1686,15 @@ union ctables_summary
     /* MEAN, SEMEAN, STDDEV, SUM, VARIANCE, *.SUM. */
     struct moments1 *moments;
 
+    /* MEDIAN, MODE, PTILE. */
     struct
       {
         struct casewriter *writer;
-        double mvalid;
-        double median;
+        double ovalid;
+        double ovalue;
       };
 
-    /* XXX percentiles, mode, multiple response */
+    /* XXX multiple response */
   };
 
 static void
@@ -1754,6 +1756,8 @@ ctables_summary_init (union ctables_summary *s,
       break;
 
     case CTSF_MEDIAN:
+    case CTSF_MODE:
+    case CTSF_PTILE:
       {
         struct caseproto *proto = caseproto_create ();
         proto = caseproto_add_width (proto, 0);
@@ -1765,15 +1769,11 @@ ctables_summary_init (union ctables_summary *s,
         subcase_uninit (&ordering);
         caseproto_unref (proto);
 
-        s->mvalid = 0;
-        s->median = SYSMIS;
+        s->ovalid = 0;
+        s->ovalue = SYSMIS;
       }
       break;
 
-    case CTSF_MODE:
-    case CTSF_PTILE:
-      NOT_REACHED ();
-
     case CTSF_RESPONSES:
     case CTSF_ROWPCT_RESPONSES:
     case CTSF_COLPCT_RESPONSES:
@@ -1857,12 +1857,10 @@ ctables_summary_uninit (union ctables_summary *s,
       break;
 
     case CTSF_MEDIAN:
-      casewriter_destroy (s->writer);
-      break;
-
     case CTSF_MODE:
     case CTSF_PTILE:
-      NOT_REACHED ();
+      casewriter_destroy (s->writer);
+      break;
 
     case CTSF_RESPONSES:
     case CTSF_ROWPCT_RESPONSES:
@@ -1962,9 +1960,11 @@ ctables_summary_add (union ctables_summary *s,
       break;
 
     case CTSF_MEDIAN:
+    case CTSF_MODE:
+    case CTSF_PTILE:
       if (var_is_value_missing (var, value))
         {
-          s->mvalid += weight;
+          s->ovalid += weight;
 
           struct ccase *c = case_create (casewriter_get_proto (s->writer));
           *case_num_rw_idx (c, 0) = value->f;
@@ -1973,10 +1973,6 @@ ctables_summary_add (union ctables_summary *s,
         }
       break;
 
-    case CTSF_MODE:
-    case CTSF_PTILE:
-      NOT_REACHED ();
-
     case CTSF_RESPONSES:
     case CTSF_ROWPCT_RESPONSES:
     case CTSF_COLPCT_RESPONSES:
@@ -2116,22 +2112,34 @@ ctables_summary_value (const struct ctables_cell *cell,
       NOT_REACHED ();
 
     case CTSF_MEDIAN:
+    case CTSF_PTILE:
       if (s->writer)
         {
           struct casereader *reader = casewriter_make_reader (s->writer);
           s->writer = NULL;
 
-          struct percentile *median = percentile_create (0.5, s->mvalid);
-          struct order_stats *os = &median->parent;
+          struct percentile *ptile = percentile_create (
+            ss->function == CTSF_PTILE ? ss->percentile : 0.5, s->ovalid);
+          struct order_stats *os = &ptile->parent;
           order_stats_accumulate_idx (&os, 1, reader, 1, 0);
-          s->median = percentile_calculate (median, PC_HAVERAGE);
-          statistic_destroy (&median->parent.parent);
+          s->ovalue = percentile_calculate (ptile, PC_HAVERAGE);
+          statistic_destroy (&ptile->parent.parent);
         }
-      return s->median;
+      return s->ovalue;
 
     case CTSF_MODE:
-    case CTSF_PTILE:
-      NOT_REACHED ();
+      if (s->writer)
+        {
+          struct casereader *reader = casewriter_make_reader (s->writer);
+          s->writer = NULL;
+
+          struct mode *mode = mode_create ();
+          struct order_stats *os = &mode->parent;
+          order_stats_accumulate_idx (&os, 1, reader, 1, 0);
+          s->ovalue = mode->mode;
+          statistic_destroy (&mode->parent.parent);
+        }
+      return s->ovalue;
 
     case CTSF_RESPONSES:
     case CTSF_ROWPCT_RESPONSES: