double *data; /* Crosstabulation table for integer mode. */
}
u;
- union value v[1]; /* Values. */
+ union value values[1]; /* Values. */
};
/* A crosstabulation. */
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. */
};
/* 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. */
static void postcalc (void *);
static void submit (struct tab_table *);
+static void format_short (char *s, const struct fmt_spec *fp,
+ const union value *v);
+
#if DEBUGGING
static void debug_print (void);
static void print_table_entries (struct table_entry **tab);
mode = variables ? INTEGER : GENERAL;
/* CELLS. */
- expected = 0;
if (!cmd.sbc_cells)
{
cmd.a_cells[CRS_CL_COUNT] = 1;
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;
- }
+ cmd.a_cells[num_cells++] = i;
}
/* STATISTICS. */
int i;
for (i = 0; i < n_by; i++)
- x->v[i] = by[i][by_iter[i]];
+ x->vars[i] = by[i][by_iter[i]];
}
{
x->ofs = n_sorted_tab;
for (j = 2; j < x->nvar; j++)
- count *= x->v[j - 2]->p.crs.count;
+ count *= x->vars[j - 2]->p.crs.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;
+ v[j] = x->vars[j]->p.crs.min;
for (j = 0; j < count; j++)
{
struct table_entry *te;
te->table = i;
{
- const int mat_size = (x->v[0]->p.crs.count
- * x->v[1]->p.crs.count);
+ const int mat_size = (x->vars[0]->p.crs.count
+ * x->vars[1]->p.crs.count);
int m;
te->u.data = xmalloc (sizeof *te->u.data * mat_size);
}
for (k = 2; k < x->nvar; k++)
- te->v[k].f = v[k];
+ te->values[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;
+ if (++v[k] >= x->vars[k]->p.crs.max)
+ v[k] = x->vars[k]->p.crs.min;
else
break;
}
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 (&c->data[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 (&c->data[x->vars[j]->fv],
+ x->vars[j])))
{
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 = c->data[x->vars[j]->fv].f;
else
{
- memcpy (te->v[j].s, c->data[x->v[j]->fv].s, x->v[j]->width);
+ memcpy (te->values[j].s, c->data[x->vars[j]->fv].s,
+ 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);
}
}
}
ofs = x->ofs;
for (i = 0; i < x->nvar; i++)
{
- struct variable *const v = x->v[i];
+ struct variable *const v = x->vars[i];
double value = c->data[v->fv].f;
/* Note that the first test also rules out SYSMIS. */
}
{
- 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;
+ const int row = c->data[x->vars[ROW_VAR]->fv].f - x->vars[ROW_VAR]->p.crs.min;
+ const int col = c->data[x->vars[COL_VAR]->fv].f - x->vars[COL_VAR]->p.crs.min;
+ const int col_dim = x->vars[COL_VAR]->p.crs.count;
sorted_tab[ofs]->u.data[col + row * col_dim] += weight;
}
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)
}
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;
}
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;
}
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 = x->vars[COL_VAR]->p.crs.count;
+ const int n_rows = x->vars[ROW_VAR]->p.crs.count;
const int count = n_cols * n_rows;
for (valid = 0.; pb < pe; pb++)
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);
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, COL_VAR, &cols, &n_cols);
/* 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);
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"));
}
{
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;
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);
*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.;
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.;
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;
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;
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;
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);
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;
}
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;
}
{
if (mode == GENERAL)
{
- int width = xtab[(*entries)->table]->v[var_idx]->width;
+ int width = xtab[(*entries)->table]->vars[var_idx]->width;
int i;
*values = xmalloc (sizeof **values * entry_cnt);
for (i = 0; i < entry_cnt; i++)
- (*values)[i] = entries[i]->v[var_idx];
+ (*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[(*entries)->table]->v[var_idx]->p.crs;
+ struct crosstab_proc *crs
+ = &xtab[(*entries)->table]->vars[var_idx]->p.crs;
int i;
assert (mode == INTEGER);
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 == ' ')
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. */
s.length = 9;
s.string = tab_alloc (table, 9);
s.string[8] = 'M';
- data_out (s.string, &f, (union value *) &v);
+ format_short (s.string, &f, (union value *) &v);
while (*s.string == ' ')
{
s.length--;
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"));
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;
+ double expected_value = row_tot[r] * col_tot[c] / W;
for (i = 0; i < num_cells; i++)
{
double v;
}
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])))
+ && (is_num_user_missing (cols[c].f, x->vars[COL_VAR])
+ || is_num_user_missing (rows[r].f, x->vars[ROW_VAR])))
float_M_suffix (table, c, i, v);
else if (v != 0.)
tab_float (table, c, i, TAB_RIGHT, v, 8, 0);
}
if (cmd.miss == CRS_REPORT
- && is_num_user_missing (rows[r].f, x->v[ROW_VAR]))
+ && is_num_user_missing (rows[r].f, x->vars[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);
/* Column totals, grand total. */
{
int c, j;
+ int last_row = 0;
if (num_cells > 1)
tab_hline (table, TAL_1, -1, n_cols, 0);
}
if (cmd.miss == CRS_REPORT && c < n_cols
- && is_num_user_missing (cols[c].f, x->v[COL_VAR]))
+ && is_num_user_missing (cols[c].f, x->vars[COL_VAR]))
float_M_suffix (table, c, j, v);
else if (v != 0.)
tab_float (table, c, j, TAB_RIGHT, v, 8, 0);
j++;
}
+ last_row = j;
}
- tab_offset (table, -1, tab_row (table) + j);
+ tab_offset (table, -1, tab_row (table) + last_row);
}
tab_offset (table, 0, -1);
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;
}
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);
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);
}
}
/* 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);
const double freq = mat[n_cols * r + c];
const double residual = freq - expected;
- if (expected)
- Xp += residual * residual / expected;
+ Xp += residual * residual / expected;
}
}
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