1 /* PSPP - computes sample statistics.
2 Copyright (C) 2005 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 #include "missing-values.h"
24 #include <libpspp/str.h>
27 /* Initializes MV as a set of missing values for a variable of
28 the given WIDTH. Although only numeric variables and short
29 string variables may have missing values, WIDTH may be any
30 valid variable width. */
32 mv_init (struct missing_values *mv, int width)
34 assert (width >= 0 && width <= MAX_STRING);
40 mv_set_type(struct missing_values *mv, enum mv_type type)
46 /* Copies SRC to MV. */
48 mv_copy (struct missing_values *mv, const struct missing_values *src)
55 /* Returns true if MV is an empty set of missing values. */
57 mv_is_empty (const struct missing_values *mv)
59 return mv->type == MV_NONE;
62 /* Returns the width of the missing values that MV may
65 mv_get_width (const struct missing_values *mv)
70 /* Attempts to add individual value V to the set of missing
71 values MV. Returns true if successful, false if MV has no
72 more room for missing values. (Long string variables never
73 accept missing values.) */
75 mv_add_value (struct missing_values *mv, const union value *v)
77 if (mv->width > MAX_SHORT_STRING)
85 mv->values[mv->type & 3] = *v;
96 /* Attempts to add S to the set of string missing values MV. S
97 must contain exactly as many characters as MV's width.
98 Returns true if successful, false if MV has no more room for
99 missing values. (Long string variables never accept missing
102 mv_add_str (struct missing_values *mv, const char s[])
104 assert (mv->width > 0);
105 return mv_add_value (mv, (union value *) s);
108 /* Attempts to add D to the set of numeric missing values MV.
109 Returns true if successful, false if MV has no more room for
112 mv_add_num (struct missing_values *mv, double d)
114 assert (mv->width == 0);
115 return mv_add_value (mv, (union value *) &d);
118 /* Attempts to add range [LOW, HIGH] to the set of numeric
119 missing values MV. Returns true if successful, false if MV
120 has no room for a range, or if LOW > HIGH. */
122 mv_add_num_range (struct missing_values *mv, double low, double high)
124 assert (mv->width == 0);
131 mv->values[1].f = low;
132 mv->values[2].f = high;
145 /* Returns true if MV contains an individual value,
146 false if MV is empty (or contains only a range). */
148 mv_has_value (const struct missing_values *mv)
165 /* Removes one individual value from MV and stores it in *V.
166 MV must contain an individual value (as determined by
169 mv_pop_value (struct missing_values *mv, union value *v)
171 assert (mv_has_value (mv));
173 *v = mv->values[mv->type & 3];
176 /* Stores a value in *V.
177 MV must contain an individual value (as determined by
179 IDX is the zero based index of the value to get
182 mv_peek_value (const struct missing_values *mv, union value *v, int idx)
187 assert (mv_has_value (mv));
188 *v = mv->values[idx];
192 mv_replace_value (struct missing_values *mv, const union value *v, int idx)
195 assert (idx < mv_n_values(mv));
197 mv->values[idx] = *v;
203 mv_n_values (const struct missing_values *mv)
205 assert(mv_has_value(mv));
210 /* Returns true if MV contains a numeric range,
211 false if MV is empty (or contains only individual values). */
213 mv_has_range (const struct missing_values *mv)
230 /* Removes the numeric range from MV and stores it in *LOW and
231 *HIGH. MV must contain a individual range (as determined by
234 mv_pop_range (struct missing_values *mv, double *low, double *high)
236 assert (mv_has_range (mv));
237 *low = mv->values[1].f;
238 *high = mv->values[2].f;
243 /* Returns the numeric range from MV into *LOW and
244 *HIGH. MV must contain a individual range (as determined by
247 mv_peek_range (const struct missing_values *mv, double *low, double *high)
249 assert (mv_has_range (mv));
250 *low = mv->values[1].f;
251 *high = mv->values[2].f;
255 /* Returns true if values[IDX] is in use when the `type' member
256 is set to TYPE (in struct missing_values),
259 using_element (unsigned type, int idx)
261 assert (idx >= 0 && idx < 3);
281 /* Returns true if S contains only spaces between indexes
282 NEW_WIDTH (inclusive) and OLD_WIDTH (exclusive),
285 can_resize_string (const char *s, int old_width, int new_width)
289 assert (new_width < old_width);
290 for (i = new_width; i < old_width; i++)
296 /* Returns true if MV can be resized to the given WIDTH with
297 mv_resize(), false otherwise. Resizing to the same width is
298 always possible. Resizing to a long string WIDTH is only
299 possible if MV is an empty set of missing values; otherwise,
300 resizing to a larger WIDTH is always possible. Resizing to a
301 shorter width is possible only when each missing value
302 contains only spaces in the characters that will be
305 mv_is_resizable (struct missing_values *mv, int width)
307 assert ((width == 0) == (mv->width == 0));
308 if (width > MAX_SHORT_STRING && mv->type != MV_NONE)
310 else if (width >= mv->width)
316 for (i = 0; i < 3; i++)
317 if (using_element (mv->type, i)
318 && !can_resize_string (mv->values[i].s, mv->width, width))
324 /* Resizes MV to the given WIDTH. WIDTH must fit the constraints
325 explained for mv_is_resizable(). */
327 mv_resize (struct missing_values *mv, int width)
329 assert (mv_is_resizable (mv, width));
330 if (width > mv->width)
334 for (i = 0; i < 3; i++)
335 memset (mv->values[i].s + mv->width, ' ', width - mv->width);
340 /* Returns true if V is system missing or a missing value in MV,
343 mv_is_value_missing (const struct missing_values *mv, const union value *v)
345 return (mv->width == 0
346 ? mv_is_num_missing (mv, v->f)
347 : mv_is_str_missing (mv, v->s));
350 /* Returns true if D is system missing or a missing value in MV,
352 MV must be a set of numeric missing values. */
354 mv_is_num_missing (const struct missing_values *mv, double d)
356 assert (mv->width == 0);
357 return d == SYSMIS || mv_is_num_user_missing (mv, d);
360 /* Returns true if S[] is a missing value in MV, false otherwise.
361 MV must be a set of string missing values.
362 S[] must contain exactly as many characters as MV's width. */
364 mv_is_str_missing (const struct missing_values *mv, const char s[])
366 return mv_is_str_user_missing (mv, s);
369 /* Returns true if V is a missing value in MV, false otherwise. */
371 mv_is_value_user_missing (const struct missing_values *mv,
372 const union value *v)
374 return (mv->width == 0
375 ? mv_is_num_user_missing (mv, v->f)
376 : mv_is_str_user_missing (mv, v->s));
379 /* Returns true if D is a missing value in MV, false otherwise.
380 MV must be a set of numeric missing values. */
382 mv_is_num_user_missing (const struct missing_values *mv, double d)
384 const union value *v = mv->values;
385 assert (mv->width == 0);
393 return v[0].f == d || v[1].f == d;
395 return v[0].f == d || v[1].f == d || v[2].f == d;
397 return v[1].f <= d && d <= v[2].f;
399 return v[0].f == d || (v[1].f <= d && d <= v[2].f);
404 /* Returns true if S[] is a missing value in MV, false otherwise.
405 MV must be a set of string missing values.
406 S[] must contain exactly as many characters as MV's width. */
408 mv_is_str_user_missing (const struct missing_values *mv,
411 const union value *v = mv->values;
412 assert (mv->width > 0);
418 return !memcmp (v[0].s, s, mv->width);
420 return (!memcmp (v[0].s, s, mv->width)
421 || !memcmp (v[1].s, s, mv->width));
423 return (!memcmp (v[0].s, s, mv->width)
424 || !memcmp (v[1].s, s, mv->width)
425 || !memcmp (v[2].s, s, mv->width));
433 /* Returns true if MV is a set of numeric missing values and V is
434 the system missing value. */
436 mv_is_value_system_missing (const struct missing_values *mv,
437 const union value *v)
439 return mv->width == 0 ? v->f == SYSMIS : false;