Don't crash on Games-Howell test when there are small numbers of cases per category.
authorJohn Darrington <john@darrington.wattle.id.au>
Thu, 26 Jan 2012 21:39:33 +0000 (22:39 +0100)
committerJohn Darrington <john@darrington.wattle.id.au>
Thu, 26 Jan 2012 21:39:33 +0000 (22:39 +0100)
Fixes bug #34978

lib/tukey/ptukey.c
lib/tukey/qtukey.c
src/language/stats/oneway.c
tests/language/stats/oneway.at

index c86ef23613c0766e90681dfdabc25c026257c58f..9a89104cf90e78f206a002e611d850b5ad922eb6 100644 (file)
@@ -371,9 +371,7 @@ ptukey (double q, double rr, double cc, double df, int lower_tail, int log_p)
   double ans, f2, f21, f2lf, ff4, otsum, qsqz, rotsum, t1, twa1, ulen, wprb;
   int i, j, jj;
 
-#ifdef IEEE_754
-  abort (! (ISNAN (q) || ISNAN (rr) || ISNAN (cc) || ISNAN (df)));
-#endif
+  assert (! (isnan (q) || isnan (rr) || isnan (cc) || isnan (df)));
 
   if (q <= 0)
     return R_DT_0;
index 08253df7546b4bb051cedc0e957b3215512e1d14..ec146001420eca7d4876e6af12a813efe3f206da 100644 (file)
 
 static double fmax2(double x, double y)
 {
-#ifdef IEEE_754
-       if (ISNAN(x) || ISNAN(y))
+       if (isnan(x) || isnan(y))
                return x + y;
-#endif
        return (x < y) ? y : x;
 }
 
@@ -188,15 +186,20 @@ double qtukey(double p, double rr, double cc, double df,
     double ans = 0.0, valx0, valx1, x0, x1, xabs;
     int iter;
 
-#ifdef IEEE_754
-    if (ISNAN(p) || ISNAN(rr) || ISNAN(cc) || ISNAN(df)) {
-       ML_ERROR(ME_DOMAIN, "qtukey");
+    if (isnan(p) || isnan(rr) || isnan(cc) || isnan(df)) {
+      /*       ML_ERROR(ME_DOMAIN, "qtukey"); */
        return p + rr + cc + df;
     }
-#endif
 
     /* df must be > 1 ; there must be at least two values */
-    assert (! (df < 2 || rr < 1 || cc < 2) );
+    /*              ^^ 
+       JMD: The comment says 1 but the code says 2.
+       Which is correct?
+    */
+    assert (df >= 2);
+    assert (rr >= 1);
+    assert (cc >= 2);
+    
 
     R_Q_P01_boundaries (p, 0, ML_POSINF);
 
index 2c401f56270de4c6f97852c300bd583d6ebd6189..5ea77473720b6c34a7149ae252508ccd523805a6 100644 (file)
@@ -164,6 +164,9 @@ df_individual (const struct per_var_ws *pvw UNUSED, const struct moments1 *mom_i
 
   moments1_calculate (mom_i, &n_i, NULL, &var_i, 0, 0);  
   moments1_calculate (mom_j, &n_j, NULL, &var_j, 0, 0);
+  
+  if ( n_i <= 1.0 || n_j <= 1.0)
+    return SYSMIS;
 
   nom = pow2 (var_i/n_i + var_j/n_j);
   denom = pow2 (var_i/n_i) / (n_i - 1) + pow2 (var_j/n_j) / (n_j - 1);
@@ -191,6 +194,9 @@ static double sidak_pinv (double std_err, double alpha, double df, int k, const
 
 static double tukey_pinv (double std_err, double alpha, double df, int k, const struct moments1 *mom_i UNUSED, const struct moments1 *mom_j UNUSED)
 {
+  if ( k < 2 || df < 2)
+    return SYSMIS;
+
   return std_err / sqrt (2.0)  * qtukey (1 - alpha, 1.0, k, df, 1, 0);
 }
 
@@ -211,6 +217,9 @@ static double gh_pinv (double std_err UNUSED, double alpha, double df, int k, co
 
   m = sqrt ((var_i/n_i + var_j/n_j) / 2.0);
 
+  if ( k < 2 || df < 2)
+    return SYSMIS;
+
   return m * qtukey (1 - alpha, 1.0, k, df, 1, 0);
 }
 
@@ -224,6 +233,8 @@ multiple_comparison_sig (double std_err,
   int k = pvw->n_groups;
   double df = ph->dff (pvw, dd_i->mom, dd_j->mom);
   double ts = ph->tsf (k, dd_i->mom, dd_j->mom, std_err);
+  if ( df == SYSMIS)
+    return SYSMIS;
   return  ph->p1f (ts, k - 1, df);
 }
 
@@ -232,13 +243,20 @@ mc_half_range (const struct oneway_spec *cmd, const struct per_var_ws *pvw, doub
 {
   int k = pvw->n_groups;
   double df = ph->dff (pvw, dd_i->mom, dd_j->mom);
+  if ( df == SYSMIS)
+    return SYSMIS;
 
   return ph->pinv (std_err, cmd->alpha, df, k, dd_i->mom, dd_j->mom);
 }
 
 static double tukey_1tailsig (double ts, double df1, double df2)
 {
-  double twotailedsig = 1.0 - ptukey (ts, 1.0, df1 + 1, df2, 1, 0);
+  double twotailedsig;
+
+  if (df2 < 2 || df1 < 1)
+    return SYSMIS;
+
+  twotailedsig = 1.0 - ptukey (ts, 1.0, df1 + 1, df2, 1, 0);
 
   return twotailedsig / 2.0;
 }
index 7602eff465c7295c2c1832ecce550c36c492382b..dfb43bbe909bafafbae78cb46f7a31eea9dc3029 100644 (file)
@@ -948,3 +948,27 @@ ONEWAY
 AT_CHECK([pspp -O format=csv crash2.sps], [0], [ignore])
 
 AT_CLEANUP
+
+
+
+
+AT_SETUP([ONEWAY Games-Howell test with few cases])
+AT_DATA([crash3.sps],[dnl
+data list notable list /dv * y * .
+begin data.
+2 2
+1 2
+1 1
+2 4
+3 4
+end data.
+
+ONEWAY
+ /VARIABLES= dv BY y
+ /POSTHOC = GH
+ . 
+])
+
+AT_CHECK([pspp -O format=csv crash3.sps], [0], [ignore])
+
+AT_CLEANUP