1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2009, 2010, 2011 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include <gsl/gsl_cdf.h>
25 #include "data/case.h"
26 #include "data/casegrouper.h"
27 #include "data/casereader.h"
28 #include "data/dataset.h"
29 #include "data/dictionary.h"
30 #include "data/format.h"
31 #include "data/value-labels.h"
32 #include "data/variable.h"
33 #include "language/command.h"
34 #include "language/dictionary/split-file.h"
35 #include "language/lexer/lexer.h"
36 #include "language/lexer/value-parser.h"
37 #include "libpspp/array.h"
38 #include "libpspp/assertion.h"
39 #include "libpspp/compiler.h"
40 #include "libpspp/hash.h"
41 #include "libpspp/message.h"
42 #include "libpspp/misc.h"
43 #include "libpspp/str.h"
44 #include "libpspp/taint.h"
45 #include "math/correlation.h"
46 #include "math/group-proc.h"
47 #include "math/levene.h"
48 #include "output/tab.h"
50 #include "gl/minmax.h"
51 #include "gl/xalloc.h"
52 #include "gl/xmemdup0.h"
55 #define _(msgid) gettext (msgid)
63 +variables=varlist("PV_NO_SCRATCH | PV_NUMERIC");
65 missing=miss:!analysis/listwise,
66 incl:include/!exclude;
67 +format=fmt:!labels/nolabels;
68 criteria=:cin(d:criteria,"%s > 0. && %s < 1.").
79 /* A pair of variables to be compared. */
82 const struct variable *v[2]; /* The paired variables. */
83 double n; /* The number of valid variable pairs */
84 double sum[2]; /* The sum of the members */
85 double ssq[2]; /* sum of squares of the members */
86 double std_dev[2]; /* Std deviation of the members */
87 double s_std_dev[2]; /* Sample Std deviation of the members */
88 double mean[2]; /* The means of the members */
89 double correlation; /* Correlation coefficient between the variables. */
90 double sum_of_diffs; /* The sum of the differences */
91 double sum_of_prod; /* The sum of the products */
92 double mean_diff; /* The mean of the differences */
93 double ssq_diffs; /* The sum of the squares of the differences */
94 double std_dev_diff; /* The std deviation of the differences */
97 /* Which mode was T-TEST invoked */
99 T_1_SAMPLE, /* One-sample tests. */
100 T_IND_SAMPLES, /* Independent-sample tests. */
101 T_PAIRED /* Paired-sample tests. */
104 /* Total state of a T-TEST procedure. */
107 enum t_test_mode mode; /* Mode that T-TEST was invoked in. */
108 double criteria; /* Confidence interval in (0, 1). */
109 enum mv_class exclude; /* Classes of missing values to exclude. */
110 bool listwise_missing; /* Drop whole case if one missing var? */
111 struct fmt_spec weight_format; /* Format of weight variable. */
113 /* Dependent variables. */
114 const struct variable **vars;
117 /* For mode == T_1_SAMPLE. */
120 /* For mode == T_PAIRED only. */
124 /* For mode == T_IND_SAMPLES only. */
125 struct variable *indep_var; /* Independent variable. */
126 enum comparison criterion; /* Type of comparison. */
127 double critical_value; /* CMP_LE only: Grouping threshold value. */
128 union value g_value[2]; /* CMP_EQ only: Per-group indep var values. */
131 /* Statistics Summary Box */
135 void (*populate) (struct ssbox *, struct t_test_proc *);
136 void (*finalize) (struct ssbox *);
139 static void ssbox_create (struct ssbox *, struct t_test_proc *);
140 static void ssbox_populate (struct ssbox *, struct t_test_proc *);
141 static void ssbox_finalize (struct ssbox *);
143 /* Paired Samples Correlation box */
144 static void pscbox (struct t_test_proc *);
147 /* Test Results Box. */
150 void (*populate) (struct trbox *, struct t_test_proc *);
151 void (*finalize) (struct trbox *);
154 static void trbox_create (struct trbox *, struct t_test_proc *);
155 static void trbox_populate (struct trbox *, struct t_test_proc *);
156 static void trbox_finalize (struct trbox *);
158 static void calculate (struct t_test_proc *, struct casereader *,
159 const struct dataset *);
161 static int compare_group_binary (const struct group_statistics *a,
162 const struct group_statistics *b,
163 const struct t_test_proc *);
164 static unsigned hash_group_binary (const struct group_statistics *g,
165 const struct t_test_proc *p);
167 static void t_test_proc_destroy (struct t_test_proc *proc);
170 cmd_t_test (struct lexer *lexer, struct dataset *ds)
172 struct cmd_t_test cmd;
173 struct t_test_proc proc;
174 struct casegrouper *grouper;
175 struct casereader *group;
182 proc.indep_var = NULL;
183 if (!parse_t_test (lexer, ds, &cmd, &proc))
186 wv = dict_get_weight (dataset_dict (ds));
187 proc.weight_format = wv ? *var_get_print_format (wv) : F_8_0;
189 if ((cmd.sbc_testval != 0) + (cmd.sbc_groups != 0) + (cmd.sbc_pairs != 0)
192 msg (SE, _("Exactly one of TESTVAL, GROUPS and PAIRS subcommands "
193 "must be specified."));
197 proc.mode = (cmd.sbc_testval ? T_1_SAMPLE
198 : cmd.sbc_groups ? T_IND_SAMPLES
200 proc.criteria = cmd.sbc_criteria ? cmd.criteria : 0.95;
201 proc.exclude = cmd.incl != TTS_INCLUDE ? MV_ANY : MV_SYSTEM;
202 proc.listwise_missing = cmd.miss == TTS_LISTWISE;
204 if (proc.mode == T_1_SAMPLE)
205 proc.testval = cmd.n_testval[0];
207 if (proc.mode == T_PAIRED)
211 if (cmd.sbc_variables)
213 msg (SE, _("VARIABLES subcommand may not be used with PAIRS."));
217 /* Fill proc.vars with the unique variables from pairs. */
218 proc.n_vars = proc.n_pairs * 2;
219 proc.vars = xmalloc (sizeof *proc.vars * proc.n_vars);
220 for (i = j = 0; i < proc.n_pairs; i++)
222 proc.vars[j++] = proc.pairs[i].v[0];
223 proc.vars[j++] = proc.pairs[i].v[1];
225 proc.n_vars = sort_unique (proc.vars, proc.n_vars, sizeof *proc.vars,
226 compare_var_ptrs_by_name, NULL);
230 if (!cmd.n_variables)
232 msg (SE, _("One or more VARIABLES must be specified."));
235 proc.n_vars = cmd.n_variables;
236 proc.vars = cmd.v_variables;
237 cmd.v_variables = NULL;
241 grouper = casegrouper_create_splits (proc_open (ds), dataset_dict (ds));
242 while (casegrouper_get_next_group (grouper, &group))
243 calculate (&proc, group, ds);
244 ok = casegrouper_destroy (grouper);
246 /* Free 'proc' then commit the procedure. Must happen in this order because
247 if proc->indep_var was created by a temporary transformation then
248 committing will destroy it. */
249 t_test_proc_destroy (&proc);
250 ok = proc_commit (ds) && ok;
252 return ok ? CMD_SUCCESS : CMD_FAILURE;
257 t_test_proc_destroy (&proc);
262 t_test_proc_destroy (struct t_test_proc *proc)
264 if (proc->indep_var != NULL)
266 int width = var_get_width (proc->indep_var);
267 value_destroy (&proc->g_value[0], width);
268 value_destroy (&proc->g_value[1], width);
275 tts_custom_groups (struct lexer *lexer, struct dataset *ds,
276 struct cmd_t_test *cmd UNUSED, void *proc_)
278 struct t_test_proc *proc = proc_;
282 lex_match (lexer, T_EQUALS);
284 proc->indep_var = parse_variable (lexer, dataset_dict (ds));
285 if (proc->indep_var == NULL)
287 lex_error (lexer, "expecting variable name in GROUPS subcommand");
290 width = var_get_width (proc->indep_var);
291 value_init (&proc->g_value[0], width);
292 value_init (&proc->g_value[1], width);
294 if (!lex_match (lexer, T_LPAREN))
298 if (!parse_value (lexer, &proc->g_value[0], width))
300 lex_match (lexer, T_COMMA);
301 if (lex_match (lexer, T_RPAREN))
305 if (!parse_value (lexer, &proc->g_value[1], width)
306 || !lex_force_match (lexer, T_RPAREN))
312 if (var_is_numeric (proc->indep_var))
314 proc->criterion = n_values == 1 ? CMP_LE : CMP_EQ;
316 proc->critical_value = proc->g_value[0].f;
317 else if (n_values == 0)
319 proc->g_value[0].f = 1;
320 proc->g_value[1].f = 2;
325 proc->criterion = CMP_EQ;
328 msg (SE, _("When applying GROUPS to a string variable, two "
329 "values must be specified."));
337 add_pair (struct t_test_proc *proc,
338 const struct variable *v0, const struct variable *v1)
340 struct pair *p = &proc->pairs[proc->n_pairs++];
346 tts_custom_pairs (struct lexer *lexer, struct dataset *ds,
347 struct cmd_t_test *cmd UNUSED, void *proc_)
349 struct t_test_proc *proc = proc_;
351 const struct variable **vars1 = NULL;
354 const struct variable **vars2 = NULL;
359 size_t n_total_pairs;
362 lex_match (lexer, T_EQUALS);
364 if (!parse_variables_const (lexer, dataset_dict (ds), &vars1, &n_vars1,
365 PV_DUPLICATE | PV_NUMERIC | PV_NO_SCRATCH))
368 if (lex_match (lexer, T_WITH))
370 if (!parse_variables_const (lexer, dataset_dict (ds), &vars2, &n_vars2,
371 PV_DUPLICATE | PV_NUMERIC | PV_NO_SCRATCH))
377 if (lex_match (lexer, T_LPAREN)
378 && lex_match_id (lexer, "PAIRED")
379 && lex_match (lexer, T_RPAREN))
382 if (n_vars1 != n_vars2)
384 msg (SE, _("PAIRED was specified but the number of variables "
385 "preceding WITH (%zu) did not match the number "
399 msg (SE, _("At least two variables must be specified on PAIRS."));
404 /* Allocate storage for the new pairs. */
405 n_total_pairs = proc->n_pairs + (paired ? n_vars1
406 : n_vars2 > 0 ? n_vars1 * n_vars2
407 : n_vars1 * (n_vars1 - 1) / 2);
408 proc->pairs = xnrealloc (proc->pairs, n_total_pairs, sizeof *proc->pairs);
410 /* Populate the pairs with the appropriate variables. */
412 for (i = 0; i < n_vars1; i++)
413 add_pair (proc, vars1[i], vars2[i]);
414 else if (n_vars2 > 0)
415 for (i = 0; i < n_vars1; i++)
416 for (j = 0; j < n_vars2; j++)
417 add_pair (proc, vars1[i], vars2[j]);
419 for (i = 0; i < n_vars1; i++)
420 for (j = i + 1; j < n_vars1; j++)
421 add_pair (proc, vars1[i], vars1[j]);
422 assert (proc->n_pairs == n_total_pairs);
429 /* Implementation of the SSBOX object. */
431 static void ssbox_base_init (struct ssbox *, int cols, int rows);
432 static void ssbox_base_finalize (struct ssbox *);
433 static void ssbox_one_sample_init (struct ssbox *, struct t_test_proc *);
434 static void ssbox_independent_samples_init (struct ssbox *, struct t_test_proc *);
435 static void ssbox_paired_init (struct ssbox *, struct t_test_proc *);
437 /* Factory to create an ssbox. */
439 ssbox_create (struct ssbox *ssb, struct t_test_proc *proc)
444 ssbox_one_sample_init (ssb, proc);
447 ssbox_independent_samples_init (ssb, proc);
450 ssbox_paired_init (ssb, proc);
457 /* Despatcher for the populate method */
459 ssbox_populate (struct ssbox *ssb, struct t_test_proc *proc)
461 ssb->populate (ssb, proc);
464 /* Despatcher for finalize */
466 ssbox_finalize (struct ssbox *ssb)
471 /* Submit the box and clear up */
473 ssbox_base_finalize (struct ssbox *ssb)
478 /* Initialize a ssbox struct */
480 ssbox_base_init (struct ssbox *this, int cols, int rows)
482 this->finalize = ssbox_base_finalize;
483 this->t = tab_create (cols, rows);
485 tab_headers (this->t, 0, 0, 1, 0);
486 tab_box (this->t, TAL_2, TAL_2, TAL_0, TAL_1, 0, 0, cols - 1, rows - 1);
487 tab_hline (this->t, TAL_2, 0, cols- 1, 1);
490 /* ssbox implementations. */
492 static void ssbox_one_sample_populate (struct ssbox *, struct t_test_proc *);
493 static void ssbox_independent_samples_populate (struct ssbox *,
494 struct t_test_proc *);
495 static void ssbox_paired_populate (struct ssbox *, struct t_test_proc *);
497 /* Initialize the one_sample ssbox */
499 ssbox_one_sample_init (struct ssbox *this, struct t_test_proc *proc)
502 const int vsize = proc->n_vars + 1;
504 this->populate = ssbox_one_sample_populate;
506 ssbox_base_init (this, hsize, vsize);
507 tab_title (this->t, _("One-Sample Statistics"));
508 tab_vline (this->t, TAL_2, 1, 0, vsize - 1);
509 tab_text (this->t, 1, 0, TAB_CENTER | TAT_TITLE, _("N"));
510 tab_text (this->t, 2, 0, TAB_CENTER | TAT_TITLE, _("Mean"));
511 tab_text (this->t, 3, 0, TAB_CENTER | TAT_TITLE, _("Std. Deviation"));
512 tab_text (this->t, 4, 0, TAB_CENTER | TAT_TITLE, _("S.E. Mean"));
515 /* Initialize the independent samples ssbox */
517 ssbox_independent_samples_init (struct ssbox *this, struct t_test_proc *proc)
520 int vsize = proc->n_vars * 2 + 1;
522 this->populate = ssbox_independent_samples_populate;
524 ssbox_base_init (this, hsize, vsize);
525 tab_vline (this->t, TAL_GAP, 1, 0, vsize - 1);
526 tab_title (this->t, _("Group Statistics"));
527 tab_text (this->t, 1, 0, TAB_CENTER | TAT_TITLE,
528 var_get_name (proc->indep_var));
529 tab_text (this->t, 2, 0, TAB_CENTER | TAT_TITLE, _("N"));
530 tab_text (this->t, 3, 0, TAB_CENTER | TAT_TITLE, _("Mean"));
531 tab_text (this->t, 4, 0, TAB_CENTER | TAT_TITLE, _("Std. Deviation"));
532 tab_text (this->t, 5, 0, TAB_CENTER | TAT_TITLE, _("S.E. Mean"));
535 /* Populate the ssbox for independent samples */
537 ssbox_independent_samples_populate (struct ssbox *ssb,
538 struct t_test_proc *proc)
543 double indep_value[2];
547 for (i = 0; i < 2; i++)
549 union value *value = &proc->g_value[i];
550 int width = var_get_width (proc->indep_var);
552 indep_value[i] = (proc->criterion == CMP_LE ? proc->critical_value
555 if (val_type_from_width (width) == VAL_NUMERIC)
557 const char *s = var_lookup_value_label (proc->indep_var, value);
558 val_lab[i] = s ? xstrdup (s) : xasprintf ("%g", indep_value[i]);
561 val_lab[i] = xmemdup0 (value_str (value, width), width);
564 if (proc->criterion == CMP_LE)
566 strcpy (prefix[0], ">=");
567 strcpy (prefix[1], "<");
571 strcpy (prefix[0], "");
572 strcpy (prefix[1], "");
575 for (i = 0; i < proc->n_vars; i++)
577 const struct variable *var = proc->vars[i];
578 struct hsh_table *grp_hash = group_proc_get (var)->group_hash;
581 tab_text (ssb->t, 0, i * 2 + 1, TAB_LEFT,
582 var_get_name (proc->vars[i]));
583 tab_text_format (ssb->t, 1, i * 2 + 1, TAB_LEFT,
584 "%s%s", prefix[0], val_lab[0]);
585 tab_text_format (ssb->t, 1, i * 2 + 1+ 1, TAB_LEFT,
586 "%s%s", prefix[1], val_lab[1]);
588 /* Fill in the group statistics */
589 for (count = 0; count < 2; count++)
591 union value search_val;
592 struct group_statistics *gs;
594 if (proc->criterion == CMP_LE)
595 search_val.f = proc->critical_value + (count == 0 ? 1.0 : -1.0);
597 search_val = proc->g_value[count];
599 gs = hsh_find (grp_hash, &search_val);
602 tab_double (ssb->t, 2, i * 2 + count+ 1, TAB_RIGHT, gs->n,
603 &proc->weight_format);
604 tab_double (ssb->t, 3, i * 2 + count+ 1, TAB_RIGHT, gs->mean, NULL);
605 tab_double (ssb->t, 4, i * 2 + count+ 1, TAB_RIGHT, gs->std_dev,
607 tab_double (ssb->t, 5, i * 2 + count+ 1, TAB_RIGHT, gs->se_mean,
615 /* Initialize the paired values ssbox */
617 ssbox_paired_init (struct ssbox *this, struct t_test_proc *proc)
620 int vsize = proc->n_pairs * 2 + 1;
622 this->populate = ssbox_paired_populate;
624 ssbox_base_init (this, hsize, vsize);
625 tab_title (this->t, _("Paired Sample Statistics"));
626 tab_vline (this->t, TAL_GAP, 1, 0, vsize - 1);
627 tab_vline (this->t, TAL_2, 2, 0, vsize - 1);
628 tab_text (this->t, 2, 0, TAB_CENTER | TAT_TITLE, _("Mean"));
629 tab_text (this->t, 3, 0, TAB_CENTER | TAT_TITLE, _("N"));
630 tab_text (this->t, 4, 0, TAB_CENTER | TAT_TITLE, _("Std. Deviation"));
631 tab_text (this->t, 5, 0, TAB_CENTER | TAT_TITLE, _("S.E. Mean"));
634 /* Populate the ssbox for paired values */
636 ssbox_paired_populate (struct ssbox *ssb, struct t_test_proc *proc)
640 for (i = 0; i < proc->n_pairs; i++)
642 struct pair *p = &proc->pairs[i];
645 tab_text_format (ssb->t, 0, i * 2 + 1, TAB_LEFT, _("Pair %d"), i);
646 for (j=0; j < 2; j++)
649 tab_text (ssb->t, 1, i * 2 + j + 1, TAB_LEFT,
650 var_get_name (p->v[j]));
653 tab_double (ssb->t, 2, i * 2 + j + 1, TAB_RIGHT, p->mean[j], NULL);
654 tab_double (ssb->t, 3, i * 2 + j + 1, TAB_RIGHT, p->n,
655 &proc->weight_format);
656 tab_double (ssb->t, 4, i * 2 + j + 1, TAB_RIGHT, p->std_dev[j],
658 tab_double (ssb->t, 5, i * 2 + j + 1, TAB_RIGHT,
659 p->std_dev[j] /sqrt (p->n), NULL);
664 /* Populate the one sample ssbox */
666 ssbox_one_sample_populate (struct ssbox *ssb, struct t_test_proc *proc)
670 for (i = 0; i < proc->n_vars; i++)
672 struct group_statistics *gs = &group_proc_get (proc->vars[i])->ugs;
674 tab_text (ssb->t, 0, i + 1, TAB_LEFT, var_get_name (proc->vars[i]));
675 tab_double (ssb->t, 1, i + 1, TAB_RIGHT, gs->n, &proc->weight_format);
676 tab_double (ssb->t, 2, i + 1, TAB_RIGHT, gs->mean, NULL);
677 tab_double (ssb->t, 3, i + 1, TAB_RIGHT, gs->std_dev, NULL);
678 tab_double (ssb->t, 4, i + 1, TAB_RIGHT, gs->se_mean, NULL);
682 /* Implementation of the Test Results box struct */
684 static void trbox_base_init (struct trbox *, size_t n_vars, int cols);
685 static void trbox_base_finalize (struct trbox *);
686 static void trbox_independent_samples_init (struct trbox *,
687 struct t_test_proc *);
688 static void trbox_independent_samples_populate (struct trbox *,
689 struct t_test_proc *);
690 static void trbox_one_sample_init (struct trbox *, struct t_test_proc *);
691 static void trbox_one_sample_populate (struct trbox *, struct t_test_proc *);
692 static void trbox_paired_init (struct trbox *, struct t_test_proc *);
693 static void trbox_paired_populate (struct trbox *, struct t_test_proc *);
695 /* Create a trbox according to mode*/
697 trbox_create (struct trbox *trb, struct t_test_proc *proc)
702 trbox_one_sample_init (trb, proc);
705 trbox_independent_samples_init (trb, proc);
708 trbox_paired_init (trb, proc);
715 /* Populate a trbox according to proc */
717 trbox_populate (struct trbox *trb, struct t_test_proc *proc)
719 trb->populate (trb, proc);
722 /* Submit and destroy a trbox */
724 trbox_finalize (struct trbox *trb)
729 /* Initialize the independent samples trbox */
731 trbox_independent_samples_init (struct trbox *self,
732 struct t_test_proc *proc)
734 const int hsize = 11;
735 const int vsize = proc->n_vars * 2 + 3;
738 self->populate = trbox_independent_samples_populate;
740 trbox_base_init (self, proc->n_vars * 2, hsize);
741 tab_title (self->t, _("Independent Samples Test"));
742 tab_hline (self->t, TAL_1, 2, hsize - 1, 1);
743 tab_vline (self->t, TAL_2, 2, 0, vsize - 1);
744 tab_vline (self->t, TAL_1, 4, 0, vsize - 1);
745 tab_box (self->t, -1, -1, -1, TAL_1, 2, 1, hsize - 2, vsize - 1);
746 tab_hline (self->t, TAL_1, hsize - 2, hsize - 1, 2);
747 tab_box (self->t, -1, -1, -1, TAL_1, hsize - 2, 2, hsize - 1, vsize - 1);
748 tab_joint_text (self->t, 2, 0, 3, 0,
749 TAB_CENTER, _("Levene's Test for Equality of Variances"));
750 tab_joint_text (self->t, 4, 0, hsize- 1, 0,
751 TAB_CENTER, _("t-test for Equality of Means"));
753 tab_text (self->t, 2, 2, TAB_CENTER | TAT_TITLE, _("F"));
754 tab_text (self->t, 3, 2, TAB_CENTER | TAT_TITLE, _("Sig."));
755 tab_text (self->t, 4, 2, TAB_CENTER | TAT_TITLE, _("t"));
756 tab_text (self->t, 5, 2, TAB_CENTER | TAT_TITLE, _("df"));
757 tab_text (self->t, 6, 2, TAB_CENTER | TAT_TITLE, _("Sig. (2-tailed)"));
758 tab_text (self->t, 7, 2, TAB_CENTER | TAT_TITLE, _("Mean Difference"));
759 tab_text (self->t, 8, 2, TAB_CENTER | TAT_TITLE, _("Std. Error Difference"));
760 tab_text (self->t, 9, 2, TAB_CENTER | TAT_TITLE, _("Lower"));
761 tab_text (self->t, 10, 2, TAB_CENTER | TAT_TITLE, _("Upper"));
763 tab_joint_text_format (self->t, 9, 1, 10, 1, TAB_CENTER,
764 _("%g%% Confidence Interval of the Difference"),
765 proc->criteria * 100.0);
768 /* Populate the independent samples trbox */
770 trbox_independent_samples_populate (struct trbox *self,
771 struct t_test_proc *proc)
775 for (i = 0; i < proc->n_vars; i++)
784 double pooled_variance;
790 const struct variable *var = proc->vars[i];
791 struct group_proc *grp_data = group_proc_get (var);
793 struct hsh_table *grp_hash = grp_data->group_hash;
795 struct group_statistics *gs0;
796 struct group_statistics *gs1;
798 union value search_val;
800 if (proc->criterion == CMP_LE)
801 search_val.f = proc->critical_value - 1.0;
803 search_val = proc->g_value[0];
805 gs0 = hsh_find (grp_hash, &search_val);
808 if (proc->criterion == CMP_LE)
809 search_val.f = proc->critical_value + 1.0;
811 search_val = proc->g_value[1];
813 gs1 = hsh_find (grp_hash, &search_val);
817 tab_text (self->t, 0, i * 2 + 3, TAB_LEFT, var_get_name (proc->vars[i]));
818 tab_text (self->t, 1, i * 2 + 3, TAB_LEFT, _("Equal variances assumed"));
819 tab_double (self->t, 2, i * 2 + 3, TAB_CENTER, grp_data->levene, NULL);
821 /* Now work out the significance of the Levene test */
823 df2 = grp_data->ugs.n - 2;
824 q = gsl_cdf_fdist_Q (grp_data->levene, df1, df2);
825 tab_double (self->t, 3, i * 2 + 3, TAB_CENTER, q, NULL);
827 df = gs0->n + gs1->n - 2.0;
828 tab_double (self->t, 5, i * 2 + 3, TAB_RIGHT, df, NULL);
830 pooled_variance = (gs0->n * pow2 (gs0->s_std_dev)
831 + gs1->n *pow2 (gs1->s_std_dev)) / df ;
833 t = (gs0->mean - gs1->mean) / sqrt (pooled_variance);
834 t /= sqrt ((gs0->n + gs1->n) / (gs0->n * gs1->n));
836 tab_double (self->t, 4, i * 2 + 3, TAB_RIGHT, t, NULL);
838 p = gsl_cdf_tdist_P (t, df);
839 q = gsl_cdf_tdist_Q (t, df);
841 tab_double (self->t, 6, i * 2 + 3, TAB_RIGHT, 2.0 * (t > 0 ? q : p),
844 mean_diff = gs0->mean - gs1->mean;
845 tab_double (self->t, 7, i * 2 + 3, TAB_RIGHT, mean_diff, NULL);
848 std_err_diff = sqrt (pow2 (gs0->se_mean) + pow2 (gs1->se_mean));
849 tab_double (self->t, 8, i * 2 + 3, TAB_RIGHT, std_err_diff, NULL);
851 /* Now work out the confidence interval */
852 q = (1 - proc->criteria)/2.0; /* 2-tailed test */
854 t = gsl_cdf_tdist_Qinv (q, df);
855 tab_double (self->t, 9, i * 2 + 3, TAB_RIGHT,
856 mean_diff - t * std_err_diff, NULL);
858 tab_double (self->t, 10, i * 2 + 3, TAB_RIGHT,
859 mean_diff + t * std_err_diff, NULL);
862 /* Now for the \sigma_1 != \sigma_2 case */
863 tab_text (self->t, 1, i * 2 + 3 + 1,
864 TAB_LEFT, _("Equal variances not assumed"));
866 se2 = ((pow2 (gs0->s_std_dev) / (gs0->n - 1)) +
867 (pow2 (gs1->s_std_dev) / (gs1->n - 1)));
869 t = mean_diff / sqrt (se2);
870 tab_double (self->t, 4, i * 2 + 3 + 1, TAB_RIGHT, t, NULL);
872 df = pow2 (se2) / ((pow2 (pow2 (gs0->s_std_dev) / (gs0->n - 1))
874 + (pow2 (pow2 (gs1->s_std_dev) / (gs1->n - 1))
876 tab_double (self->t, 5, i * 2 + 3 + 1, TAB_RIGHT, df, NULL);
878 p = gsl_cdf_tdist_P (t, df);
879 q = gsl_cdf_tdist_Q (t, df);
881 tab_double (self->t, 6, i * 2 + 3 + 1, TAB_RIGHT, 2.0 * (t > 0 ? q : p),
884 /* Now work out the confidence interval */
885 q = (1 - proc->criteria) / 2.0; /* 2-tailed test */
887 t = gsl_cdf_tdist_Qinv (q, df);
889 tab_double (self->t, 7, i * 2 + 3 + 1, TAB_RIGHT, mean_diff, NULL);
890 tab_double (self->t, 8, i * 2 + 3 + 1, TAB_RIGHT, std_err_diff, NULL);
891 tab_double (self->t, 9, i * 2 + 3 + 1, TAB_RIGHT,
892 mean_diff - t * std_err_diff, NULL);
893 tab_double (self->t, 10, i * 2 + 3 + 1, TAB_RIGHT,
894 mean_diff + t * std_err_diff, NULL);
898 /* Initialize the paired samples trbox */
900 trbox_paired_init (struct trbox *self, struct t_test_proc *proc)
903 const int vsize=proc->n_pairs+ 3;
905 self->populate = trbox_paired_populate;
907 trbox_base_init (self, proc->n_pairs, hsize);
908 tab_title (self->t, _("Paired Samples Test"));
909 tab_hline (self->t, TAL_1, 2, 6, 1);
910 tab_vline (self->t, TAL_2, 2, 0, vsize - 1);
911 tab_joint_text (self->t, 2, 0, 6, 0, TAB_CENTER, _("Paired Differences"));
912 tab_box (self->t, -1, -1, -1, TAL_1, 2, 1, 6, vsize - 1);
913 tab_box (self->t, -1, -1, -1, TAL_1, 6, 0, hsize - 1, vsize - 1);
914 tab_hline (self->t, TAL_1, 5, 6, 2);
915 tab_vline (self->t, TAL_GAP, 6, 0, 1);
917 tab_joint_text_format (self->t, 5, 1, 6, 1, TAB_CENTER,
918 _("%g%% Confidence Interval of the Difference"),
919 proc->criteria*100.0);
921 tab_text (self->t, 2, 2, TAB_CENTER | TAT_TITLE, _("Mean"));
922 tab_text (self->t, 3, 2, TAB_CENTER | TAT_TITLE, _("Std. Deviation"));
923 tab_text (self->t, 4, 2, TAB_CENTER | TAT_TITLE, _("Std. Error Mean"));
924 tab_text (self->t, 5, 2, TAB_CENTER | TAT_TITLE, _("Lower"));
925 tab_text (self->t, 6, 2, TAB_CENTER | TAT_TITLE, _("Upper"));
926 tab_text (self->t, 7, 2, TAB_CENTER | TAT_TITLE, _("t"));
927 tab_text (self->t, 8, 2, TAB_CENTER | TAT_TITLE, _("df"));
928 tab_text (self->t, 9, 2, TAB_CENTER | TAT_TITLE, _("Sig. (2-tailed)"));
931 /* Populate the paired samples trbox */
933 trbox_paired_populate (struct trbox *trb,
934 struct t_test_proc *proc)
938 for (i = 0; i < proc->n_pairs; i++)
940 struct pair *pair = &proc->pairs[i];
948 tab_text_format (trb->t, 0, i + 3, TAB_LEFT, _("Pair %d"), i);
949 tab_text_format (trb->t, 1, i + 3, TAB_LEFT, "%s - %s",
950 var_get_name (pair->v[0]),
951 var_get_name (pair->v[1]));
952 tab_double (trb->t, 2, i + 3, TAB_RIGHT, pair->mean_diff, NULL);
953 tab_double (trb->t, 3, i + 3, TAB_RIGHT, pair->std_dev_diff, NULL);
956 se_mean = pair->std_dev_diff / sqrt (n);
957 tab_double (trb->t, 4, i + 3, TAB_RIGHT, se_mean, NULL);
959 /* Now work out the confidence interval */
960 q = (1 - proc->criteria) / 2.0; /* 2-tailed test */
962 t = gsl_cdf_tdist_Qinv (q, df);
964 tab_double (trb->t, 5, i + 3, TAB_RIGHT,
965 pair->mean_diff - t * se_mean, NULL);
966 tab_double (trb->t, 6, i + 3, TAB_RIGHT,
967 pair->mean_diff + t * se_mean, NULL);
969 t = ((pair->mean[0] - pair->mean[1])
970 / sqrt ((pow2 (pair->s_std_dev[0]) + pow2 (pair->s_std_dev[1])
971 - (2 * pair->correlation
972 * pair->s_std_dev[0] * pair->s_std_dev[1]))
975 tab_double (trb->t, 7, i + 3, TAB_RIGHT, t, NULL);
977 /* Degrees of freedom */
978 tab_double (trb->t, 8, i + 3, TAB_RIGHT, df, &proc->weight_format);
980 p = gsl_cdf_tdist_P (t,df);
981 q = gsl_cdf_tdist_Q (t,df);
983 tab_double (trb->t, 9, i + 3, TAB_RIGHT, 2.0 * (t > 0 ? q : p), NULL);
987 /* Initialize the one sample trbox */
989 trbox_one_sample_init (struct trbox *self, struct t_test_proc *proc)
992 const int vsize = proc->n_vars + 3;
994 self->populate = trbox_one_sample_populate;
996 trbox_base_init (self, proc->n_vars, hsize);
997 tab_title (self->t, _("One-Sample Test"));
998 tab_hline (self->t, TAL_1, 1, hsize - 1, 1);
999 tab_vline (self->t, TAL_2, 1, 0, vsize - 1);
1001 tab_joint_text_format (self->t, 1, 0, hsize - 1, 0, TAB_CENTER,
1002 _("Test Value = %f"), proc->testval);
1004 tab_box (self->t, -1, -1, -1, TAL_1, 1, 1, hsize - 1, vsize - 1);
1007 tab_joint_text_format (self->t, 5, 1, 6, 1, TAB_CENTER,
1008 _("%g%% Confidence Interval of the Difference"),
1009 proc->criteria * 100.0);
1011 tab_vline (self->t, TAL_GAP, 6, 1, 1);
1012 tab_hline (self->t, TAL_1, 5, 6, 2);
1013 tab_text (self->t, 1, 2, TAB_CENTER | TAT_TITLE, _("t"));
1014 tab_text (self->t, 2, 2, TAB_CENTER | TAT_TITLE, _("df"));
1015 tab_text (self->t, 3, 2, TAB_CENTER | TAT_TITLE, _("Sig. (2-tailed)"));
1016 tab_text (self->t, 4, 2, TAB_CENTER | TAT_TITLE, _("Mean Difference"));
1017 tab_text (self->t, 5, 2, TAB_CENTER | TAT_TITLE, _("Lower"));
1018 tab_text (self->t, 6, 2, TAB_CENTER | TAT_TITLE, _("Upper"));
1021 /* Populate the one sample trbox */
1023 trbox_one_sample_populate (struct trbox *trb, struct t_test_proc *proc)
1029 for (i = 0; i < proc->n_vars; i++)
1034 struct group_statistics *gs = &group_proc_get (proc->vars[i])->ugs;
1036 tab_text (trb->t, 0, i + 3, TAB_LEFT, var_get_name (proc->vars[i]));
1038 t = (gs->mean - proc->testval) * sqrt (gs->n) / gs->std_dev;
1040 tab_double (trb->t, 1, i + 3, TAB_RIGHT, t, NULL);
1042 /* degrees of freedom */
1045 tab_double (trb->t, 2, i + 3, TAB_RIGHT, df, &proc->weight_format);
1047 p = gsl_cdf_tdist_P (t, df);
1048 q = gsl_cdf_tdist_Q (t, df);
1050 /* Multiply by 2 to get 2-tailed significance, makeing sure we've got
1052 tab_double (trb->t, 3, i + 3, TAB_RIGHT, 2.0 * (t > 0 ? q : p), NULL);
1053 tab_double (trb->t, 4, i + 3, TAB_RIGHT, gs->mean_diff, NULL);
1056 q = (1 - proc->criteria) / 2.0; /* 2-tailed test */
1057 t = gsl_cdf_tdist_Qinv (q, df);
1059 tab_double (trb->t, 5, i + 3, TAB_RIGHT,
1060 gs->mean_diff - t * gs->se_mean, NULL);
1061 tab_double (trb->t, 6, i + 3, TAB_RIGHT,
1062 gs->mean_diff + t * gs->se_mean, NULL);
1066 /* Base initializer for the generalized trbox */
1068 trbox_base_init (struct trbox *self, size_t data_rows, int cols)
1070 const size_t rows = 3 + data_rows;
1072 self->finalize = trbox_base_finalize;
1073 self->t = tab_create (cols, rows);
1074 tab_headers (self->t, 0, 0, 3, 0);
1075 tab_box (self->t, TAL_2, TAL_2, TAL_0, TAL_0, 0, 0, cols - 1, rows - 1);
1076 tab_hline (self->t, TAL_2, 0, cols- 1, 3);
1079 /* Base finalizer for the trbox */
1081 trbox_base_finalize (struct trbox *trb)
1083 tab_submit (trb->t);
1086 /* Create, populate and submit the Paired Samples Correlation box */
1088 pscbox (struct t_test_proc *proc)
1090 const int rows=1+proc->n_pairs;
1094 struct tab_table *table;
1096 table = tab_create (cols, rows);
1098 tab_headers (table, 0, 0, 1, 0);
1099 tab_box (table, TAL_2, TAL_2, TAL_0, TAL_1, 0, 0, cols - 1, rows - 1);
1100 tab_hline (table, TAL_2, 0, cols - 1, 1);
1101 tab_vline (table, TAL_2, 2, 0, rows - 1);
1102 tab_title (table, _("Paired Samples Correlations"));
1104 /* column headings */
1105 tab_text (table, 2, 0, TAB_CENTER | TAT_TITLE, _("N"));
1106 tab_text (table, 3, 0, TAB_CENTER | TAT_TITLE, _("Correlation"));
1107 tab_text (table, 4, 0, TAB_CENTER | TAT_TITLE, _("Sig."));
1109 for (i = 0; i < proc->n_pairs; i++)
1111 struct pair *pair = &proc->pairs[i];
1114 tab_text_format (table, 0, i + 1, TAB_LEFT | TAT_TITLE,
1116 tab_text_format (table, 1, i + 1, TAB_LEFT | TAT_TITLE,
1118 var_get_name (pair->v[0]),
1119 var_get_name (pair->v[1]));
1122 tab_double (table, 2, i + 1, TAB_RIGHT, pair->n, &proc->weight_format);
1123 tab_double (table, 3, i + 1, TAB_RIGHT, pair->correlation, NULL);
1125 tab_double (table, 4, i + 1, TAB_RIGHT,
1126 2.0 * significance_of_correlation (pair->correlation, pair->n), NULL);
1132 /* Calculation Implementation */
1134 /* Calculations common to all variants of the T test. */
1136 common_calc (const struct dictionary *dict,
1137 struct t_test_proc *proc,
1138 struct casereader *reader)
1143 for (i = 0; i < proc->n_vars; i++)
1145 struct group_statistics *gs = &group_proc_get (proc->vars[i])->ugs;
1152 for (; (c = casereader_read (reader)) != NULL; case_unref (c))
1154 double weight = dict_get_case_weight (dict, c, NULL);
1156 /* Listwise has to be implicit if the independent variable
1158 if (proc->mode == T_IND_SAMPLES)
1160 if (var_is_value_missing (proc->indep_var,
1161 case_data (c, proc->indep_var),
1166 for (i = 0; i < proc->n_vars; i++)
1168 const struct variable *v = proc->vars[i];
1169 const union value *val = case_data (c, v);
1171 if (!var_is_value_missing (v, val, proc->exclude))
1173 struct group_statistics *gs;
1174 gs = &group_proc_get (v)->ugs;
1177 gs->sum += weight * val->f;
1178 gs->ssq += weight * pow2 (val->f);
1182 casereader_destroy (reader);
1184 for (i = 0; i < proc->n_vars; i++)
1186 struct group_statistics *gs = &group_proc_get (proc->vars[i])->ugs;
1188 gs->mean = gs->sum / gs->n;
1189 gs->s_std_dev = sqrt (((gs->ssq / gs->n) - pow2 (gs->mean)));
1190 gs->std_dev = sqrt (gs->n / (gs->n- 1)
1191 * ((gs->ssq / gs->n) - pow2 (gs->mean)));
1192 gs->se_mean = gs->std_dev / sqrt (gs->n);
1193 gs->mean_diff = gs->sum_diff / gs->n;
1197 /* Calculations for one sample T test. */
1199 one_sample_calc (const struct dictionary *dict, struct t_test_proc *proc,
1200 struct casereader *reader)
1205 for (i = 0; i < proc->n_vars; i++)
1207 struct group_statistics *gs = &group_proc_get (proc->vars[i])->ugs;
1211 for (; (c = casereader_read (reader)) != NULL; case_unref (c))
1213 double weight = dict_get_case_weight (dict, c, NULL);
1214 for (i = 0; i < proc->n_vars; i++)
1216 const struct variable *v = proc->vars[i];
1217 struct group_statistics *gs = &group_proc_get (v)->ugs;
1218 const union value *val = case_data (c, v);
1219 if (!var_is_value_missing (v, val, proc->exclude))
1220 gs->sum_diff += weight * (val->f - proc->testval);
1224 for (i = 0; i < proc->n_vars; i++)
1226 struct group_statistics *gs = &group_proc_get (proc->vars[i])->ugs;
1227 gs->mean_diff = gs->sum_diff / gs->n;
1230 casereader_destroy (reader);
1236 paired_calc (const struct dictionary *dict, struct t_test_proc *proc,
1237 struct casereader *reader)
1242 for (i = 0; i < proc->n_pairs; i++)
1244 struct pair *pair = &proc->pairs[i];
1246 pair->sum[0] = pair->sum[1] = 0;
1247 pair->ssq[0] = pair->ssq[1] = 0;
1248 pair->sum_of_prod = 0;
1249 pair->correlation = 0;
1250 pair->sum_of_diffs = 0;
1251 pair->ssq_diffs = 0;
1254 for (; (c = casereader_read (reader)) != NULL; case_unref (c))
1256 double weight = dict_get_case_weight (dict, c, NULL);
1257 for (i = 0; i < proc->n_pairs; i++)
1259 struct pair *pair = &proc->pairs[i];
1260 const struct variable *v0 = pair->v[0];
1261 const struct variable *v1 = pair->v[1];
1263 const union value *val0 = case_data (c, v0);
1264 const union value *val1 = case_data (c, v1);
1266 if (!var_is_value_missing (v0, val0, proc->exclude)
1267 && !var_is_value_missing (v1, val1, proc->exclude))
1270 pair->sum[0] += weight * val0->f;
1271 pair->sum[1] += weight * val1->f;
1272 pair->ssq[0] += weight * pow2 (val0->f);
1273 pair->ssq[1] += weight * pow2 (val1->f);
1274 pair->sum_of_prod += weight * val0->f * val1->f;
1275 pair->sum_of_diffs += weight * (val0->f - val1->f);
1276 pair->ssq_diffs += weight * pow2 (val0->f - val1->f);
1281 for (i = 0; i < proc->n_pairs; i++)
1283 struct pair *pair = &proc->pairs[i];
1284 const double n = pair->n;
1287 for (j=0; j < 2; j++)
1289 pair->mean[j] = pair->sum[j] / n;
1290 pair->s_std_dev[j] = sqrt ((pair->ssq[j] / n
1291 - pow2 (pair->mean[j])));
1292 pair->std_dev[j] = sqrt (n / (n- 1) * (pair->ssq[j] / n
1293 - pow2 (pair->mean[j])));
1296 pair->correlation = (pair->sum_of_prod / pair->n
1297 - pair->mean[0] * pair->mean[1]);
1298 /* correlation now actually contains the covariance */
1299 pair->correlation /= pair->std_dev[0] * pair->std_dev[1];
1300 pair->correlation *= pair->n / (pair->n - 1);
1302 pair->mean_diff = pair->sum_of_diffs / n;
1303 pair->std_dev_diff = sqrt (n / (n - 1) * ((pair->ssq_diffs / n)
1304 - pow2 (pair->mean_diff)));
1307 casereader_destroy (reader);
1312 group_calc (const struct dictionary *dict, struct t_test_proc *proc,
1313 struct casereader *reader)
1318 for (i = 0; i < proc->n_vars; i++)
1320 struct group_proc *ttpr = group_proc_get (proc->vars[i]);
1323 /* There's always 2 groups for a T - TEST */
1325 ttpr->group_hash = hsh_create (2,
1326 (hsh_compare_func *) compare_group_binary,
1327 (hsh_hash_func *) hash_group_binary,
1328 (hsh_free_func *) free_group,
1331 for (j = 0; j < 2; j++)
1333 struct group_statistics *gs = xmalloc (sizeof *gs);
1337 if (proc->criterion == CMP_EQ)
1338 gs->id = proc->g_value[j];
1342 gs->id.f = proc->critical_value - 1.0;
1344 gs->id.f = proc->critical_value + 1.0;
1347 hsh_insert (ttpr->group_hash, gs);
1351 for (; (c = casereader_read (reader)) != NULL; case_unref (c))
1353 const double weight = dict_get_case_weight (dict, c, NULL);
1354 const union value *gv;
1356 if (var_is_value_missing (proc->indep_var,
1357 case_data (c, proc->indep_var), proc->exclude))
1360 gv = case_data (c, proc->indep_var);
1361 for (i = 0; i < proc->n_vars; i++)
1363 const struct variable *var = proc->vars[i];
1364 const union value *val = case_data (c, var);
1365 struct hsh_table *grp_hash = group_proc_get (var)->group_hash;
1366 struct group_statistics *gs = hsh_find (grp_hash, gv);
1368 /* If the independent variable doesn't match either of the values
1369 for this case then move on to the next case. */
1373 if (!var_is_value_missing (var, val, proc->exclude))
1376 gs->sum += weight * val->f;
1377 gs->ssq += weight * pow2 (val->f);
1382 for (i = 0; i < proc->n_vars; i++)
1384 const struct variable *var = proc->vars[i];
1385 struct hsh_table *grp_hash = group_proc_get (var)->group_hash;
1386 struct hsh_iterator g;
1387 struct group_statistics *gs;
1390 for (gs = hsh_first (grp_hash, &g); gs != NULL;
1391 gs = hsh_next (grp_hash, &g))
1393 gs->mean = gs->sum / gs->n;
1394 gs->s_std_dev = sqrt (((gs->ssq / gs->n) - pow2 (gs->mean)));
1395 gs->std_dev = sqrt (gs->n / (gs->n- 1)
1396 * ((gs->ssq / gs->n) - pow2 (gs->mean)));
1397 gs->se_mean = gs->std_dev / sqrt (gs->n);
1400 assert (count == 2);
1403 casereader_destroy (reader);
1410 is_criteria_value (const struct ccase *c, void *aux)
1412 const struct t_test_proc *proc = aux;
1413 const union value *val = case_data (c, proc->indep_var);
1414 int width = var_get_width (proc->indep_var);
1416 if ( value_equal (val, &proc->g_value[0], width))
1419 if ( value_equal (val, &proc->g_value[1], width))
1426 calculate (struct t_test_proc *proc,
1427 struct casereader *input, const struct dataset *ds)
1429 const struct dictionary *dict = dataset_dict (ds);
1430 struct ssbox stat_summary_box;
1431 struct trbox test_results_box;
1432 struct taint *taint;
1435 c = casereader_peek (input, 0);
1438 casereader_destroy (input);
1441 output_split_file_values (ds, c);
1444 if (proc->listwise_missing)
1445 input = casereader_create_filter_missing (input,
1448 proc->exclude, NULL, NULL);
1449 input = casereader_create_filter_weight (input, dict, NULL, NULL);
1450 taint = taint_clone (casereader_get_taint (input));
1452 common_calc (dict, proc, casereader_clone (input));
1456 one_sample_calc (dict, proc, input);
1459 paired_calc (dict, proc, input);
1462 group_calc (dict, proc, casereader_clone (input));
1464 for (i = 0; i < proc->n_vars; ++i)
1466 struct group_proc *grp_data = group_proc_get (proc->vars[i]);
1468 if ( proc->criterion == CMP_EQ )
1470 input = casereader_create_filter_func (input, is_criteria_value, NULL,
1475 grp_data->levene = levene ( input, proc->indep_var, proc->vars[i], dict_get_weight (dict), proc->exclude);
1482 if (!taint_has_tainted_successor (taint))
1484 ssbox_create (&stat_summary_box, proc);
1485 ssbox_populate (&stat_summary_box, proc);
1486 ssbox_finalize (&stat_summary_box);
1488 if (proc->mode == T_PAIRED)
1491 trbox_create (&test_results_box, proc);
1492 trbox_populate (&test_results_box, proc);
1493 trbox_finalize (&test_results_box);
1496 taint_destroy (taint);
1499 /* return 0 if G belongs to group 0,
1500 1 if it belongs to group 1,
1501 2 if it belongs to neither group */
1503 which_group (const struct group_statistics *g,
1504 const struct t_test_proc *proc)
1506 int width = var_get_width (proc->indep_var);
1508 if (0 == value_compare_3way (&g->id, &proc->g_value[0], width))
1511 if (0 == value_compare_3way (&g->id, &proc->g_value[1], width))
1517 /* Return -1 if the id of a is less than b; +1 if greater than and
1520 compare_group_binary (const struct group_statistics *a,
1521 const struct group_statistics *b,
1522 const struct t_test_proc *proc)
1527 if (proc->criterion == CMP_LE)
1529 flag_a = (a->id.f < proc->critical_value);
1530 flag_b = (b->id.f < proc->critical_value);
1534 flag_a = which_group (a, proc);
1535 flag_b = which_group (b, proc);
1538 if (flag_a < flag_b)
1541 return (flag_a > flag_b);
1544 /* This is a degenerate case of a hash, since it can only return three possible
1545 values. It's really a comparison, being used as a hash function */
1548 hash_group_binary (const struct group_statistics *g,
1549 const struct t_test_proc *proc)
1551 return (proc->criterion == CMP_LE
1552 ? g->id.f < proc->critical_value
1553 : which_group (g, proc));