1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2006, 2008, 2009, 2010 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/>. */
21 #include <data/any-writer.h>
22 #include <data/case.h>
23 #include <data/casegrouper.h>
24 #include <data/casereader.h>
25 #include <data/casewriter.h>
26 #include <data/dictionary.h>
27 #include <data/file-handle-def.h>
28 #include <data/format.h>
29 #include <data/procedure.h>
30 #include <data/settings.h>
31 #include <data/subcase.h>
32 #include <data/sys-file-writer.h>
33 #include <data/variable.h>
34 #include <language/command.h>
35 #include <language/data-io/file-handle.h>
36 #include <language/lexer/lexer.h>
37 #include <language/lexer/variable-parser.h>
38 #include <language/stats/sort-criteria.h>
39 #include <libpspp/assertion.h>
40 #include <libpspp/message.h>
41 #include <libpspp/misc.h>
42 #include <libpspp/pool.h>
43 #include <libpspp/str.h>
44 #include <math/moments.h>
45 #include <math/sort.h>
46 #include <math/statistic.h>
47 #include <math/percentiles.h>
49 #include "aggregate.h"
55 #define _(msgid) gettext (msgid)
56 #define N_(msgid) msgid
58 /* Argument for AGGREGATE function. */
61 double f; /* Numeric. */
62 char *c; /* Short or long string. */
65 /* Specifies how to make an aggregate variable. */
68 struct agr_var *next; /* Next in list. */
70 /* Collected during parsing. */
71 const struct variable *src; /* Source variable. */
72 struct variable *dest; /* Target variable. */
73 int function; /* Function. */
74 enum mv_class exclude; /* Classes of missing values to exclude. */
75 union agr_argument arg[2]; /* Arguments. */
77 /* Accumulated during AGGREGATE execution. */
82 struct moments1 *moments;
85 struct variable *subject;
86 struct variable *weight;
87 struct casewriter *writer;
90 /* Aggregation functions. */
93 SUM, MEAN, MEDIAN, SD, MAX, MIN, PGT, PLT, PIN, POUT, FGT, FLT, FIN,
94 FOUT, N, NU, NMISS, NUMISS, FIRST, LAST,
96 FUNC = 0x1f, /* Function mask. */
97 FSTRING = 1<<5, /* String function bit. */
101 /* Attributes of aggregation functions. */
102 const struct agr_func agr_func_tab[] =
104 {"SUM", N_("Sum of values"), AGR_SV_YES, 0, -1, {FMT_F, 8, 2}},
105 {"MEAN", N_("Mean average"), AGR_SV_YES, 0, -1, {FMT_F, 8, 2}},
106 {"MEDIAN", N_("Median average"), AGR_SV_YES, 0, -1, {FMT_F, 8, 2}},
107 {"SD", N_("Standard deviation"), AGR_SV_YES, 0, -1, {FMT_F, 8, 2}},
108 {"MAX", N_("Maximum value"), AGR_SV_YES, 0, VAL_STRING, {-1, -1, -1}},
109 {"MIN", N_("Minimum value"), AGR_SV_YES, 0, VAL_STRING, {-1, -1, -1}},
110 {"PGT", N_("Percentage greater than"), AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 1}},
111 {"PLT", N_("Percentage less than"), AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 1}},
112 {"PIN", N_("Percentage included in range"), AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 1}},
113 {"POUT", N_("Percentage excluded from range"), AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 1}},
114 {"FGT", N_("Fraction greater than"), AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 3}},
115 {"FLT", N_("Fraction less than"), AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 3}},
116 {"FIN", N_("Fraction included in range"), AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 3}},
117 {"FOUT", N_("Fraction excluded from range"), AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 3}},
118 {"N", N_("Number of cases"), AGR_SV_NO, 0, VAL_NUMERIC, {FMT_F, 7, 0}},
119 {"NU", N_("Number of cases (unweighted)"), AGR_SV_OPT, 0, VAL_NUMERIC, {FMT_F, 7, 0}},
120 {"NMISS", N_("Number of missing values"), AGR_SV_YES, 0, VAL_NUMERIC, {FMT_F, 7, 0}},
121 {"NUMISS", N_("Number of missing values (unweighted)"), AGR_SV_YES, 0, VAL_NUMERIC, {FMT_F, 7, 0}},
122 {"FIRST", N_("First non-missing value"), AGR_SV_YES, 0, VAL_STRING, {-1, -1, -1}},
123 {"LAST", N_("Last non-missing value"), AGR_SV_YES, 0, VAL_STRING, {-1, -1, -1}},
124 {NULL, NULL, AGR_SV_NO, 0, -1, {-1, -1, -1}},
127 /* Missing value types. */
128 enum missing_treatment
130 ITEMWISE, /* Missing values item by item. */
131 COLUMNWISE /* Missing values column by column. */
134 /* An entire AGGREGATE procedure. */
137 /* Break variables. */
138 struct subcase sort; /* Sort criteria (break variables). */
139 const struct variable **break_vars; /* Break variables. */
140 size_t break_var_cnt; /* Number of break variables. */
142 enum missing_treatment missing; /* How to treat missing values. */
143 struct agr_var *agr_vars; /* First aggregate variable. */
144 struct dictionary *dict; /* Aggregate dictionary. */
145 const struct dictionary *src_dict; /* Dict of the source */
146 int case_cnt; /* Counts aggregated cases. */
148 bool add_variables; /* True iff the aggregated variables should
149 be appended to the existing dictionary */
152 static void initialize_aggregate_info (struct agr_proc *);
154 static void accumulate_aggregate_info (struct agr_proc *,
155 const struct ccase *);
157 static bool parse_aggregate_functions (struct lexer *, const struct dictionary *,
159 static void agr_destroy (struct agr_proc *);
160 static void dump_aggregate_info (const struct agr_proc *agr,
161 struct casewriter *output,
162 const struct ccase *break_case);
166 /* Parses and executes the AGGREGATE procedure. */
168 cmd_aggregate (struct lexer *lexer, struct dataset *ds)
170 struct dictionary *dict = dataset_dict (ds);
172 struct file_handle *out_file = NULL;
173 struct casereader *input = NULL, *group;
174 struct casegrouper *grouper;
175 struct casewriter *output = NULL;
177 bool copy_documents = false;
178 bool presorted = false;
182 memset(&agr, 0 , sizeof (agr));
183 agr.missing = ITEMWISE;
185 subcase_init_empty (&agr.sort);
187 /* OUTFILE subcommand must be first. */
188 lex_match (lexer, '/');
189 if (!lex_force_match_id (lexer, "OUTFILE"))
191 lex_match (lexer, '=');
192 if (!lex_match (lexer, '*'))
194 out_file = fh_parse (lexer, FH_REF_FILE | FH_REF_SCRATCH);
195 if (out_file == NULL)
199 if (out_file == NULL && lex_match_id (lexer, "MODE"))
201 lex_match (lexer, '=');
202 if (lex_match_id (lexer, "ADDVARIABLES"))
204 agr.add_variables = true;
206 /* presorted is assumed in ADDVARIABLES mode */
209 else if (lex_match_id (lexer, "REPLACE"))
211 agr.add_variables = false;
217 if ( agr.add_variables )
218 agr.dict = dict_clone (dict);
220 agr.dict = dict_create ();
222 dict_set_label (agr.dict, dict_get_label (dict));
223 dict_set_documents (agr.dict, dict_get_documents (dict));
225 /* Read most of the subcommands. */
228 lex_match (lexer, '/');
230 if (lex_match_id (lexer, "MISSING"))
232 lex_match (lexer, '=');
233 if (!lex_match_id (lexer, "COLUMNWISE"))
235 lex_error (lexer, _("while expecting COLUMNWISE"));
238 agr.missing = COLUMNWISE;
240 else if (lex_match_id (lexer, "DOCUMENT"))
241 copy_documents = true;
242 else if (lex_match_id (lexer, "PRESORTED"))
244 else if (lex_match_id (lexer, "BREAK"))
248 lex_match (lexer, '=');
249 if (!parse_sort_criteria (lexer, dict, &agr.sort, &agr.break_vars,
252 agr.break_var_cnt = subcase_get_n_fields (&agr.sort);
254 if (! agr.add_variables)
255 for (i = 0; i < agr.break_var_cnt; i++)
256 dict_clone_var_assert (agr.dict, agr.break_vars[i]);
258 /* BREAK must follow the options. */
263 lex_error (lexer, _("expecting BREAK"));
267 if (presorted && saw_direction)
268 msg (SW, _("When PRESORTED is specified, specifying sorting directions "
269 "with (A) or (D) has no effect. Output data will be sorted "
270 "the same way as the input data."));
272 /* Read in the aggregate functions. */
273 lex_match (lexer, '/');
274 if (!parse_aggregate_functions (lexer, dict, &agr))
277 /* Delete documents. */
279 dict_clear_documents (agr.dict);
281 /* Cancel SPLIT FILE. */
282 dict_set_split_vars (agr.dict, NULL, 0);
287 if (out_file == NULL)
289 /* The active file will be replaced by the aggregated data,
290 so TEMPORARY is moot. */
291 proc_cancel_temporary_transformations (ds);
292 proc_discard_output (ds);
293 output = autopaging_writer_create (dict_get_proto (agr.dict));
297 output = any_writer_open (out_file, agr.dict);
302 input = proc_open (ds);
303 if (!subcase_is_empty (&agr.sort) && !presorted)
305 input = sort_execute (input, &agr.sort);
306 subcase_clear (&agr.sort);
309 for (grouper = casegrouper_create_vars (input, agr.break_vars,
311 casegrouper_get_next_group (grouper, &group);
312 casereader_destroy (group))
314 struct casereader *placeholder = NULL;
315 struct ccase *c = casereader_peek (group, 0);
319 casereader_destroy (group);
323 initialize_aggregate_info (&agr);
325 if ( agr.add_variables )
326 placeholder = casereader_clone (group);
330 for (; (cg = casereader_read (group)) != NULL; case_unref (cg))
331 accumulate_aggregate_info (&agr, cg);
335 if (agr.add_variables)
338 for (; (cg = casereader_read (placeholder)) != NULL; case_unref (cg))
339 dump_aggregate_info (&agr, output, cg);
341 casereader_destroy (placeholder);
345 dump_aggregate_info (&agr, output, c);
349 if (!casegrouper_destroy (grouper))
352 if (!proc_commit (ds))
359 if (out_file == NULL)
361 struct casereader *next_input = casewriter_make_reader (output);
362 if (next_input == NULL)
365 proc_set_active_file (ds, next_input, agr.dict);
370 ok = casewriter_destroy (output);
383 casewriter_destroy (output);
386 return CMD_CASCADING_FAILURE;
389 /* Parse all the aggregate functions. */
391 parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict,
392 struct agr_proc *agr)
394 struct agr_var *tail; /* Tail of linked list starting at agr->vars. */
396 /* Parse everything. */
403 struct string function_name;
405 enum mv_class exclude;
406 const struct agr_func *function;
409 union agr_argument arg[2];
411 const struct variable **src;
424 ds_init_empty (&function_name);
426 /* Parse the list of target variables. */
427 while (!lex_match (lexer, '='))
429 size_t n_dest_prev = n_dest;
431 if (!parse_DATA_LIST_vars (lexer, &dest, &n_dest,
432 (PV_APPEND | PV_SINGLE | PV_NO_SCRATCH
436 /* Assign empty labels. */
440 dest_label = xnrealloc (dest_label, n_dest, sizeof *dest_label);
441 for (j = n_dest_prev; j < n_dest; j++)
442 dest_label[j] = NULL;
447 if (lex_token (lexer) == T_STRING)
450 ds_init_string (&label, lex_tokstr (lexer));
452 ds_truncate (&label, 255);
453 dest_label[n_dest - 1] = ds_xstrdup (&label);
459 /* Get the name of the aggregation function. */
460 if (lex_token (lexer) != T_ID)
462 lex_error (lexer, _("expecting aggregation function"));
468 ds_assign_string (&function_name, lex_tokstr (lexer));
470 ds_chomp (&function_name, '.');
472 if (lex_tokid(lexer)[strlen (lex_tokid (lexer)) - 1] == '.')
475 for (function = agr_func_tab; function->name; function++)
476 if (!strcasecmp (function->name, ds_cstr (&function_name)))
478 if (NULL == function->name)
480 msg (SE, _("Unknown aggregation function %s."),
481 ds_cstr (&function_name));
484 ds_destroy (&function_name);
485 func_index = function - agr_func_tab;
488 /* Check for leading lparen. */
489 if (!lex_match (lexer, '('))
491 if (function->src_vars == AGR_SV_YES)
493 lex_error (lexer, _("expecting `('"));
499 /* Parse list of source variables. */
501 int pv_opts = PV_NO_SCRATCH;
503 if (func_index == SUM || func_index == MEAN || func_index == SD)
504 pv_opts |= PV_NUMERIC;
505 else if (function->n_args)
506 pv_opts |= PV_SAME_TYPE;
508 if (!parse_variables_const (lexer, dict, &src, &n_src, pv_opts))
512 /* Parse function arguments, for those functions that
513 require arguments. */
514 if (function->n_args != 0)
515 for (i = 0; i < function->n_args; i++)
519 lex_match (lexer, ',');
520 if (lex_token (lexer) == T_STRING)
522 arg[i].c = ds_xstrdup (lex_tokstr (lexer));
525 else if (lex_is_number (lexer))
527 arg[i].f = lex_tokval (lexer);
532 msg (SE, _("Missing argument %zu to %s."),
533 i + 1, function->name);
539 if (type != var_get_type (src[0]))
541 msg (SE, _("Arguments to %s must be of same type as "
542 "source variables."),
548 /* Trailing rparen. */
549 if (!lex_match (lexer, ')'))
551 lex_error (lexer, _("expecting `)'"));
555 /* Now check that the number of source variables match
556 the number of target variables. If we check earlier
557 than this, the user can get very misleading error
558 message, i.e. `AGGREGATE x=SUM(y t).' will get this
559 error message when a proper message would be more
560 like `unknown variable t'. */
563 msg (SE, _("Number of source variables (%zu) does not match "
564 "number of target variables (%zu)."),
569 if ((func_index == PIN || func_index == POUT
570 || func_index == FIN || func_index == FOUT)
571 && (var_is_numeric (src[0])
572 ? arg[0].f > arg[1].f
573 : str_compare_rpad (arg[0].c, arg[1].c) > 0))
575 union agr_argument t = arg[0];
579 msg (SW, _("The value arguments passed to the %s function "
580 "are out-of-order. They will be treated as if "
581 "they had been specified in the correct order."),
586 /* Finally add these to the linked list of aggregation
588 for (i = 0; i < n_dest; i++)
590 struct agr_var *v = xzalloc (sizeof *v);
592 /* Add variable to chain. */
593 if (agr->agr_vars != NULL)
601 /* Create the target variable in the aggregate
604 struct variable *destvar;
606 v->function = func_index;
612 if (var_is_alpha (src[i]))
614 v->function |= FSTRING;
615 v->string = xmalloc (var_get_width (src[i]));
618 if (function->alpha_type == VAL_STRING)
619 destvar = dict_clone_var_as (agr->dict, v->src, dest[i]);
622 assert (var_is_numeric (v->src)
623 || function->alpha_type == VAL_NUMERIC);
624 destvar = dict_create_var (agr->dict, dest[i], 0);
628 if ((func_index == N || func_index == NMISS)
629 && dict_get_weight (dict) != NULL)
630 f = fmt_for_output (FMT_F, 8, 2);
632 f = function->format;
633 var_set_both_formats (destvar, &f);
639 destvar = dict_create_var (agr->dict, dest[i], 0);
642 if ((func_index == N || func_index == NMISS)
643 && dict_get_weight (dict) != NULL)
644 f = fmt_for_output (FMT_F, 8, 2);
646 f = function->format;
647 var_set_both_formats (destvar, &f);
653 msg (SE, _("Variable name %s is not unique within the "
654 "aggregate file dictionary, which contains "
655 "the aggregate variables and the break "
663 var_set_label (destvar, dest_label[i]);
668 v->exclude = exclude;
674 if (var_is_numeric (v->src))
675 for (j = 0; j < function->n_args; j++)
676 v->arg[j].f = arg[j].f;
678 for (j = 0; j < function->n_args; j++)
679 v->arg[j].c = xstrdup (arg[j].c);
683 if (src != NULL && var_is_alpha (src[0]))
684 for (i = 0; i < function->n_args; i++)
694 if (!lex_match (lexer, '/'))
696 if (lex_token (lexer) == '.')
699 lex_error (lexer, "expecting end of command");
705 ds_destroy (&function_name);
706 for (i = 0; i < n_dest; i++)
709 free (dest_label[i]);
715 if (src && n_src && var_is_alpha (src[0]))
716 for (i = 0; i < function->n_args; i++)
729 agr_destroy (struct agr_proc *agr)
731 struct agr_var *iter, *next;
733 subcase_destroy (&agr->sort);
734 free (agr->break_vars);
735 for (iter = agr->agr_vars; iter; iter = next)
739 if (iter->function & FSTRING)
744 n_args = agr_func_tab[iter->function & FUNC].n_args;
745 for (i = 0; i < n_args; i++)
746 free (iter->arg[i].c);
749 else if (iter->function == SD)
750 moments1_destroy (iter->moments);
752 dict_destroy_internal_var (iter->subject);
753 dict_destroy_internal_var (iter->weight);
757 if (agr->dict != NULL)
758 dict_destroy (agr->dict);
763 /* Accumulates aggregation data from the case INPUT. */
765 accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input)
767 struct agr_var *iter;
769 bool bad_warn = true;
771 weight = dict_get_case_weight (agr->src_dict, input, &bad_warn);
773 for (iter = agr->agr_vars; iter; iter = iter->next)
776 const union value *v = case_data (input, iter->src);
777 int src_width = var_get_width (iter->src);
779 if (var_is_value_missing (iter->src, v, iter->exclude))
781 switch (iter->function)
784 case NMISS | FSTRING:
785 iter->dbl[0] += weight;
788 case NUMISS | FSTRING:
792 iter->saw_missing = true;
796 /* This is horrible. There are too many possibilities. */
797 switch (iter->function)
800 iter->dbl[0] += v->f * weight;
804 iter->dbl[0] += v->f * weight;
805 iter->dbl[1] += weight;
812 cout = case_create (casewriter_get_proto (iter->writer));
814 case_data_rw (cout, iter->subject)->f
815 = case_data (input, iter->src)->f;
817 wv = dict_get_case_weight (agr->src_dict, input, NULL);
819 case_data_rw (cout, iter->weight)->f = wv;
823 casewriter_write (iter->writer, cout);
827 moments1_add (iter->moments, v->f, weight);
830 iter->dbl[0] = MAX (iter->dbl[0], v->f);
834 if (memcmp (iter->string, value_str (v, src_width), src_width) < 0)
835 memcpy (iter->string, value_str (v, src_width), src_width);
839 iter->dbl[0] = MIN (iter->dbl[0], v->f);
843 if (memcmp (iter->string, value_str (v, src_width), src_width) > 0)
844 memcpy (iter->string, value_str (v, src_width), src_width);
849 if (v->f > iter->arg[0].f)
850 iter->dbl[0] += weight;
851 iter->dbl[1] += weight;
855 if (memcmp (iter->arg[0].c,
856 value_str (v, src_width), src_width) < 0)
857 iter->dbl[0] += weight;
858 iter->dbl[1] += weight;
862 if (v->f < iter->arg[0].f)
863 iter->dbl[0] += weight;
864 iter->dbl[1] += weight;
868 if (memcmp (iter->arg[0].c,
869 value_str (v, src_width), src_width) > 0)
870 iter->dbl[0] += weight;
871 iter->dbl[1] += weight;
875 if (iter->arg[0].f <= v->f && v->f <= iter->arg[1].f)
876 iter->dbl[0] += weight;
877 iter->dbl[1] += weight;
881 if (memcmp (iter->arg[0].c,
882 value_str (v, src_width), src_width) <= 0
883 && memcmp (iter->arg[1].c,
884 value_str (v, src_width), src_width) >= 0)
885 iter->dbl[0] += weight;
886 iter->dbl[1] += weight;
890 if (iter->arg[0].f > v->f || v->f > iter->arg[1].f)
891 iter->dbl[0] += weight;
892 iter->dbl[1] += weight;
896 if (memcmp (iter->arg[0].c,
897 value_str (v, src_width), src_width) > 0
898 || memcmp (iter->arg[1].c,
899 value_str (v, src_width), src_width) < 0)
900 iter->dbl[0] += weight;
901 iter->dbl[1] += weight;
905 iter->dbl[0] += weight;
918 case FIRST | FSTRING:
921 memcpy (iter->string, value_str (v, src_width), src_width);
930 memcpy (iter->string, value_str (v, src_width), src_width);
934 case NMISS | FSTRING:
936 case NUMISS | FSTRING:
937 /* Our value is not missing or it would have been
938 caught earlier. Nothing to do. */
944 switch (iter->function)
947 iter->dbl[0] += weight;
958 /* Writes an aggregated record to OUTPUT. */
960 dump_aggregate_info (const struct agr_proc *agr, struct casewriter *output, const struct ccase *break_case)
962 struct ccase *c = case_create (dict_get_proto (agr->dict));
964 if ( agr->add_variables)
966 case_copy (c, 0, break_case, 0, dict_get_var_cnt (agr->src_dict));
973 for (i = 0; i < agr->break_var_cnt; i++)
975 const struct variable *v = agr->break_vars[i];
976 value_copy (case_data_rw_idx (c, value_idx),
977 case_data (break_case, v),
986 for (i = agr->agr_vars; i; i = i->next)
988 union value *v = case_data_rw (c, i->dest);
989 int width = var_get_width (i->dest);
991 if (agr->missing == COLUMNWISE && i->saw_missing
992 && (i->function & FUNC) != N && (i->function & FUNC) != NU
993 && (i->function & FUNC) != NMISS && (i->function & FUNC) != NUMISS)
995 value_set_missing (v, width);
996 casewriter_destroy (i->writer);
1000 switch (i->function)
1003 v->f = i->int1 ? i->dbl[0] : SYSMIS;
1006 v->f = i->dbl[1] != 0.0 ? i->dbl[0] / i->dbl[1] : SYSMIS;
1012 struct percentile *median = percentile_create (0.5, i->cc);
1013 struct order_stats *os = &median->parent;
1014 struct casereader *sorted_reader = casewriter_make_reader (i->writer);
1017 order_stats_accumulate (&os, 1,
1022 i->dbl[0] = percentile_calculate (median, PC_HAVERAGE);
1023 statistic_destroy (&median->parent.parent);
1032 /* FIXME: we should use two passes. */
1033 moments1_calculate (i->moments, NULL, NULL, &variance,
1035 if (variance != SYSMIS)
1036 v->f = sqrt (variance);
1043 v->f = i->int1 ? i->dbl[0] : SYSMIS;
1048 memcpy (value_str_rw (v, width), i->string, width);
1050 value_set_missing (v, width);
1059 case FOUT | FSTRING:
1060 v->f = i->dbl[1] ? i->dbl[0] / i->dbl[1] : SYSMIS;
1069 case POUT | FSTRING:
1070 v->f = i->dbl[1] ? i->dbl[0] / i->dbl[1] * 100.0 : SYSMIS;
1082 v->f = i->int1 ? i->dbl[0] : SYSMIS;
1084 case FIRST | FSTRING:
1085 case LAST | FSTRING:
1087 memcpy (value_str_rw (v, width), i->string, width);
1089 value_set_missing (v, width);
1092 case NMISS | FSTRING:
1096 case NUMISS | FSTRING:
1105 casewriter_write (output, c);
1108 /* Resets the state for all the aggregate functions. */
1110 initialize_aggregate_info (struct agr_proc *agr)
1112 struct agr_var *iter;
1114 for (iter = agr->agr_vars; iter; iter = iter->next)
1116 iter->saw_missing = false;
1117 iter->dbl[0] = iter->dbl[1] = iter->dbl[2] = 0.0;
1118 iter->int1 = iter->int2 = 0;
1119 switch (iter->function)
1122 iter->dbl[0] = DBL_MAX;
1125 memset (iter->string, 255, var_get_width (iter->src));
1128 iter->dbl[0] = -DBL_MAX;
1131 memset (iter->string, 0, var_get_width (iter->src));
1135 struct caseproto *proto;
1136 struct subcase ordering;
1138 proto = caseproto_create ();
1139 proto = caseproto_add_width (proto, 0);
1140 proto = caseproto_add_width (proto, 0);
1142 if ( ! iter->subject)
1143 iter->subject = dict_create_internal_var (0, 0);
1145 if ( ! iter->weight)
1146 iter->weight = dict_create_internal_var (1, 0);
1148 subcase_init_var (&ordering, iter->subject, SC_ASCEND);
1149 iter->writer = sort_create_writer (&ordering, proto);
1150 subcase_destroy (&ordering);
1151 caseproto_unref (proto);
1157 if (iter->moments == NULL)
1158 iter->moments = moments1_create (MOMENT_VARIANCE);
1160 moments1_clear (iter->moments);