X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fcrosstabs.q;h=9c17ed0297379c06887ada4803d55de8bad91543;hb=f1cd7ca88d074b671844ef073b364e069672ce66;hp=5ea9a1d53af3ebd7b95224d67000381e94c1a5ed;hpb=4944c86a9318bc5b5578ab145a95c116ffd2c9fd;p=pspp-builds.git diff --git a/src/crosstabs.q b/src/crosstabs.q index 5ea9a1d5..9c17ed02 100644 --- a/src/crosstabs.q +++ b/src/crosstabs.q @@ -29,46 +29,32 @@ */ -/* AIX requires this to be the first thing in the file. */ #include -#if __GNUC__ -#define alloca __builtin_alloca -#else -#if HAVE_ALLOCA_H -#include -#else -#ifdef _AIX -#pragma alloca -#else -#ifndef alloca /* predefined by HP cc +Olibcalls */ -char *alloca (); -#endif -#endif -#endif -#endif - -#include +#include "error.h" #include #include #include +#include +#include "algorithm.h" #include "alloc.h" -#include "avl.h" +#include "case.h" +#include "dictionary.h" #include "hash.h" #include "pool.h" -#include "dcdflib/cdflib.h" #include "command.h" #include "lexer.h" #include "error.h" #include "magic.h" #include "misc.h" -#include "stats.h" #include "output.h" +#include "str.h" #include "tab.h" +#include "value-labels.h" #include "var.h" #include "vfm.h" -#undef DEBUGGING -/*#define DEBUGGING 1*/ +/* (headers) */ + #include "debug-print.h" /* (specification) @@ -83,7 +69,7 @@ char *alloca (); tabl:!tables/notables, box:!box/nobox, pivot:!pivot/nopivot; - +cells[cl_]=count,none,row,column,total,expected,residual,sresidual, + +cells[cl_]=count,none,expected,row,column,total,residual,sresidual, asresidual,all; +statistics[st_]=chisq,phi,cc,lambda,uc,none,btau,ctau,risk,gamma,d, kappa,eta,corr,all. @@ -110,7 +96,7 @@ struct table_entry double *data; /* Crosstabulation table for integer mode. */ } u; - union value v[1]; /* Values. */ + union value values[1]; /* Values. */ }; /* A crosstabulation. */ @@ -119,10 +105,26 @@ struct crosstab int nvar; /* Number of variables. */ double missing; /* Missing cases count. */ int ofs; /* Integer mode: Offset into sorted_tab[]. */ - struct variable *v[2]; /* At least two variables; sorted by + struct variable *vars[2]; /* At least two variables; sorted by larger indices first. */ }; +/* Integer mode variable info. */ +struct var_range + { + int min; /* Minimum value. */ + int max; /* Maximum value + 1. */ + int count; /* max - min. */ + }; + +static inline struct var_range * +get_var_range (struct variable *v) +{ + assert (v != NULL); + assert (v->aux != NULL); + return v->aux; +} + /* Indexes into crosstab.v. */ enum { @@ -135,8 +137,9 @@ static struct hsh_table *gen_tab; /* Hash table. */ static int n_sorted_tab; /* Number of entries in sorted_tab. */ static struct table_entry **sorted_tab; /* Sorted table. */ -/* VARIABLES dictionary. */ -static struct dictionary *var_dict; +/* Variables specifies on VARIABLES. */ +static struct variable **variables; +static size_t variables_cnt; /* TABLES. */ static struct crosstab **xtab; @@ -153,7 +156,6 @@ static int mode; /* CELLS. */ static int num_cells; /* Number of cells requested. */ static int cells[8]; /* Cells requested. */ -static int expected; /* Nonzero if expected value is needed. */ /* WRITE. */ static int write; /* One of WR_* that specifies the WRITE style. */ @@ -166,17 +168,14 @@ static struct pool *pl_tc; /* For table cells. */ static struct pool *pl_col; /* For column data. */ static int internal_cmd_crosstabs (void); -static void free_var_dict (void); -static void precalc (void); -static int calc_general (struct ccase *); -static int calc_integer (struct ccase *); -static void postcalc (void); +static void precalc (void *); +static int calc_general (struct ccase *, void *); +static int calc_integer (struct ccase *, void *); +static void postcalc (void *); static void submit (struct tab_table *); -#if DEBUGGING -static void debug_print (void); -static void print_table_entries (struct table_entry **tab); -#endif +static void format_short (char *s, const struct fmt_spec *fp, + const union value *v); /* Parse and execute CROSSTABS, then clean up. */ int @@ -184,7 +183,7 @@ cmd_crosstabs (void) { int result = internal_cmd_crosstabs (); - free_var_dict (); + free (variables); pool_destroy (pl_tc); pool_destroy (pl_col); @@ -195,34 +194,27 @@ cmd_crosstabs (void) static int internal_cmd_crosstabs (void) { - var_dict = NULL; + int i; + + variables = NULL; + variables_cnt = 0; xtab = NULL; nxtab = 0; pl_tc = pool_create (); pl_col = pool_create (); - lex_match_id ("CROSSTABS"); if (!parse_crosstabs (&cmd)) return CMD_FAILURE; -#if DEBUGGING - /* Needs var_dict. */ - debug_print (); -#endif - - mode = var_dict ? INTEGER : GENERAL; - free_var_dict(); + mode = variables ? INTEGER : GENERAL; /* CELLS. */ - expected = 0; if (!cmd.sbc_cells) { cmd.a_cells[CRS_CL_COUNT] = 1; - num_cells = 1; } else { - int i; int count = 0; for (i = 0; i < CRS_CL_count; i++) @@ -242,14 +234,10 @@ internal_cmd_crosstabs (void) cmd.a_cells[CRS_CL_ALL] = 0; } cmd.a_cells[CRS_CL_NONE] = 0; - for (num_cells = i = 0; i < CRS_CL_count; i++) - if (cmd.a_cells[i]) - { - if (i >= CRS_CL_EXPECTED) - expected = 1; - cmd.a_cells[num_cells++] = i; - } } + for (num_cells = i = 0; i < CRS_CL_count; i++) + if (cmd.a_cells[i]) + cells[num_cells++] = i; /* STATISTICS. */ if (cmd.sbc_statistics) @@ -296,45 +284,18 @@ internal_cmd_crosstabs (void) else write = CRS_WR_NONE; - update_weighting (&default_dict); - procedure (precalc, mode == GENERAL ? calc_general : calc_integer, postcalc); + procedure_with_splits (precalc, + mode == GENERAL ? calc_general : calc_integer, + postcalc, NULL); return CMD_SUCCESS; } -/* Frees var_dict once it's no longer needed. */ -static void -free_var_dict (void) -{ - if (!var_dict) - return; - - { - int i; - - if (var_dict->var_by_name) - { - avl_destroy (var_dict->var_by_name, NULL); - var_dict->var_by_name = NULL; - } - - for (i = 0; i < var_dict->nvar; i++) - free (var_dict->var[i]); - free (var_dict->var); - var_dict->var = NULL; - var_dict->nvar = 0; - - free_dictionary (var_dict); - - var_dict = NULL; - } -} - /* Parses the TABLES subcommand. */ static int -crs_custom_tables (struct cmd_crosstabs *cmd unused) +crs_custom_tables (struct cmd_crosstabs *cmd UNUSED) { - struct dictionary *dict; + struct var_set *var_set; int n_by; struct variable ***by = NULL; int *by_nvar = NULL; @@ -343,20 +304,24 @@ crs_custom_tables (struct cmd_crosstabs *cmd unused) /* Ensure that this is a TABLES subcommand. */ if (!lex_match_id ("TABLES") - && (token != T_ID || !is_varname (tokid)) + && (token != T_ID || dict_lookup_var (default_dict, tokid) == NULL) && token != T_ALL) return 2; lex_match ('='); - dict = var_dict ? var_dict : &default_dict; + if (variables != NULL) + var_set = var_set_create_from_array (variables, variables_cnt); + else + var_set = var_set_create_from_dict (default_dict); + assert (var_set != NULL); for (n_by = 0; ;) { by = xrealloc (by, sizeof *by * (n_by + 1)); by_nvar = xrealloc (by_nvar, sizeof *by_nvar * (n_by + 1)); - if (!parse_variables (dict, &by[n_by], &by_nvar[n_by], - PV_NO_DUPLICATE | PV_NO_SCRATCH)) - goto lossage; + if (!parse_var_set_vars (var_set, &by[n_by], &by_nvar[n_by], + PV_NO_DUPLICATE | PV_NO_SCRATCH)) + goto done; nx *= by_nvar[n_by]; n_by++; @@ -365,7 +330,7 @@ crs_custom_tables (struct cmd_crosstabs *cmd unused) if (n_by < 1) { lex_error (_("expecting BY")); - goto lossage; + goto done; } else break; @@ -388,12 +353,8 @@ crs_custom_tables (struct cmd_crosstabs *cmd unused) { int i; - if (var_dict == NULL) - for (i = 0; i < n_by; i++) - x->v[i] = by[i][by_iter[i]]; - else - for (i = 0; i < n_by; i++) - x->v[i] = default_dict.var[by[i][by_iter[i]]->foo]; + for (i = 0; i < n_by; i++) + x->vars[i] = by[i][by_iter[i]]; } { @@ -411,11 +372,10 @@ crs_custom_tables (struct cmd_crosstabs *cmd unused) } free (by_iter); } - success = 1; - /* Despite the name, we come here whether we're successful or - not. */ - lossage: + + done: + /* All return paths lead here. */ { int i; @@ -425,16 +385,15 @@ crs_custom_tables (struct cmd_crosstabs *cmd unused) free (by_nvar); } + var_set_destroy (var_set); + return success; } /* Parses the VARIABLES subcommand. */ static int -crs_custom_variables (struct cmd_crosstabs *cmd unused) +crs_custom_variables (struct cmd_crosstabs *cmd UNUSED) { - struct variable **v = NULL; - int nv = 0; - if (nxtab) { msg (SE, _("VARIABLES must be specified before TABLES.")); @@ -445,12 +404,12 @@ crs_custom_variables (struct cmd_crosstabs *cmd unused) for (;;) { - int orig_nv = nv; + int orig_nv = variables_cnt; int i; long min, max; - if (!parse_variables (&default_dict, &v, &nv, + if (!parse_variables (default_dict, &variables, &variables_cnt, (PV_APPEND | PV_NUMERIC | PV_NO_DUPLICATE | PV_NO_SCRATCH))) return 0; @@ -487,96 +446,26 @@ crs_custom_variables (struct cmd_crosstabs *cmd unused) } lex_get (); - for (i = orig_nv; i < nv; i++) - { - v[i]->p.crs.min = min; - v[i]->p.crs.max = max + 1.; - v[i]->p.crs.count = max - min + 1; + for (i = orig_nv; i < variables_cnt; i++) + { + struct var_range *vr = xmalloc (sizeof *vr); + vr->min = min; + vr->max = max + 1.; + vr->count = max - min + 1; + var_attach_aux (variables[i], vr, var_dtor_free); } if (token == '/') break; } - { - int i; - - var_dict = new_dictionary (0); - var_dict->var = xmalloc (sizeof *var_dict->var * nv); - var_dict->nvar = nv; - for (i = 0; i < nv; i++) - { - struct variable *var = xmalloc (offsetof (struct variable, width)); - strcpy (var->name, v[i]->name); - var->index = i; - var->type = v[i]->type; - var->foo = v[i]->index; - var_dict->var[i] = var; - avl_force_insert (var_dict->var_by_name, var); - } - - free (v); - return 1; - } + return 1; lossage: - free (v); + free (variables); + variables = NULL; return 0; } - -#if DEBUGGING -static void -debug_print (void) -{ - printf ("CROSSTABS\n"); - - if (var_dict) - { - int i; - - printf ("\t/VARIABLES="); - for (i = 0; i < var_dict->nvar; i++) - { - struct variable *v = var_dict->var[i]; - struct variable *iv = default_dict.var[v->foo]; - - printf ("%s ", v->name); - if (i < var_dict->nvar - 1) - { - struct variable *nv = var_dict->var[i + 1]; - struct variable *niv = default_dict.var[nv->foo]; - - if (iv->p.crs.min == niv->p.crs.min - && iv->p.crs.max == niv->p.crs.max) - continue; - } - printf ("(%d,%d) ", iv->p.crs.min, iv->p.crs.max - 1); - } - printf ("\n"); - } - - { - int i; - - printf ("\t/TABLES="); - for (i = 0; i < nxtab; i++) - { - struct crosstab *x = xtab[i]; - int j; - - if (i) - printf("\t\t"); - for (j = 0; j < x->nvar; j++) - { - if (j) - printf (" BY "); - printf ("%s", x->v[j]->name); - } - printf ("\n"); - } - } -} -#endif /* DEBUGGING */ /* Data file processing. */ @@ -585,7 +474,7 @@ static unsigned hash_table_entry (const void *, void *); /* Set up the crosstabulation tables for processing. */ static void -precalc (void) +precalc (void *aux UNUSED) { if (mode == GENERAL) { @@ -608,14 +497,14 @@ precalc (void) x->ofs = n_sorted_tab; - for (j = 2; j < x->nvar; j++) - count *= x->v[j - 2]->p.crs.count; - + for (j = 2; j < x->nvar; j++) + count *= get_var_range (x->vars[j - 2])->count; + sorted_tab = xrealloc (sorted_tab, sizeof *sorted_tab * (n_sorted_tab + count)); v = local_alloc (sizeof *v * x->nvar); - for (j = 2; j < x->nvar; j++) - v[j] = x->v[j]->p.crs.min; + for (j = 2; j < x->nvar; j++) + v[j] = get_var_range (x->vars[j])->min; for (j = 0; j < count; j++) { struct table_entry *te; @@ -626,8 +515,9 @@ precalc (void) te->table = i; { - const int mat_size = (x->v[0]->p.crs.count - * x->v[1]->p.crs.count); + int row_cnt = get_var_range (x->vars[0])->count; + int col_cnt = get_var_range (x->vars[1])->count; + const int mat_size = row_cnt * col_cnt; int m; te->u.data = xmalloc (sizeof *te->u.data * mat_size); @@ -636,12 +526,15 @@ precalc (void) } for (k = 2; k < x->nvar; k++) - te->v[k].f = v[k]; - for (k = 2; k < x->nvar; k++) - if (++v[k] >= x->v[k]->p.crs.max) - v[k] = x->v[k]->p.crs.min; - else - break; + te->values[k].f = v[k]; + for (k = 2; k < x->nvar; k++) + { + struct var_range *vr = get_var_range (x->vars[k]); + if (++v[k] >= vr->max) + v[k] = vr->min; + else + break; + } } local_free (v); } @@ -654,12 +547,12 @@ precalc (void) /* Form crosstabulations for general mode. */ static int -calc_general (struct ccase *c) +calc_general (struct ccase *c, void *aux UNUSED) { + int bad_warn = 1; + /* Case weight. */ - double w = (default_dict.weight_index != -1 - ? c->data[default_dict.var[default_dict.weight_index]->fv].f - : 1.0); + double weight = dict_get_case_weight (default_dict, c, &bad_warn); /* Flattened current table index. */ int t; @@ -680,41 +573,44 @@ calc_general (struct ccase *c) for (j = 0; j < x->nvar; j++) { if ((cmd.miss == CRS_TABLE - && is_missing (&c->data[x->v[j]->fv], x->v[j])) + && is_missing (case_data (c, x->vars[j]->fv), x->vars[j])) || (cmd.miss == CRS_INCLUDE - && is_system_missing (&c->data[x->v[j]->fv], x->v[j]))) + && is_system_missing (case_data (c, x->vars[j]->fv), + x->vars[j]))) { - x->missing += w; + x->missing += weight; goto next_crosstab; } - if (x->v[j]->type == NUMERIC) - te->v[j].f = c->data[x->v[j]->fv].f; + if (x->vars[j]->type == NUMERIC) + te->values[j].f = case_num (c, x->vars[j]->fv); else { - memcpy (te->v[j].s, c->data[x->v[j]->fv].s, x->v[j]->width); + memcpy (te->values[j].s, case_str (c, x->vars[j]->fv), + x->vars[j]->width); /* Necessary in order to simplify comparisons. */ - memset (&te->v[j].s[x->v[j]->width], 0, - sizeof (union value) - x->v[j]->width); + memset (&te->values[j].s[x->vars[j]->width], 0, + sizeof (union value) - x->vars[j]->width); } } } /* Add record to hash table. */ { - struct table_entry **tepp = (struct table_entry **) hsh_probe (gen_tab, te); - if (NULL == *tepp) + struct table_entry **tepp + = (struct table_entry **) hsh_probe (gen_tab, te); + if (*tepp == NULL) { struct table_entry *tep = pool_alloc (pl_tc, entry_size); - te->u.freq = w; + te->u.freq = weight; memcpy (tep, te, entry_size); *tepp = tep; } else - (*tepp)->u.freq += w; + (*tepp)->u.freq += weight; } next_crosstab: @@ -725,12 +621,12 @@ calc_general (struct ccase *c) } static int -calc_integer (struct ccase *c) +calc_integer (struct ccase *c, void *aux UNUSED) { + int bad_warn = 1; + /* Case weight. */ - double w = (default_dict.weight_index != -1 - ? c->data[default_dict.var[default_dict.weight_index]->fv].f - : 1.0); + double weight = dict_get_case_weight (default_dict, c, &bad_warn); /* Flattened current table index. */ int t; @@ -744,30 +640,35 @@ calc_integer (struct ccase *c) ofs = x->ofs; for (i = 0; i < x->nvar; i++) { - struct variable *const v = x->v[i]; - double value = c->data[v->fv].f; + struct variable *const v = x->vars[i]; + struct var_range *vr = get_var_range (v); + double value = case_num (c, v->fv); /* Note that the first test also rules out SYSMIS. */ - if ((value < v->p.crs.min || value >= v->p.crs.max) + if ((value < vr->min || value >= vr->max) || (cmd.miss == CRS_TABLE && is_num_user_missing (value, v))) { - x->missing += w; + x->missing += weight; goto next_crosstab; } if (i > 1) { - ofs += fact * ((int) value - v->p.crs.min); - fact *= v->p.crs.count; + ofs += fact * ((int) value - vr->min); + fact *= vr->count; } } { - const int row = c->data[x->v[ROW_VAR]->fv].f - x->v[ROW_VAR]->p.crs.min; - const int col = c->data[x->v[COL_VAR]->fv].f - x->v[COL_VAR]->p.crs.min; - const int col_dim = x->v[COL_VAR]->p.crs.count; + struct variable *row_var = x->vars[ROW_VAR]; + const int row = case_num (c, row_var->fv) - get_var_range (row_var)->min; + + struct variable *col_var = x->vars[COL_VAR]; + const int col = case_num (c, col_var->fv) - get_var_range (col_var)->min; + + const int col_dim = get_var_range (col_var)->count; - sorted_tab[ofs]->u.data[col + row * col_dim] += w; + sorted_tab[ofs]->u.data[col + row * col_dim] += weight; } next_crosstab: ; @@ -776,58 +677,27 @@ calc_integer (struct ccase *c) return 1; } -#if DEBUGGING -/* Print out all table entries in NULL-terminated TAB for use by a - debugger (a person, not a program). */ -static void -print_table_entries (struct table_entry **tab) -{ - printf ("raw crosstabulation data:\n"); - for (; *tab; tab++) - { - const struct crosstab *x = xtab[(*tab)->table]; - int i; - - printf ("(%g) table:%d ", (*tab)->u.freq, (*tab)->table); - for (i = 0; i < x->nvar; i++) - { - if (i) - printf (", "); - printf ("%s:", x->v[i]->name); - - if (x->v[i]->type == NUMERIC) - printf ("%g", (*tab)->v[i].f); - else - printf ("%.*s", x->v[i]->width, (*tab)->v[i].s); - } - printf ("\n"); - } - fflush (stdout); -} -#endif - -/* Compare the table_entry's at PA and PB and return a strcmp()-type +/* Compare the table_entry's at A and B and return a strcmp()-type result. */ static int -compare_table_entry (const void *pa, const void *pb, void *foo unused) +compare_table_entry (const void *a_, const void *b_, void *foo UNUSED) { - const struct table_entry *a = pa; - const struct table_entry *b = pb; - - { - const int difftable = a->table - b->table; - if (difftable) - return difftable; - } + const struct table_entry *a = a_; + const struct table_entry *b = b_; + + if (a->table > b->table) + return 1; + else if (a->table < b->table) + return -1; { const struct crosstab *x = xtab[a->table]; int i; for (i = x->nvar - 1; i >= 0; i--) - if (x->v[i]->type == NUMERIC) + if (x->vars[i]->type == NUMERIC) { - const double diffnum = a->v[i].f - b->v[i].f; + const double diffnum = a->values[i].f - b->values[i].f; if (diffnum < 0) return -1; else if (diffnum > 0) @@ -835,9 +705,10 @@ compare_table_entry (const void *pa, const void *pb, void *foo unused) } else { - assert (x->v[i]->type == ALPHA); + assert (x->vars[i]->type == ALPHA); { - const int diffstr = strncmp (a->v[i].s, b->v[i].s, x->v[i]->width); + const int diffstr = strncmp (a->values[i].s, b->values[i].s, + x->vars[i]->width); if (diffstr) return diffstr; } @@ -847,48 +718,40 @@ compare_table_entry (const void *pa, const void *pb, void *foo unused) return 0; } -/* Calculate a hash value from table_entry PA. */ +/* Calculate a hash value from table_entry A. */ static unsigned -hash_table_entry (const void *pa, void *foo unused) +hash_table_entry (const void *a_, void *foo UNUSED) { - const struct table_entry *a = pa; - unsigned long hash = a->table; + const struct table_entry *a = a_; + unsigned long hash; int i; - /* Hash formula from _SPSS Statistical Algorithms_. */ + hash = a->table; for (i = 0; i < xtab[a->table]->nvar; i++) - { - hash = (hash << 3) | (hash >> (CHAR_BIT * SIZEOF_LONG - 3)); - hash ^= a->v[i].hash[0]; -#if SIZEOF_DOUBLE / SIZEOF_LONG > 1 - hash ^= a->v[i].hash[1]; -#endif - } + hash ^= hsh_hash_bytes (&a->values[i], sizeof a->values[i]); return hash; } /* Post-data reading calculations. */ -static struct table_entry **find_pivot_extent (struct table_entry **, int *cnt, int pivot); -static void enum_var_values (struct table_entry **beg, int cnt, - union value **values, int *nvalues, - int var_index); +static struct table_entry **find_pivot_extent (struct table_entry **, + int *cnt, int pivot); +static void enum_var_values (struct table_entry **entries, int entry_cnt, + int var_idx, + union value **values, int *value_cnt); static void output_pivot_table (struct table_entry **, struct table_entry **, double **, double **, double **, int *, int *, int *); static void make_summary_table (void); static void -postcalc (void) +postcalc (void *aux UNUSED) { if (mode == GENERAL) { n_sorted_tab = hsh_count (gen_tab); - sorted_tab = (struct table_entry **) hsh_sort (gen_tab, compare_table_entry); -#if DEBUGGING - print_table_entries (sorted_tab); -#endif + sorted_tab = (struct table_entry **) hsh_sort (gen_tab); } make_summary_table (); @@ -972,8 +835,8 @@ make_summary_table (void) else { const struct crosstab *const x = xtab[(*pb)->table]; - const int n_cols = x->v[COL_VAR]->p.crs.count; - const int n_rows = x->v[ROW_VAR]->p.crs.count; + const int n_cols = get_var_range (x->vars[COL_VAR])->count; + const int n_rows = get_var_range (x->vars[ROW_VAR])->count; const int count = n_cols * n_rows; for (valid = 0.; pb < pe; pb++) @@ -1016,7 +879,8 @@ insert_summary (struct tab_table *t, int tab_index, double valid) if (i > 0) cp = stpcpy (cp, " * "); - cp = stpcpy (cp, x->v[i]->label ? x->v[i]->label : x->v[i]->name); + cp = stpcpy (cp, + x->vars[i]->label ? x->vars[i]->label : x->vars[i]->name); } tab_text (t, 0, 0, TAB_LEFT, buf); @@ -1107,10 +971,10 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe, int tc = pe - pb; /* Table count. */ /* Table entry for header comparison. */ - struct table_entry *cmp; + struct table_entry *cmp = NULL; x = xtab[(*pb)->table]; - enum_var_values (pb, pe - pb, &cols, &n_cols, COL_VAR); + enum_var_values (pb, pe - pb, COL_VAR, &cols, &n_cols); nvar = cmd.pivot == CRS_PIVOT ? x->nvar : 2; @@ -1123,7 +987,7 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe, /* First header line. */ tab_joint_text (table, nvar - 1, 0, (nvar - 1) + (n_cols - 1), 0, - TAB_CENTER | TAT_TITLE, x->v[COL_VAR]->name); + TAB_CENTER | TAT_TITLE, x->vars[COL_VAR]->name); tab_hline (table, TAL_1, nvar - 1, nvar + n_cols - 2, 1); @@ -1134,12 +998,13 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe, for (i = 2; i < nvar; i++) tab_joint_text (table, nvar - i - 1, 0, nvar - i - 1, 1, TAB_RIGHT | TAT_TITLE, - x->v[i]->label ? x->v[i]->label : x->v[i]->name); + (x->vars[i]->label + ? x->vars[i]->label : x->vars[i]->name)); tab_text (table, nvar - 2, 1, TAB_RIGHT | TAT_TITLE, - x->v[ROW_VAR]->name); + x->vars[ROW_VAR]->name); for (i = 0; i < n_cols; i++) table_value_missing (table, nvar + i - 1, 1, TAB_RIGHT, &cols[i], - x->v[COL_VAR]); + x->vars[COL_VAR]); tab_text (table, nvar + n_cols - 1, 1, TAB_CENTER, _("Total")); } @@ -1157,11 +1022,12 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe, { if (i) cp = stpcpy (cp, " by "); - cp = stpcpy (cp, x->v[i]->name); + cp = stpcpy (cp, x->vars[i]->name); } else { - cp = spprintf (cp, "%s by %s for", x->v[0]->name, x->v[1]->name); + cp = spprintf (cp, "%s by %s for", + x->vars[0]->name, x->vars[1]->name); for (i = 2; i < nvar; i++) { char buf[64], *bufp; @@ -1169,9 +1035,9 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe, if (i > 2) *cp++ = ','; *cp++ = ' '; - cp = stpcpy (cp, x->v[i]->name); + cp = stpcpy (cp, x->vars[i]->name); *cp++ = '='; - data_out (buf, &x->v[i]->print, &(*pb)->v[i]); + format_short (buf, &x->vars[i]->print, &(*pb)->values[i]); for (bufp = buf; isspace ((unsigned char) *bufp); bufp++) ; cp = stpcpy (cp, bufp); @@ -1316,7 +1182,7 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe, break; /* Find all the row variable values. */ - enum_var_values (tb, te - tb, &rows, &n_rows, ROW_VAR); + enum_var_values (tb, te - tb, ROW_VAR, &rows, &n_rows); /* Allocate memory space for the column and row totals. */ if (n_rows > *maxrows) @@ -1360,7 +1226,7 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe, *cp = 0.; for (p = &tb[0]; p < te; p++) { - for (; memcmp (cur_col, &(*p)->v[COL_VAR], sizeof *cur_col); + for (; memcmp (cur_col, &(*p)->values[COL_VAR], sizeof *cur_col); cur_row = rows) { *++cp = 0.; @@ -1373,7 +1239,7 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe, mp = &mat[cur_col - cols]; } - for (; memcmp (cur_row, &(*p)->v[ROW_VAR], sizeof *cur_row); + for (; memcmp (cur_row, &(*p)->values[ROW_VAR], sizeof *cur_row); cur_row++) { *mp = 0.; @@ -1469,35 +1335,6 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe, W = cum; } -#if DEBUGGING - /* Print the matrix. */ - { - int i, r, c; - - printf ("%s by %s for", x->v[0]->name, x->v[1]->name); - for (i = 2; i < nvar; i++) - printf (" %s=%g", x->v[i]->name, tb[0]->v[i].f); - printf ("\n"); - printf (" "); - for (c = 0; c < n_cols; c++) - printf ("%4g", cols[c].f); - printf ("\n"); - for (r = 0; r < n_rows; r++) - { - printf ("%4g:", rows[r].f); - for (c = 0; c < n_cols; c++) - printf ("%4g", mat[c + r * n_cols]); - printf ("%4g", row_tot[r]); - printf ("\n"); - } - printf (" "); - for (c = 0; c < n_cols; c++) - printf ("%4g", col_tot[c]); - printf ("%4g", W); - printf ("\n\n"); - } -#endif - /* Find the first variable that differs from the last subtable, then display the values of the dimensioning variables for each table that needs it. */ @@ -1508,8 +1345,9 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe, for (; ; first_difference--) { assert (first_difference >= 2); - if (memcmp (&cmp->v[first_difference], - &(*tb)->v[first_difference], sizeof *cmp->v)) + if (memcmp (&cmp->values[first_difference], + &(*tb)->values[first_difference], + sizeof *cmp->values)) break; } cmp = *tb; @@ -1568,7 +1406,7 @@ delete_missing (void) int r; for (r = 0; r < n_rows; r++) - if (is_num_user_missing (rows[r].f, x->v[ROW_VAR])) + if (is_num_user_missing (rows[r].f, x->vars[ROW_VAR])) { int c; @@ -1582,7 +1420,7 @@ delete_missing (void) int c; for (c = 0; c < n_cols; c++) - if (is_num_user_missing (cols[c].f, x->v[COL_VAR])) + if (is_num_user_missing (cols[c].f, x->vars[COL_VAR])) { int r; @@ -1612,7 +1450,7 @@ submit (struct tab_table *t) if (t != table) for (i = 2; i < nvar; i++) tab_text (t, nvar - i - 1, 0, TAB_RIGHT | TAT_TITLE, - x->v[i]->label ? x->v[i]->label : x->v[i]->name); + x->vars[i]->label ? x->vars[i]->label : x->vars[i]->name); tab_box (t, TAL_2, TAL_2, -1, -1, 0, 0, tab_nc (t) - 1, tab_nr (t) - 1); tab_box (t, -1, -1, -1, TAL_1, tab_l (t), tab_t (t) - 1, tab_nc (t) - 1, tab_nr (t) - 1); @@ -1701,7 +1539,7 @@ find_pivot_extent_general (struct table_entry **tp, int *cnt, int pivot) if (pivot) continue; - if (memcmp (&(*tp)->v[2], &fp->v[2], sizeof (union value) * (x->nvar - 2))) + if (memcmp (&(*tp)->values[2], &fp->values[2], sizeof (union value) * (x->nvar - 2))) break; } @@ -1710,8 +1548,8 @@ find_pivot_extent_general (struct table_entry **tp, int *cnt, int pivot) /* Integer mode correspondent to find_pivot_extent_general(). This could be optimized somewhat, but I just don't give a crap about - CROSSTABS performance in integer mode, which is just a wart on - CROSSTABS' ass as far as I'm concerned. + CROSSTABS performance in integer mode, which is just a + CROSSTABS wart as far as I'm concerned. That said, feel free to send optimization patches to me. */ static struct table_entry ** @@ -1735,75 +1573,64 @@ find_pivot_extent_integer (struct table_entry **tp, int *cnt, int pivot) if (pivot) continue; - if (memcmp (&(*tp)->v[2], &fp->v[2], sizeof (union value) * (x->nvar - 2))) + if (memcmp (&(*tp)->values[2], &fp->values[2], + sizeof (union value) * (x->nvar - 2))) break; } return tp; } -/* Compare value * A and B, where WIDTH is the string width or 0 for - numerics, and return a strcmp()-type result. */ +/* Compares `union value's A_ and B_ and returns a strcmp()-like + result. WIDTH_ points to an int which is either 0 for a + numeric value or a string width for a string value. */ static int -compare_value (const void *pa, const void *pb, void *pwidth) +compare_value (const void *a_, const void *b_, void *width_) { - const union value *a = pa; - const union value *b = pb; - const int width = (int) pwidth; + const union value *a = a_; + const union value *b = b_; + const int *pwidth = width_; + const int width = *pwidth; - if (width) - return strncmp (a->s, b->s, width); + if (width == 0) + return (a->f < b->f) ? -1 : (a->f > b->f); else - return a->f < b->f ? -1 : (a->f > b->f ? 1 : 0); + return strncmp (a->s, b->s, width); } -/* Given a list of CNT table_entry's starting at BEG, creates a list - of *NVALUES values *VALUES of variable with index VAR_INDEX. */ +/* Given an array of ENTRY_CNT table_entry structures starting at + ENTRIES, creates a sorted list of the values that the variable + with index VAR_IDX takes on. The values are returned as a + malloc()'darray stored in *VALUES, with the number of values + stored in *VALUE_CNT. + */ static void -enum_var_values (struct table_entry **beg, int cnt, union value **values, int *nvalues, - int var_index) +enum_var_values (struct table_entry **entries, int entry_cnt, int var_idx, + union value **values, int *value_cnt) { + struct variable *v = xtab[(*entries)->table]->vars[var_idx]; + if (mode == GENERAL) { - avl_tree *tree; - - tree = avl_create (pl_col, compare_value, - (void *) (xtab[(*beg)->table]->v[var_index]->width)); - - { - int i; - - for (i = 0; i < cnt; i++) - avl_insert (tree, &beg[i]->v[var_index]); - *values = xmalloc (sizeof **values * avl_count (tree)); - } - - { - avl_traverser trav; - union value *v; - int i; - - i = 0; - hsh_iterator_init (trav); - while (NULL != (v = avl_traverse (tree, &trav))) - (*values)[i++] = *v; - *nvalues = i; - } + int width = v->width; + int i; - /* Destroy tree. */ - pool_destroy (pl_col); - pl_col = pool_create (); + *values = xmalloc (sizeof **values * entry_cnt); + for (i = 0; i < entry_cnt; i++) + (*values)[i] = entries[i]->values[var_idx]; + *value_cnt = sort_unique (*values, entry_cnt, sizeof **values, + compare_value, &width); } else { - struct crosstab_proc *crs = &xtab[(*beg)->table]->v[var_index]->p.crs; + struct var_range *vr = get_var_range (v); int i; assert (mode == INTEGER); - *values = xmalloc (sizeof **values * crs->count); - for (i = 0; i < crs->count; i++) - (*values)[i].f = i + crs->min; - *nvalues = crs->count; + *values = xmalloc (sizeof **values * vr->count); + for (i = 0; i < vr->count; i++) + (*values)[i].f = i + vr->min; + *value_cnt = vr->count; } } @@ -1816,16 +1643,16 @@ table_value_missing (struct tab_table *table, int c, int r, unsigned char opt, { struct len_string s; - char *label = get_val_lab (var, *v, 0); + const char *label = val_labs_find (var->val_labs, *v); if (label) { tab_text (table, c, r, TAB_LEFT, label); return; } - s.length = var->print.w; - s.string = tab_alloc (table, s.length + 1); - data_out (s.string, &var->print, v); + s.string = tab_alloc (table, var->print.w); + format_short (s.string, &var->print, v); + s.length = strlen (s.string); if (cmd.miss == CRS_REPORT && is_num_user_missing (v->f, var)) s.string[s.length++] = 'M'; while (s.length && *s.string == ' ') @@ -1848,26 +1675,35 @@ display_dimensions (struct tab_table *table, int first_difference, struct table_ for (; first_difference >= 2; first_difference--) table_value_missing (table, nvar - first_difference - 1, 0, - TAB_RIGHT, &tb->v[first_difference], - x->v[first_difference]); + TAB_RIGHT, &tb->values[first_difference], + x->vars[first_difference]); } -/* Put value V into cell (C,R) of TABLE, suffixed with letter M. */ +/* Put VALUE into cell (C,R) of TABLE, suffixed with character + SUFFIX if nonzero. If MARK_MISSING is nonzero the entry is + additionally suffixed with a letter `M'. */ static void -float_M_suffix (struct tab_table *table, int c, int r, double v) +format_cell_entry (struct tab_table *table, int c, int r, double value, + char suffix, int mark_missing) { - static const struct fmt_spec f = {FMT_F, 8, 0}; + const struct fmt_spec f = {FMT_F, 10, 1}; + union value v; struct len_string s; - - s.length = 9; - s.string = tab_alloc (table, 9); - s.string[8] = 'M'; - data_out (s.string, &f, (union value *) &v); + + s.length = 10; + s.string = tab_alloc (table, 16); + v.f = value; + data_out (s.string, &f, &v); while (*s.string == ' ') { s.length--; s.string++; } + if (suffix != 0) + s.string[s.length++] = suffix; + if (mark_missing) + s.string[s.length++] = 'M'; + tab_raw (table, c, r, TAB_RIGHT, &s); } @@ -1880,7 +1716,7 @@ display_crosstabulation (void) for (r = 0; r < n_rows; r++) table_value_missing (table, nvar - 2, r * num_cells, - TAB_RIGHT, &rows[r], x->v[ROW_VAR]); + TAB_RIGHT, &rows[r], x->vars[ROW_VAR]); } tab_text (table, nvar - 2, n_rows * num_cells, TAB_LEFT, _("Total")); @@ -1897,13 +1733,16 @@ display_crosstabulation (void) tab_hline (table, TAL_1, -1, n_cols, 0); for (c = 0; c < n_cols; c++) { - double expected_value; - - if (expected) - expected_value = row_tot[r] * col_tot[c] / W; + int mark_missing = 0; + double expected_value = row_tot[r] * col_tot[c] / W; + if (cmd.miss == CRS_REPORT + && (is_num_user_missing (cols[c].f, x->vars[COL_VAR]) + || is_num_user_missing (rows[r].f, x->vars[ROW_VAR]))) + mark_missing = 1; for (i = 0; i < num_cells; i++) { double v; + int suffix = 0; switch (cells[i]) { @@ -1912,12 +1751,15 @@ display_crosstabulation (void) break; case CRS_CL_ROW: v = *mp / row_tot[r] * 100.; + suffix = '%'; break; case CRS_CL_COLUMN: v = *mp / col_tot[c] * 100.; + suffix = '%'; break; case CRS_CL_TOTAL: v = *mp / W * 100.; + suffix = '%'; break; case CRS_CL_EXPECTED: v = expected_value; @@ -1936,14 +1778,10 @@ display_crosstabulation (void) break; default: assert (0); + abort (); } - if (cmd.miss == CRS_REPORT - && (is_num_user_missing (cols[c].f, x->v[COL_VAR]) - || is_num_user_missing (rows[r].f, x->v[ROW_VAR]))) - float_M_suffix (table, c, i, v); - else if (v != 0.) - tab_float (table, c, i, TAB_RIGHT, v, 8, 0); + format_cell_entry (table, c, i, v, suffix, mark_missing); } mp++; @@ -1958,57 +1796,72 @@ display_crosstabulation (void) int r, i; tab_offset (table, -1, tab_row (table) - num_cells * n_rows); - for (r = 0; r < n_rows; r++) - for (i = 0; i < num_cells; i++) - { - double v; - - switch (cells[i]) - { - case CRS_CL_COUNT: - v = row_tot[r]; - break; - case CRS_CL_ROW: - v = 100.; - break; - case CRS_CL_COLUMN: - v = row_tot[r] / W * 100.; - break; - case CRS_CL_TOTAL: - v = row_tot[r] / W * 100.; - break; - case CRS_CL_EXPECTED: - case CRS_CL_RESIDUAL: - case CRS_CL_SRESIDUAL: - case CRS_CL_ASRESIDUAL: - v = 0.; - break; - default: - assert (0); - } - - if (cmd.miss == CRS_REPORT - && is_num_user_missing (rows[r].f, x->v[ROW_VAR])) - float_M_suffix (table, n_cols, 0, v); - else if (v != 0.) - tab_float (table, n_cols, 0, TAB_RIGHT, v, 8, 0); - - tab_next_row (table); - } + for (r = 0; r < n_rows; r++) + { + char suffix = 0; + int mark_missing = 0; + + if (cmd.miss == CRS_REPORT + && is_num_user_missing (rows[r].f, x->vars[ROW_VAR])) + mark_missing = 1; + + for (i = 0; i < num_cells; i++) + { + double v; + + switch (cells[i]) + { + case CRS_CL_COUNT: + v = row_tot[r]; + break; + case CRS_CL_ROW: + v = 100.; + suffix = '%'; + break; + case CRS_CL_COLUMN: + v = row_tot[r] / W * 100.; + suffix = '%'; + break; + case CRS_CL_TOTAL: + v = row_tot[r] / W * 100.; + suffix = '%'; + break; + case CRS_CL_EXPECTED: + case CRS_CL_RESIDUAL: + case CRS_CL_SRESIDUAL: + case CRS_CL_ASRESIDUAL: + v = 0.; + break; + default: + assert (0); + abort (); + } + + format_cell_entry (table, n_cols, 0, v, suffix, mark_missing); + tab_next_row (table); + } + } } /* Column totals, grand total. */ { - int c, j; + int c; + int last_row = 0; if (num_cells > 1) tab_hline (table, TAL_1, -1, n_cols, 0); for (c = 0; c <= n_cols; c++) { double ct = c < n_cols ? col_tot[c] : W; - int i; + int mark_missing = 0; + char suffix = 0; + int i; - for (i = j = 0; i < num_cells; i++) + if (cmd.miss == CRS_REPORT && c < n_cols + && is_num_user_missing (cols[c].f, x->vars[COL_VAR])) + mark_missing = 1; + + for (i = 0; i < num_cells; i++) { double v; @@ -2016,15 +1869,19 @@ display_crosstabulation (void) { case CRS_CL_COUNT: v = ct; + suffix = '%'; break; case CRS_CL_ROW: v = ct / W * 100.; + suffix = '%'; break; case CRS_CL_COLUMN: v = 100.; + suffix = '%'; break; case CRS_CL_TOTAL: v = ct / W * 100.; + suffix = '%'; break; case CRS_CL_EXPECTED: case CRS_CL_RESIDUAL: @@ -2033,19 +1890,15 @@ display_crosstabulation (void) continue; default: assert (0); + abort (); } - if (cmd.miss == CRS_REPORT && c < n_cols - && is_num_user_missing (cols[c].f, x->v[COL_VAR])) - float_M_suffix (table, c, j, v); - else if (v != 0.) - tab_float (table, c, j, TAB_RIGHT, v, 8, 0); - - j++; + format_cell_entry (table, c, i, v, suffix, mark_missing); } + last_row = i; } - tab_offset (table, -1, tab_row (table) + j); + tab_offset (table, -1, tab_row (table) + last_row); } tab_offset (table, 0, -1); @@ -2090,7 +1943,7 @@ display_chisq (void) tab_float (chisq, 1, 0, TAB_RIGHT, chisq_v[i], 8, 3); tab_float (chisq, 2, 0, TAB_RIGHT, df[i], 8, 0); tab_float (chisq, 3, 0, TAB_RIGHT, - chisq_sig (chisq_v[i], df[i]), 8, 3); + gsl_cdf_chisq_Q (chisq_v[i], df[i]), 8, 3); } else { @@ -2202,24 +2055,24 @@ display_risk (void) switch (i) { case 0: - if (x->v[COL_VAR]->type == NUMERIC) + if (x->vars[COL_VAR]->type == NUMERIC) sprintf (buf, _("Odds Ratio for %s (%g / %g)"), - x->v[COL_VAR]->name, c[0].f, c[1].f); + x->vars[COL_VAR]->name, c[0].f, c[1].f); else sprintf (buf, _("Odds Ratio for %s (%.*s / %.*s)"), - x->v[COL_VAR]->name, - x->v[COL_VAR]->width, c[0].s, - x->v[COL_VAR]->width, c[1].s); + x->vars[COL_VAR]->name, + x->vars[COL_VAR]->width, c[0].s, + x->vars[COL_VAR]->width, c[1].s); break; case 1: case 2: - if (x->v[ROW_VAR]->type == NUMERIC) + if (x->vars[ROW_VAR]->type == NUMERIC) sprintf (buf, _("For cohort %s = %g"), - x->v[ROW_VAR]->name, rows[i - 1].f); + x->vars[ROW_VAR]->name, rows[i - 1].f); else sprintf (buf, _("For cohort %s = %.*s"), - x->v[ROW_VAR]->name, - x->v[ROW_VAR]->width, rows[i - 1].s); + x->vars[ROW_VAR]->name, + x->vars[ROW_VAR]->width, rows[i - 1].s); break; } @@ -2334,9 +2187,9 @@ display_directional (void) if (k == 0) string = NULL; else if (k == 1) - string = x->v[0]->name; + string = x->vars[0]->name; else - string = x->v[1]->name; + string = x->vars[1]->name; tab_text (direct, j, 0, TAB_LEFT | TAT_PRINTF, gettext (stats_names[j][k]), string); @@ -2360,7 +2213,7 @@ display_directional (void) /* Returns the value of the gamma (factorial) function for an integer argument X. */ -double +static double gamma_int (double x) { double r = 1; @@ -2448,8 +2301,7 @@ calc_chisq (double chisq[N_CHISQ], int df[N_CHISQ], const double freq = mat[n_cols * r + c]; const double residual = freq - expected; - if (expected) - chisq[0] += residual * residual / expected; + chisq[0] += residual * residual / expected; if (freq) chisq[1] += freq * log (expected / freq); } @@ -2507,7 +2359,7 @@ calc_chisq (double chisq[N_CHISQ], int df[N_CHISQ], } /* Calculate Mantel-Haenszel. */ - if (x->v[ROW_VAR]->type == NUMERIC && x->v[COL_VAR]->type == NUMERIC) + if (x->vars[ROW_VAR]->type == NUMERIC && x->vars[COL_VAR]->type == NUMERIC) { double r, ase_0, ase_1; calc_r ((double *) rows, (double *) cols, &r, &ase_0, &ase_1); @@ -2622,8 +2474,7 @@ calc_symmetric (double v[N_SYMMETRIC], double ase[N_SYMMETRIC], const double freq = mat[n_cols * r + c]; const double residual = freq - expected; - if (expected) - Xp += residual * residual / expected; + Xp += residual * residual / expected; } } @@ -2757,10 +2608,10 @@ calc_symmetric (double v[N_SYMMETRIC], double ase[N_SYMMETRIC], if (cmd.a_statistics[CRS_ST_D]) { - d_yx_cum += fij * sqr (Dr * (Cij - Dij) - - (P - Q) * (W - row_tot[i])); - d_xy_cum += fij * sqr (Dc * (Dij - Cij) - - (Q - P) * (W - col_tot[j])); + d_yx_cum += fij * pow2 (Dr * (Cij - Dij) + - (P - Q) * (W - row_tot[i])); + d_xy_cum += fij * pow2 (Dc * (Dij - Cij) + - (Q - P) * (W - col_tot[j])); } if (++j == n_cols) @@ -2780,8 +2631,8 @@ calc_symmetric (double v[N_SYMMETRIC], double ase[N_SYMMETRIC], } btau_var = ((btau_cum - - (W * sqr (W * (P - Q) / sqrt (Dr * Dc) * (Dr + Dc)))) - / sqr (Dr * Dc)); + - (W * pow2 (W * (P - Q) / sqrt (Dr * Dc) * (Dr + Dc)))) + / pow2 (Dr * Dc)); if (cmd.a_statistics[CRS_ST_BTAU]) { ase[3] = sqrt (btau_var); @@ -2806,17 +2657,17 @@ calc_symmetric (double v[N_SYMMETRIC], double ase[N_SYMMETRIC], somers_d_ase[0] = 2. * btau_var / (Dr + Dc) * sqrt (Dr * Dc); somers_d_t[0] = (somers_d_v[0] / (4 / (Dc + Dr) - * sqrt (ctau_cum - sqr (P - Q) / W))); + * sqrt (ctau_cum - pow2 (P - Q) / W))); somers_d_v[1] = (P - Q) / Dc; - somers_d_ase[1] = 2. / sqr (Dc) * sqrt (d_xy_cum); + somers_d_ase[1] = 2. / pow2 (Dc) * sqrt (d_xy_cum); somers_d_t[1] = (somers_d_v[1] / (2. / Dc - * sqrt (ctau_cum - sqr (P - Q) / W))); + * sqrt (ctau_cum - pow2 (P - Q) / W))); somers_d_v[2] = (P - Q) / Dr; - somers_d_ase[2] = 2. / sqr (Dr) * sqrt (d_yx_cum); + somers_d_ase[2] = 2. / pow2 (Dr) * sqrt (d_yx_cum); somers_d_t[2] = (somers_d_v[2] / (2. / Dr - * sqrt (ctau_cum - sqr (P - Q) / W))); + * sqrt (ctau_cum - pow2 (P - Q) / W))); } free (cum); @@ -2909,15 +2760,15 @@ calc_symmetric (double v[N_SYMMETRIC], double ase[N_SYMMETRIC], / (W * (W * W - sum_rici) * (W * W - sum_rici))); #if 0 t[8] = v[8] / sqrt (W * (((sum_fii * (W - sum_fii)) - / sqr (W * W - sum_rici)) + / pow2 (W * W - sum_rici)) + ((2. * (W - sum_fii) * (2. * sum_fii * sum_rici - W * sum_fiiri_ci)) / cube (W * W - sum_rici)) - + (sqr (W - sum_fii) + + (pow2 (W - sum_fii) * (W * sum_fijri_ci2 - 4. * sum_rici * sum_rici) - / hypercube (W * W - sum_rici)))); + / pow4 (W * W - sum_rici)))); #else t[8] = v[8] / ase[8]; #endif @@ -3077,7 +2928,7 @@ calc_directional (double v[N_DIRECTIONAL], double ase[N_DIRECTIONAL], { const int deltaj = j == cm_index; accum += (mat[j + i * n_cols] - * sqr ((j == fim_index[i]) + * pow2 ((j == fim_index[i]) - deltaj + v[0] * deltaj)); } @@ -3093,7 +2944,7 @@ calc_directional (double v[N_DIRECTIONAL], double ase[N_DIRECTIONAL], if (cm_index != fim_index[i]) accum += (mat[i * n_cols + fim_index[i]] + mat[i * n_cols + cm_index]); - t[2] = v[2] / (sqrt (accum - sqr (sum_fim - cm) / W) / (W - cm)); + t[2] = v[2] / (sqrt (accum - pow2 (sum_fim - cm) / W) / (W - cm)); } /* ASE1 for X given Y. */ @@ -3105,7 +2956,7 @@ calc_directional (double v[N_DIRECTIONAL], double ase[N_DIRECTIONAL], { const int deltaj = i == rm_index; accum += (mat[j + i * n_cols] - * sqr ((i == fmj_index[j]) + * pow2 ((i == fmj_index[j]) - deltaj + v[0] * deltaj)); } @@ -3121,7 +2972,7 @@ calc_directional (double v[N_DIRECTIONAL], double ase[N_DIRECTIONAL], if (rm_index != fmj_index[j]) accum += (mat[j + n_cols * fmj_index[j]] + mat[j + n_cols * rm_index]); - t[1] = v[1] / (sqrt (accum - sqr (sum_fmj - rm) / W) / (W - rm)); + t[1] = v[1] / (sqrt (accum - pow2 (sum_fmj - rm) / W) / (W - rm)); } /* Symmetric ASE0 and ASE1. */ @@ -3134,12 +2985,12 @@ calc_directional (double v[N_DIRECTIONAL], double ase[N_DIRECTIONAL], { int temp0 = (fmj_index[j] == i) + (fim_index[i] == j); int temp1 = (i == rm_index) + (j == cm_index); - accum0 += mat[j + i * n_cols] * sqr (temp0 - temp1); + accum0 += mat[j + i * n_cols] * pow2 (temp0 - temp1); accum1 += (mat[j + i * n_cols] - * sqr (temp0 + (v[0] - 1.) * temp1)); + * pow2 (temp0 + (v[0] - 1.) * temp1)); } ase[0] = sqrt (accum1 - 4. * W * v[0] * v[0]) / (2. * W - rm - cm); - t[0] = v[0] / (sqrt (accum0 - sqr ((sum_fim + sum_fmj - cm - rm) / W)) + t[0] = v[0] / (sqrt (accum0 - pow2 ((sum_fim + sum_fmj - cm - rm) / W)) / (2. * W - rm - cm)); } @@ -3155,7 +3006,7 @@ calc_directional (double v[N_DIRECTIONAL], double ase[N_DIRECTIONAL], for (sum_fij2_ri = sum_fij2_ci = 0., i = 0; i < n_rows; i++) for (j = 0; j < n_cols; j++) { - double temp = sqr (mat[j + i * n_cols]); + double temp = pow2 (mat[j + i * n_cols]); sum_fij2_ri += temp / row_tot[i]; sum_fij2_ci += temp / col_tot[j]; } @@ -3193,7 +3044,7 @@ calc_directional (double v[N_DIRECTIONAL], double ase[N_DIRECTIONAL], if (entry <= 0.) continue; - P += entry * sqr (log (col_tot[j] * row_tot[i] / (W * entry))); + P += entry * pow2 (log (col_tot[j] * row_tot[i] / (W * entry))); UXY -= entry / W * log (entry / W); } @@ -3205,27 +3056,27 @@ calc_directional (double v[N_DIRECTIONAL], double ase[N_DIRECTIONAL], if (entry <= 0.) continue; - ase1_yx += entry * sqr (UY * log (entry / row_tot[i]) + ase1_yx += entry * pow2 (UY * log (entry / row_tot[i]) + (UX - UXY) * log (col_tot[j] / W)); - ase1_xy += entry * sqr (UX * log (entry / col_tot[j]) + ase1_xy += entry * pow2 (UX * log (entry / col_tot[j]) + (UY - UXY) * log (row_tot[i] / W)); - ase1_sym += entry * sqr ((UXY + ase1_sym += entry * pow2 ((UXY * log (row_tot[i] * col_tot[j] / (W * W))) - (UX + UY) * log (entry / W)); } v[5] = 2. * ((UX + UY - UXY) / (UX + UY)); - ase[5] = (2. / (W * sqr (UX + UY))) * sqrt (ase1_sym); + ase[5] = (2. / (W * pow2 (UX + UY))) * sqrt (ase1_sym); t[5] = v[5] / ((2. / (W * (UX + UY))) - * sqrt (P - sqr (UX + UY - UXY) / W)); + * sqrt (P - pow2 (UX + UY - UXY) / W)); v[6] = (UX + UY - UXY) / UX; ase[6] = sqrt (ase1_xy) / (W * UX * UX); - t[6] = v[6] / (sqrt (P - W * sqr (UX + UY - UXY)) / (W * UX)); + t[6] = v[6] / (sqrt (P - W * pow2 (UX + UY - UXY)) / (W * UX)); v[7] = (UX + UY - UXY) / UY; ase[7] = sqrt (ase1_yx) / (W * UY * UY); - t[7] = v[7] / (sqrt (P - W * sqr (UX + UY - UXY)) / (W * UY)); + t[7] = v[7] / (sqrt (P - W * pow2 (UX + UY - UXY)) / (W * UY)); } /* Somers' D. */ @@ -3304,6 +3155,34 @@ calc_directional (double v[N_DIRECTIONAL], double ase[N_DIRECTIONAL], return 1; } +/* A wrapper around data_out() that limits string output to short + string width and null terminates the result. */ +static void +format_short (char *s, const struct fmt_spec *fp, const union value *v) +{ + struct fmt_spec fmt_subst; + + /* Limit to short string width. */ + if (formats[fp->type].cat & FCAT_STRING) + { + fmt_subst = *fp; + + assert (fmt_subst.type == FMT_A || fmt_subst.type == FMT_AHEX); + if (fmt_subst.type == FMT_A) + fmt_subst.w = min (8, fmt_subst.w); + else + fmt_subst.w = min (16, fmt_subst.w); + + fp = &fmt_subst; + } + + /* Format. */ + data_out (s, fp, v); + + /* Null terminate. */ + s[fp->w] = '\0'; +} + /* Local Variables: mode: c