1 /* PSPP - computes sample statistics.
2 Copyright (C) 2005 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 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, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 #include "missing-values.h"
23 #include <libpspp/assertion.h>
25 #include <libpspp/str.h>
27 /* Types of user-missing values.
28 Invisible--use access functions defined below instead. */
31 MVT_NONE = 0, /* No user-missing values. */
32 MVT_1 = 1, /* One user-missing value. */
33 MVT_2 = 2, /* Two user-missing values. */
34 MVT_3 = 3, /* Three user-missing values. */
35 MVT_RANGE = 4, /* A range of user-missing values. */
36 MVT_RANGE_1 = 5 /* A range plus an individual value. */
39 /* Initializes MV as a set of missing values for a variable of
40 the given WIDTH. Although only numeric variables and short
41 string variables may have missing values, WIDTH may be any
42 valid variable width. */
44 mv_init (struct missing_values *mv, int width)
46 assert (width >= 0 && width <= MAX_STRING);
51 /* Removes any missing values from MV. */
53 mv_clear (struct missing_values *mv)
58 /* Copies SRC to MV. */
60 mv_copy (struct missing_values *mv, const struct missing_values *src)
67 /* Returns true if MV is an empty set of missing values. */
69 mv_is_empty (const struct missing_values *mv)
71 return mv->type == MVT_NONE;
74 /* Returns the width of the missing values that MV may
77 mv_get_width (const struct missing_values *mv)
82 /* Attempts to add individual value V to the set of missing
83 values MV. Returns true if successful, false if MV has no
84 more room for missing values. (Long string variables never
85 accept missing values.) */
87 mv_add_value (struct missing_values *mv, const union value *v)
89 if (mv->width > MAX_SHORT_STRING)
97 mv->values[mv->type & 3] = *v;
108 /* Attempts to add S to the set of string missing values MV. S
109 must contain exactly as many characters as MV's width.
110 Returns true if successful, false if MV has no more room for
111 missing values. (Long string variables never accept missing
114 mv_add_str (struct missing_values *mv, const char s[])
116 assert (mv->width > 0);
117 return mv_add_value (mv, (union value *) s);
120 /* Attempts to add D to the set of numeric missing values MV.
121 Returns true if successful, false if MV has no more room for
124 mv_add_num (struct missing_values *mv, double d)
126 assert (mv->width == 0);
127 return mv_add_value (mv, (union value *) &d);
130 /* Attempts to add range [LOW, HIGH] to the set of numeric
131 missing values MV. Returns true if successful, false if MV
132 has no room for a range, or if LOW > HIGH. */
134 mv_add_num_range (struct missing_values *mv, double low, double high)
136 assert (mv->width == 0);
143 mv->values[1].f = low;
144 mv->values[2].f = high;
157 /* Returns true if MV contains an individual value,
158 false if MV is empty (or contains only a range). */
160 mv_has_value (const struct missing_values *mv)
177 /* Removes one individual value from MV and stores it in *V.
178 MV must contain an individual value (as determined by
181 mv_pop_value (struct missing_values *mv, union value *v)
183 assert (mv_has_value (mv));
185 *v = mv->values[mv->type & 3];
188 /* Stores a value in *V.
189 MV must contain an individual value (as determined by
191 IDX is the zero based index of the value to get
194 mv_peek_value (const struct missing_values *mv, union value *v, int idx)
199 assert (mv_has_value (mv));
200 *v = mv->values[idx];
204 mv_replace_value (struct missing_values *mv, const union value *v, int idx)
207 assert (idx < mv_n_values(mv));
209 mv->values[idx] = *v;
215 mv_n_values (const struct missing_values *mv)
217 assert(mv_has_value(mv));
222 /* Returns true if MV contains a numeric range,
223 false if MV is empty (or contains only individual values). */
225 mv_has_range (const struct missing_values *mv)
242 /* Removes the numeric range from MV and stores it in *LOW and
243 *HIGH. MV must contain a individual range (as determined by
246 mv_pop_range (struct missing_values *mv, double *low, double *high)
248 assert (mv_has_range (mv));
249 *low = mv->values[1].f;
250 *high = mv->values[2].f;
255 /* Returns the numeric range from MV into *LOW and
256 *HIGH. MV must contain a individual range (as determined by
259 mv_peek_range (const struct missing_values *mv, double *low, double *high)
261 assert (mv_has_range (mv));
262 *low = mv->values[1].f;
263 *high = mv->values[2].f;
267 /* Returns true if values[IDX] is in use when the `type' member
268 is set to TYPE (in struct missing_values),
271 using_element (unsigned type, int idx)
273 assert (idx >= 0 && idx < 3);
293 /* Returns true if S contains only spaces between indexes
294 NEW_WIDTH (inclusive) and OLD_WIDTH (exclusive),
297 can_resize_string (const char *s, int old_width, int new_width)
301 assert (new_width < old_width);
302 for (i = new_width; i < old_width; i++)
308 /* Returns true if MV can be resized to the given WIDTH with
309 mv_resize(), false otherwise. Resizing to the same width is
310 always possible. Resizing to a long string WIDTH is only
311 possible if MV is an empty set of missing values; otherwise,
312 resizing to a larger WIDTH is always possible. Resizing to a
313 shorter width is possible only when each missing value
314 contains only spaces in the characters that will be
317 mv_is_resizable (const struct missing_values *mv, int width)
319 if ( var_type_from_width (width) != var_type_from_width (mv->width) )
322 if (width > MAX_SHORT_STRING && mv->type != MVT_NONE)
325 if (width >= mv->width)
331 for (i = 0; i < 3; i++)
332 if (using_element (mv->type, i)
333 && !can_resize_string (mv->values[i].s, mv->width, width))
339 /* Resizes MV to the given WIDTH. WIDTH must fit the constraints
340 explained for mv_is_resizable(). */
342 mv_resize (struct missing_values *mv, int width)
344 assert (mv_is_resizable (mv, width));
345 if (width > mv->width && mv->type != MVT_NONE)
349 for (i = 0; i < 3; i++)
350 memset (mv->values[i].s + mv->width, ' ', width - mv->width);
355 /* Returns true if D is a missing value in MV, false otherwise.
356 MV must be a set of numeric missing values. */
358 is_num_user_missing (const struct missing_values *mv, double d)
360 const union value *v = mv->values;
361 assert (mv->width == 0);
369 return v[0].f == d || v[1].f == d;
371 return v[0].f == d || v[1].f == d || v[2].f == d;
373 return v[1].f <= d && d <= v[2].f;
375 return v[0].f == d || (v[1].f <= d && d <= v[2].f);
380 /* Returns true if S[] is a missing value in MV, false otherwise.
381 MV must be a set of string missing values.
382 S[] must contain exactly as many characters as MV's width. */
384 is_str_user_missing (const struct missing_values *mv,
387 const union value *v = mv->values;
388 assert (mv->width > 0);
394 return !memcmp (v[0].s, s, mv->width);
396 return (!memcmp (v[0].s, s, mv->width)
397 || !memcmp (v[1].s, s, mv->width));
399 return (!memcmp (v[0].s, s, mv->width)
400 || !memcmp (v[1].s, s, mv->width)
401 || !memcmp (v[2].s, s, mv->width));
409 /* Returns true if V is a missing value in the given CLASS in MV,
412 mv_is_value_missing (const struct missing_values *mv, const union value *v,
415 return (mv->width == 0
416 ? mv_is_num_missing (mv, v->f, class)
417 : mv_is_str_missing (mv, v->s, class));
420 /* Returns true if D is a missing value in the given CLASS in MV,
422 MV must be a set of numeric missing values. */
424 mv_is_num_missing (const struct missing_values *mv, double d,
427 assert (mv->width == 0);
428 return ((class & MV_SYSTEM && d == SYSMIS)
429 || (class & MV_USER && is_num_user_missing (mv, d)));
432 /* Returns true if S[] is a missing value in the given CLASS in
434 MV must be a set of string missing values.
435 S[] must contain exactly as many characters as MV's width. */
437 mv_is_str_missing (const struct missing_values *mv, const char s[],
440 assert (mv->width > 0);
441 return class & MV_USER && is_str_user_missing (mv, s);