X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Fstats%2Faggregate.c;h=b54ebf6376bd1500c3f0e616703f84e2c07a1026;hb=844259de34f3b5ed9c1b4a024da63f96f4f2194e;hp=22ca39d76373c7bd1634e1d5ad92ef1c0f96ecf8;hpb=92c09e564002d356d20fc1e2e131027ef89f6748;p=pspp diff --git a/src/language/stats/aggregate.c b/src/language/stats/aggregate.c index 22ca39d763..b54ebf6376 100644 --- a/src/language/stats/aggregate.c +++ b/src/language/stats/aggregate.c @@ -1,27 +1,24 @@ -/* PSPP - computes sample statistics. - Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc. +/* PSPP - a program for statistical analysis. + Copyright (C) 1997-9, 2000, 2006, 2008, 2009, 2010 Free Software Foundation, Inc. - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. */ + along with this program. If not, see . */ #include #include #include -#include #include #include #include @@ -31,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -38,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -46,8 +43,11 @@ #include #include #include +#include +#include #include "minmax.h" +#include "xalloc.h" #include "gettext.h" #define _(msgid) gettext (msgid) @@ -77,12 +77,17 @@ struct agr_var char *string; bool saw_missing; struct moments1 *moments; + double cc; + + struct variable *subject; + struct variable *weight; + struct casewriter *writer; }; /* Aggregation functions. */ enum { - NONE, SUM, MEAN, SD, MAX, MIN, PGT, PLT, PIN, POUT, FGT, FLT, FIN, + NONE, SUM, MEAN, MEDIAN, SD, MAX, MIN, PGT, PLT, PIN, POUT, FGT, FLT, FIN, FOUT, N, NU, NMISS, NUMISS, FIRST, LAST, N_AGR_FUNCS, N_NO_VARS, NU_NO_VARS, FUNC = 0x1f, /* Function mask. */ @@ -94,36 +99,37 @@ struct agr_func { const char *name; /* Aggregation function name. */ size_t n_args; /* Number of arguments. */ - enum var_type alpha_type; /* When given ALPHA arguments, output type. */ + enum val_type alpha_type; /* When given ALPHA arguments, output type. */ struct fmt_spec format; /* Format spec if alpha_type != ALPHA. */ }; /* Attributes of aggregation functions. */ -static const struct agr_func agr_func_tab[] = +static const struct agr_func agr_func_tab[] = { {"", 0, -1, {0, 0, 0}}, {"SUM", 0, -1, {FMT_F, 8, 2}}, {"MEAN", 0, -1, {FMT_F, 8, 2}}, + {"MEDIAN", 0, -1, {FMT_F, 8, 2}}, {"SD", 0, -1, {FMT_F, 8, 2}}, - {"MAX", 0, VAR_STRING, {-1, -1, -1}}, - {"MIN", 0, VAR_STRING, {-1, -1, -1}}, - {"PGT", 1, VAR_NUMERIC, {FMT_F, 5, 1}}, - {"PLT", 1, VAR_NUMERIC, {FMT_F, 5, 1}}, - {"PIN", 2, VAR_NUMERIC, {FMT_F, 5, 1}}, - {"POUT", 2, VAR_NUMERIC, {FMT_F, 5, 1}}, - {"FGT", 1, VAR_NUMERIC, {FMT_F, 5, 3}}, - {"FLT", 1, VAR_NUMERIC, {FMT_F, 5, 3}}, - {"FIN", 2, VAR_NUMERIC, {FMT_F, 5, 3}}, - {"FOUT", 2, VAR_NUMERIC, {FMT_F, 5, 3}}, - {"N", 0, VAR_NUMERIC, {FMT_F, 7, 0}}, - {"NU", 0, VAR_NUMERIC, {FMT_F, 7, 0}}, - {"NMISS", 0, VAR_NUMERIC, {FMT_F, 7, 0}}, - {"NUMISS", 0, VAR_NUMERIC, {FMT_F, 7, 0}}, - {"FIRST", 0, VAR_STRING, {-1, -1, -1}}, - {"LAST", 0, VAR_STRING, {-1, -1, -1}}, + {"MAX", 0, VAL_STRING, {-1, -1, -1}}, + {"MIN", 0, VAL_STRING, {-1, -1, -1}}, + {"PGT", 1, VAL_NUMERIC, {FMT_F, 5, 1}}, + {"PLT", 1, VAL_NUMERIC, {FMT_F, 5, 1}}, + {"PIN", 2, VAL_NUMERIC, {FMT_F, 5, 1}}, + {"POUT", 2, VAL_NUMERIC, {FMT_F, 5, 1}}, + {"FGT", 1, VAL_NUMERIC, {FMT_F, 5, 3}}, + {"FLT", 1, VAL_NUMERIC, {FMT_F, 5, 3}}, + {"FIN", 2, VAL_NUMERIC, {FMT_F, 5, 3}}, + {"FOUT", 2, VAL_NUMERIC, {FMT_F, 5, 3}}, + {"N", 0, VAL_NUMERIC, {FMT_F, 7, 0}}, + {"NU", 0, VAL_NUMERIC, {FMT_F, 7, 0}}, + {"NMISS", 0, VAL_NUMERIC, {FMT_F, 7, 0}}, + {"NUMISS", 0, VAL_NUMERIC, {FMT_F, 7, 0}}, + {"FIRST", 0, VAL_STRING, {-1, -1, -1}}, + {"LAST", 0, VAL_STRING, {-1, -1, -1}}, {NULL, 0, -1, {-1, -1, -1}}, - {"N", 0, VAR_NUMERIC, {FMT_F, 7, 0}}, - {"NU", 0, VAR_NUMERIC, {FMT_F, 7, 0}}, + {"N", 0, VAL_NUMERIC, {FMT_F, 7, 0}}, + {"NU", 0, VAL_NUMERIC, {FMT_F, 7, 0}}, }; /* Missing value types. */ @@ -134,13 +140,13 @@ enum missing_treatment }; /* An entire AGGREGATE procedure. */ -struct agr_proc +struct agr_proc { /* Break variables. */ - struct case_ordering *sort; /* Sort criteria. */ + struct subcase sort; /* Sort criteria (break variables). */ const struct variable **break_vars; /* Break variables. */ size_t break_var_cnt; /* Number of break variables. */ - struct ccase break_case; /* Last values of break variables. */ + struct ccase *break_case; /* Last values of break variables. */ enum missing_treatment missing; /* How to treat missing values. */ struct agr_var *agr_vars; /* First aggregate variable. */ @@ -151,6 +157,7 @@ struct agr_proc static void initialize_aggregate_info (struct agr_proc *, const struct ccase *); + static void accumulate_aggregate_info (struct agr_proc *, const struct ccase *); /* Prototypes. */ @@ -180,14 +187,16 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) memset(&agr, 0 , sizeof (agr)); agr.missing = ITEMWISE; - case_nullify (&agr.break_case); + agr.break_case = NULL; agr.dict = dict_create (); agr.src_dict = dict; + subcase_init_empty (&agr.sort); dict_set_label (agr.dict, dict_get_label (dict)); dict_set_documents (agr.dict, dict_get_documents (dict)); /* OUTFILE subcommand must be first. */ + lex_match (lexer, '/'); if (!lex_force_match_id (lexer, "OUTFILE")) goto error; lex_match (lexer, '='); @@ -197,12 +206,12 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) if (out_file == NULL) goto error; } - + /* Read most of the subcommands. */ for (;;) { lex_match (lexer, '/'); - + if (lex_match_id (lexer, "MISSING")) { lex_match (lexer, '='); @@ -222,17 +231,13 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) int i; lex_match (lexer, '='); - agr.sort = parse_case_ordering (lexer, dict, - - &saw_direction); - if (agr.sort == NULL) + if (!parse_sort_criteria (lexer, dict, &agr.sort, &agr.break_vars, + &saw_direction)) goto error; - case_ordering_get_vars (agr.sort, - &agr.break_vars, &agr.break_var_cnt); - + agr.break_var_cnt = subcase_get_n_fields (&agr.sort); + for (i = 0; i < agr.break_var_cnt; i++) - dict_clone_var_assert (agr.dict, agr.break_vars[i], - var_get_name (agr.break_vars[i])); + dict_clone_var_assert (agr.dict, agr.break_vars[i]); /* BREAK must follow the options. */ break; @@ -247,7 +252,7 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) msg (SW, _("When PRESORTED is specified, specifying sorting directions " "with (A) or (D) has no effect. Output data will be sorted " "the same way as the input data.")); - + /* Read in the aggregate functions. */ lex_match (lexer, '/'); if (!parse_aggregate_functions (lexer, dict, &agr)) @@ -259,19 +264,19 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) /* Cancel SPLIT FILE. */ dict_set_split_vars (agr.dict, NULL, 0); - + /* Initialize. */ agr.case_cnt = 0; - if (out_file == NULL) + if (out_file == NULL) { /* The active file will be replaced by the aggregated data, so TEMPORARY is moot. */ proc_cancel_temporary_transformations (ds); proc_discard_output (ds); - output = autopaging_writer_create (dict_get_next_value_idx (agr.dict)); + output = autopaging_writer_create (dict_get_proto (agr.dict)); } - else + else { output = any_writer_open (out_file, agr.dict); if (output == NULL) @@ -279,56 +284,59 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) } input = proc_open (ds); - if (agr.sort != NULL && !presorted) + if (!subcase_is_empty (&agr.sort) && !presorted) { - input = sort_execute (input, agr.sort); - agr.sort = NULL; + input = sort_execute (input, &agr.sort); + subcase_clear (&agr.sort); } for (grouper = casegrouper_create_vars (input, agr.break_vars, agr.break_var_cnt); casegrouper_get_next_group (grouper, &group); - casereader_destroy (group)) + casereader_destroy (group)) { - struct ccase c; - - if (!casereader_peek (group, 0, &c)) - continue; - initialize_aggregate_info (&agr, &c); - case_destroy (&c); - - for (; casereader_read (group, &c); case_destroy (&c)) - accumulate_aggregate_info (&agr, &c); + struct ccase *c = casereader_peek (group, 0); + if (c == NULL) + { + casereader_destroy (group); + continue; + } + initialize_aggregate_info (&agr, c); + case_unref (c); + + for (; (c = casereader_read (group)) != NULL; case_unref (c)) + accumulate_aggregate_info (&agr, c); dump_aggregate_info (&agr, output); } if (!casegrouper_destroy (grouper)) goto error; - if (!proc_commit (ds)) + if (!proc_commit (ds)) { input = NULL; goto error; } input = NULL; - if (out_file == NULL) + if (out_file == NULL) { struct casereader *next_input = casewriter_make_reader (output); if (next_input == NULL) goto error; - + proc_set_active_file (ds, next_input, agr.dict); agr.dict = NULL; } - else + else { ok = casewriter_destroy (output); output = NULL; if (!ok) goto error; } - + agr_destroy (&agr); + fh_unref (out_file); return CMD_SUCCESS; error: @@ -336,12 +344,14 @@ error: proc_commit (ds); casewriter_destroy (output); agr_destroy (&agr); + fh_unref (out_file); return CMD_CASCADING_FAILURE; } /* Parse all the aggregate functions. */ static bool -parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, struct agr_proc *agr) +parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, + struct agr_proc *agr) { struct agr_var *tail; /* Tail of linked list starting at agr->vars. */ @@ -379,7 +389,7 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, s while (!lex_match (lexer, '=')) { size_t n_dest_prev = n_dest; - + if (!parse_DATA_LIST_vars (lexer, &dest, &n_dest, PV_APPEND | PV_SINGLE | PV_NO_SCRATCH)) goto error; @@ -394,7 +404,7 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, s } - + if (lex_token (lexer) == T_STRING) { struct string label; @@ -428,7 +438,7 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, s break; if (NULL == function->name) { - msg (SE, _("Unknown aggregation function %s."), + msg (SE, _("Unknown aggregation function %s."), ds_cstr (&function_name)); goto error; } @@ -470,25 +480,25 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, s for (i = 0; i < function->n_args; i++) { int type; - + lex_match (lexer, ','); if (lex_token (lexer) == T_STRING) { arg[i].c = ds_xstrdup (lex_tokstr (lexer)); - type = VAR_STRING; + type = VAL_STRING; } else if (lex_is_number (lexer)) { arg[i].f = lex_tokval (lexer); - type = VAR_NUMERIC; + type = VAL_NUMERIC; } else { - msg (SE, _("Missing argument %d to %s."), - (int) i + 1, function->name); + msg (SE, _("Missing argument %zu to %s."), + i + 1, function->name); goto error; } - + lex_get (lexer); if (type != var_get_type (src[0])) @@ -506,7 +516,7 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, s lex_error (lexer, _("expecting `)'")); goto error; } - + /* Now check that the number of source variables match the number of target variables. If we check earlier than this, the user can get very misleading error @@ -515,14 +525,14 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, s like `unknown variable t'. */ if (n_src != n_dest) { - msg (SE, _("Number of source variables (%u) does not match " - "number of target variables (%u)."), - (unsigned) n_src, (unsigned) n_dest); + msg (SE, _("Number of source variables (%zu) does not match " + "number of target variables (%zu)."), + n_src, n_dest); goto error; } if ((func_index == PIN || func_index == POUT - || func_index == FIN || func_index == FOUT) + || func_index == FIN || func_index == FOUT) && (var_is_numeric (src[0]) ? arg[0].f > arg[1].f : str_compare_rpad (arg[0].c, arg[1].c) > 0)) @@ -530,19 +540,19 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, s union agr_argument t = arg[0]; arg[0] = arg[1]; arg[1] = t; - + msg (SW, _("The value arguments passed to the %s function " "are out-of-order. They will be treated as if " "they had been specified in the correct order."), function->name); } } - + /* Finally add these to the linked list of aggregation variables. */ for (i = 0; i < n_dest; i++) { - struct agr_var *v = xmalloc (sizeof *v); + struct agr_var *v = xzalloc (sizeof *v); /* Add variable to chain. */ if (agr->agr_vars != NULL) @@ -552,37 +562,37 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, s tail = v; tail->next = NULL; v->moments = NULL; - + /* Create the target variable in the aggregate dictionary. */ { struct variable *destvar; - + v->function = func_index; if (src) { v->src = src[i]; - + if (var_is_alpha (src[i])) { v->function |= FSTRING; v->string = xmalloc (var_get_width (src[i])); } - if (function->alpha_type == VAR_STRING) - destvar = dict_clone_var (agr->dict, v->src, dest[i]); + if (function->alpha_type == VAL_STRING) + destvar = dict_clone_var_as (agr->dict, v->src, dest[i]); else { assert (var_is_numeric (v->src) - || function->alpha_type == VAR_NUMERIC); + || function->alpha_type == VAL_NUMERIC); destvar = dict_create_var (agr->dict, dest[i], 0); - if (destvar != NULL) + if (destvar != NULL) { struct fmt_spec f; if ((func_index == N || func_index == NMISS) && dict_get_weight (dict) != NULL) - f = fmt_for_output (FMT_F, 8, 2); + f = fmt_for_output (FMT_F, 8, 2); else f = function->format; var_set_both_formats (destvar, &f); @@ -593,12 +603,12 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, s v->src = NULL; destvar = dict_create_var (agr->dict, dest[i], 0); if (func_index == N_NO_VARS && dict_get_weight (dict) != NULL) - f = fmt_for_output (FMT_F, 8, 2); + f = fmt_for_output (FMT_F, 8, 2); else f = function->format; var_set_both_formats (destvar, &f); } - + if (!destvar) { msg (SE, _("Variable name %s is not unique within the " @@ -615,7 +625,7 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, s v->dest = destvar; } - + v->exclude = exclude; if (v->src != NULL) @@ -630,7 +640,7 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, s v->arg[j].c = xstrdup (arg[j].c); } } - + if (src != NULL && var_is_alpha (src[0])) for (i = 0; i < function->n_args; i++) { @@ -651,7 +661,7 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, s return false; } continue; - + error: ds_destroy (&function_name); for (i = 0; i < n_dest; i++) @@ -670,7 +680,7 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, s arg[i].c = NULL; } free (src); - + return false; } } @@ -681,9 +691,9 @@ agr_destroy (struct agr_proc *agr) { struct agr_var *iter, *next; - case_ordering_destroy (agr->sort); + subcase_destroy (&agr->sort); free (agr->break_vars); - case_destroy (&agr->break_case); + case_unref (agr->break_case); for (iter = agr->agr_vars; iter; iter = next) { next = iter->next; @@ -700,6 +710,10 @@ agr_destroy (struct agr_proc *agr) } else if (iter->function == SD) moments1_destroy (iter->moments); + + dict_destroy_internal_var (iter->subject); + dict_destroy_internal_var (iter->weight); + free (iter); } if (agr->dict != NULL) @@ -709,7 +723,7 @@ agr_destroy (struct agr_proc *agr) /* Execution. */ /* Accumulates aggregation data from the case INPUT. */ -static void +static void accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) { struct agr_var *iter; @@ -740,7 +754,7 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) iter->saw_missing = true; continue; } - + /* This is horrible. There are too many possibilities. */ switch (iter->function) { @@ -752,6 +766,25 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) iter->dbl[0] += v->f * weight; iter->dbl[1] += weight; break; + case MEDIAN: + { + double wv ; + struct ccase *cout; + + cout = case_create (casewriter_get_proto (iter->writer)); + + case_data_rw (cout, iter->subject)->f + = case_data (input, iter->src)->f; + + wv = dict_get_case_weight (agr->src_dict, input, NULL); + + case_data_rw (cout, iter->weight)->f = wv; + + iter->cc += wv; + + casewriter_write (iter->writer, cout); + } + break; case SD: moments1_add (iter->moments, v->f, weight); break; @@ -760,8 +793,8 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) iter->int1 = 1; break; case MAX | FSTRING: - if (memcmp (iter->string, v->s, src_width) < 0) - memcpy (iter->string, v->s, src_width); + if (memcmp (iter->string, value_str (v, src_width), src_width) < 0) + memcpy (iter->string, value_str (v, src_width), src_width); iter->int1 = 1; break; case MIN: @@ -769,8 +802,8 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) iter->int1 = 1; break; case MIN | FSTRING: - if (memcmp (iter->string, v->s, src_width) > 0) - memcpy (iter->string, v->s, src_width); + if (memcmp (iter->string, value_str (v, src_width), src_width) > 0) + memcpy (iter->string, value_str (v, src_width), src_width); iter->int1 = 1; break; case FGT: @@ -781,7 +814,8 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) break; case FGT | FSTRING: case PGT | FSTRING: - if (memcmp (iter->arg[0].c, v->s, src_width) < 0) + if (memcmp (iter->arg[0].c, + value_str (v, src_width), src_width) < 0) iter->dbl[0] += weight; iter->dbl[1] += weight; break; @@ -793,7 +827,8 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) break; case FLT | FSTRING: case PLT | FSTRING: - if (memcmp (iter->arg[0].c, v->s, src_width) > 0) + if (memcmp (iter->arg[0].c, + value_str (v, src_width), src_width) > 0) iter->dbl[0] += weight; iter->dbl[1] += weight; break; @@ -805,8 +840,10 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) break; case FIN | FSTRING: case PIN | FSTRING: - if (memcmp (iter->arg[0].c, v->s, src_width) <= 0 - && memcmp (iter->arg[1].c, v->s, src_width) >= 0) + if (memcmp (iter->arg[0].c, + value_str (v, src_width), src_width) <= 0 + && memcmp (iter->arg[1].c, + value_str (v, src_width), src_width) >= 0) iter->dbl[0] += weight; iter->dbl[1] += weight; break; @@ -818,8 +855,10 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) break; case FOUT | FSTRING: case POUT | FSTRING: - if (memcmp (iter->arg[0].c, v->s, src_width) > 0 - || memcmp (iter->arg[1].c, v->s, src_width) < 0) + if (memcmp (iter->arg[0].c, + value_str (v, src_width), src_width) > 0 + || memcmp (iter->arg[1].c, + value_str (v, src_width), src_width) < 0) iter->dbl[0] += weight; iter->dbl[1] += weight; break; @@ -841,7 +880,7 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) case FIRST | FSTRING: if (iter->int1 == 0) { - memcpy (iter->string, v->s, src_width); + memcpy (iter->string, value_str (v, src_width), src_width); iter->int1 = 1; } break; @@ -850,7 +889,7 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) iter->int1 = 1; break; case LAST | FSTRING: - memcpy (iter->string, v->s, src_width); + memcpy (iter->string, value_str (v, src_width), src_width); iter->int1 = 1; break; case NMISS: @@ -879,46 +918,42 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) } /* Writes an aggregated record to OUTPUT. */ -static void +static void dump_aggregate_info (struct agr_proc *agr, struct casewriter *output) { - struct ccase c; - - case_create (&c, dict_get_next_value_idx (agr->dict)); + struct ccase *c = case_create (dict_get_proto (agr->dict)); { int value_idx = 0; int i; - for (i = 0; i < agr->break_var_cnt; i++) + for (i = 0; i < agr->break_var_cnt; i++) { const struct variable *v = agr->break_vars[i]; - size_t value_cnt = var_get_value_cnt (v); - memcpy (case_data_rw_idx (&c, value_idx), - case_data (&agr->break_case, v), - sizeof (union value) * value_cnt); - value_idx += value_cnt; + value_copy (case_data_rw_idx (c, value_idx), + case_data (agr->break_case, v), + var_get_width (v)); + value_idx++; } } - + { struct agr_var *i; - + for (i = agr->agr_vars; i; i = i->next) { - union value *v = case_data_rw (&c, i->dest); + union value *v = case_data_rw (c, i->dest); + int width = var_get_width (i->dest); if (agr->missing == COLUMNWISE && i->saw_missing && (i->function & FUNC) != N && (i->function & FUNC) != NU && (i->function & FUNC) != NMISS && (i->function & FUNC) != NUMISS) { - if (var_is_alpha (i->dest)) - memset (v->s, ' ', var_get_width (i->dest)); - else - v->f = SYSMIS; + value_set_missing (v, width); + casewriter_destroy (i->writer); continue; } - + switch (i->function) { case SUM: @@ -927,6 +962,25 @@ dump_aggregate_info (struct agr_proc *agr, struct casewriter *output) case MEAN: v->f = i->dbl[1] != 0.0 ? i->dbl[0] / i->dbl[1] : SYSMIS; break; + case MEDIAN: + { + struct casereader *sorted_reader; + struct percentile *median = percentile_create (0.5, i->cc); + struct order_stats *os = &median->parent; + + sorted_reader = casewriter_make_reader (i->writer); + + order_stats_accumulate (&os, 1, + sorted_reader, + i->weight, + i->subject, + i->exclude); + + v->f = percentile_calculate (median, PC_HAVERAGE); + + statistic_destroy (&median->parent.parent); + } + break; case SD: { double variance; @@ -937,7 +991,7 @@ dump_aggregate_info (struct agr_proc *agr, struct casewriter *output) if (variance != SYSMIS) v->f = sqrt (variance); else - v->f = SYSMIS; + v->f = SYSMIS; } break; case MAX: @@ -947,9 +1001,9 @@ dump_aggregate_info (struct agr_proc *agr, struct casewriter *output) case MAX | FSTRING: case MIN | FSTRING: if (i->int1) - memcpy (v->s, i->string, var_get_width (i->dest)); + memcpy (value_str_rw (v, width), i->string, width); else - memset (v->s, ' ', var_get_width (i->dest)); + value_set_missing (v, width); break; case FGT: case FGT | FSTRING: @@ -986,9 +1040,9 @@ dump_aggregate_info (struct agr_proc *agr, struct casewriter *output) case FIRST | FSTRING: case LAST | FSTRING: if (i->int1) - memcpy (v->s, i->string, var_get_width (i->dest)); + memcpy (value_str_rw (v, width), i->string, width); else - memset (v->s, ' ', var_get_width (i->dest)); + value_set_missing (v, width); break; case N_NO_VARS: v->f = i->dbl[0]; @@ -1010,7 +1064,7 @@ dump_aggregate_info (struct agr_proc *agr, struct casewriter *output) } } - casewriter_write (output, &c); + casewriter_write (output, c); } /* Resets the state for all the aggregate functions. */ @@ -1019,8 +1073,8 @@ initialize_aggregate_info (struct agr_proc *agr, const struct ccase *input) { struct agr_var *iter; - case_destroy (&agr->break_case); - case_clone (&agr->break_case, input); + case_unref (agr->break_case); + agr->break_case = case_ref (input); for (iter = agr->agr_vars; iter; iter = iter->next) { @@ -1041,6 +1095,29 @@ initialize_aggregate_info (struct agr_proc *agr, const struct ccase *input) case MAX | FSTRING: memset (iter->string, 0, var_get_width (iter->src)); break; + case MEDIAN: + { + struct caseproto *proto; + struct subcase ordering; + + proto = caseproto_create (); + proto = caseproto_add_width (proto, 0); + proto = caseproto_add_width (proto, 0); + + if ( ! iter->subject) + iter->subject = dict_create_internal_var (0, 0); + + if ( ! iter->weight) + iter->weight = dict_create_internal_var (1, 0); + + subcase_init_var (&ordering, iter->subject, SC_ASCEND); + iter->writer = sort_create_writer (&ordering, proto); + subcase_destroy (&ordering); + caseproto_unref (proto); + + iter->cc = 0; + } + break; case SD: if (iter->moments == NULL) iter->moments = moments1_create (MOMENT_VARIANCE);