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"
26 /* Initializes MV as a set of missing values for a variable of
27 the given WIDTH. Although only numeric variables and short
28 string variables may have missing values, WIDTH may be any
29 valid variable width. */
31 mv_init (struct missing_values *mv, int width)
33 assert (width >= 0 && width <= MAX_STRING);
38 /* Copies SRC to MV. */
40 mv_copy (struct missing_values *mv, const struct missing_values *src)
45 /* Returns true if MV is an empty set of missing values. */
47 mv_is_empty (const struct missing_values *mv)
49 return mv->type == MV_NONE;
52 /* Returns the width of the missing values that MV may
55 mv_get_width (const struct missing_values *mv)
60 /* Attempts to add individual value V to the set of missing
61 values MV. Returns true if successful, false if MV has no
62 more room for missing values. (Long string variables never
63 accept missing values.) */
65 mv_add_value (struct missing_values *mv, const union value *v)
67 if (mv->width > MAX_SHORT_STRING)
75 mv->values[mv->type & 3] = *v;
86 /* Attempts to add S to the set of string missing values MV. S
87 must contain exactly as many characters as MV's width.
88 Returns true if successful, false if MV has no more room for
89 missing values. (Long string variables never accept missing
92 mv_add_str (struct missing_values *mv, const char s[])
94 assert (mv->width > 0);
95 return mv_add_value (mv, (union value *) s);
98 /* Attempts to add D to the set of numeric missing values MV.
99 Returns true if successful, false if MV has no more room for
102 mv_add_num (struct missing_values *mv, double d)
104 assert (mv->width == 0);
105 return mv_add_value (mv, (union value *) &d);
108 /* Attempts to add range [LOW, HIGH] to the set of numeric
109 missing values MV. Returns true if successful, false if MV
110 has no room for a range, or if LOW > HIGH. */
112 mv_add_num_range (struct missing_values *mv, double low, double high)
114 assert (mv->width == 0);
121 mv->values[1].f = low;
122 mv->values[2].f = high;
135 /* Returns true if MV contains an individual value,
136 false if MV is empty (or contains only a range). */
138 mv_has_value (struct missing_values *mv)
155 /* Removes one individual value from MV and stores it in *V.
156 MV must contain an individual value (as determined by
159 mv_pop_value (struct missing_values *mv, union value *v)
161 assert (mv_has_value (mv));
163 *v = mv->values[mv->type & 3];
166 /* Returns true if MV contains a numeric range,
167 false if MV is empty (or contains only individual values). */
169 mv_has_range (struct missing_values *mv)
186 /* Removes the numeric range from MV and stores it in *LOW and
187 *HIGH. MV must contain a individual range (as determined by
190 mv_pop_range (struct missing_values *mv, double *low, double *high)
192 assert (mv_has_range (mv));
193 *low = mv->values[1].f;
194 *high = mv->values[2].f;
198 /* Returns true if values[IDX] is in use when the `type' member
199 is set to TYPE (in struct missing_values),
202 using_element (unsigned type, int idx)
204 assert (idx >= 0 && idx < 3);
224 /* Returns true if S contains only spaces between indexes
225 NEW_WIDTH (inclusive) and OLD_WIDTH (exclusive),
228 can_resize_string (const char *s, int old_width, int new_width)
232 assert (new_width < old_width);
233 for (i = new_width; i < old_width; i++)
239 /* Returns true if MV can be resized to the given WIDTH with
240 mv_resize(), false otherwise. Resizing to the same width is
241 always possible. Resizing to a long string WIDTH is only
242 possible if MV is an empty set of missing values; otherwise,
243 resizing to a larger WIDTH is always possible. Resizing to a
244 shorter width is possible only when each missing value
245 contains only spaces in the characters that will be
248 mv_is_resizable (struct missing_values *mv, int width)
250 assert ((width == 0) == (mv->width == 0));
251 if (width > MAX_SHORT_STRING && mv->type != MV_NONE)
253 else if (width >= mv->width)
259 for (i = 0; i < 3; i++)
260 if (using_element (mv->type, i)
261 && !can_resize_string (mv->values[i].s, mv->width, width))
267 /* Resizes MV to the given WIDTH. WIDTH must fit the constraints
268 explained for mv_is_resizable(). */
270 mv_resize (struct missing_values *mv, int width)
272 assert (mv_is_resizable (mv, width));
273 if (width > mv->width)
277 for (i = 0; i < 3; i++)
278 memset (mv->values[i].s + mv->width, ' ', width - mv->width);
283 /* Returns true if V is system missing or a missing value in MV,
286 mv_is_value_missing (const struct missing_values *mv, const union value *v)
288 return (mv->width == 0
289 ? mv_is_num_missing (mv, v->f)
290 : mv_is_str_missing (mv, v->s));
293 /* Returns true if D is system missing or a missing value in MV,
295 MV must be a set of numeric missing values. */
297 mv_is_num_missing (const struct missing_values *mv, double d)
299 assert (mv->width == 0);
300 return d == SYSMIS || mv_is_num_user_missing (mv, d);
303 /* Returns true if S[] is a missing value in MV, false otherwise.
304 MV must be a set of string missing values.
305 S[] must contain exactly as many characters as MV's width. */
307 mv_is_str_missing (const struct missing_values *mv, const char s[])
309 return mv_is_str_user_missing (mv, s);
312 /* Returns true if V is a missing value in MV, false otherwise. */
314 mv_is_value_user_missing (const struct missing_values *mv,
315 const union value *v)
317 return (mv->width == 0
318 ? mv_is_num_user_missing (mv, v->f)
319 : mv_is_str_user_missing (mv, v->s));
322 /* Returns true if D is a missing value in MV, false otherwise.
323 MV must be a set of numeric missing values. */
325 mv_is_num_user_missing (const struct missing_values *mv, double d)
327 const union value *v = mv->values;
328 assert (mv->width == 0);
336 return v[0].f == d || v[1].f == d;
338 return v[0].f == d || v[1].f == d || v[2].f == d;
340 return v[1].f <= d && d <= v[2].f;
342 return v[0].f == d || (v[1].f <= d && d <= v[2].f);
347 /* Returns true if S[] is a missing value in MV, false otherwise.
348 MV must be a set of string missing values.
349 S[] must contain exactly as many characters as MV's width. */
351 mv_is_str_user_missing (const struct missing_values *mv,
354 const union value *v = mv->values;
355 assert (mv->width > 0);
361 return !memcmp (v[0].s, s, mv->width);
363 return (!memcmp (v[0].s, s, mv->width)
364 || !memcmp (v[1].s, s, mv->width));
366 return (!memcmp (v[0].s, s, mv->width)
367 || !memcmp (v[1].s, s, mv->width)
368 || !memcmp (v[2].s, s, mv->width));
376 /* Returns true if MV is a set of numeric missing values and V is
377 the system missing value. */
379 mv_is_value_system_missing (const struct missing_values *mv,
380 const union value *v)
382 return mv->width == 0 ? v->f == SYSMIS : false;