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. */
112 mv_add_num_range (struct missing_values *mv, double low, double high)
114 assert (mv->width == 0);
119 mv->values[1].f = low;
120 mv->values[2].f = high;
133 /* Returns true if MV contains an individual value,
134 false if MV is empty (or contains only a range). */
136 mv_has_value (struct missing_values *mv)
153 /* Removes one individual value from MV and stores it in *V.
154 MV must contain an individual value (as determined by
157 mv_pop_value (struct missing_values *mv, union value *v)
159 assert (mv_has_value (mv));
161 *v = mv->values[mv->type & 3];
164 /* Returns true if MV contains a numeric range,
165 false if MV is empty (or contains only individual values). */
167 mv_has_range (struct missing_values *mv)
184 /* Removes the numeric range from MV and stores it in *LOW and
185 *HIGH. MV must contain a individual range (as determined by
188 mv_pop_range (struct missing_values *mv, double *low, double *high)
190 assert (mv_has_range (mv));
191 *low = mv->values[1].f;
192 *high = mv->values[2].f;
196 /* Returns true if values[IDX] is in use when the `type' member
197 is set to TYPE (in struct missing_values),
200 using_element (unsigned type, int idx)
202 assert (idx >= 0 && idx < 3);
222 /* Returns true if S contains only spaces between indexes
223 NEW_WIDTH (inclusive) and OLD_WIDTH (exclusive),
226 can_resize_string (const char *s, int old_width, int new_width)
230 assert (new_width < old_width);
231 for (i = new_width; i < old_width; i++)
237 /* Returns true if MV can be resized to the given WIDTH with
238 mv_resize(), false otherwise. Resizing to the same width is
239 always possible. Resizing to a long string WIDTH is only
240 possible if MV is an empty set of missing values; otherwise,
241 resizing to a larger WIDTH is always possible. Resizing to a
242 shorter width is possible only when each missing value
243 contains only spaces in the characters that will be
246 mv_is_resizable (struct missing_values *mv, int width)
248 assert ((width == 0) == (mv->width == 0));
249 if (width > MAX_SHORT_STRING && mv->type != MV_NONE)
251 else if (width >= mv->width)
257 for (i = 0; i < 3; i++)
258 if (using_element (mv->type, i)
259 && !can_resize_string (mv->values[i].s, mv->width, width))
265 /* Resizes MV to the given WIDTH. WIDTH must fit the constraints
266 explained for mv_is_resizable(). */
268 mv_resize (struct missing_values *mv, int width)
270 assert (mv_is_resizable (mv, width));
271 if (width > mv->width)
275 for (i = 0; i < 3; i++)
276 memset (mv->values[i].s + mv->width, ' ', width - mv->width);
281 /* Returns true if V is system missing or a missing value in MV,
284 mv_is_value_missing (const struct missing_values *mv, const union value *v)
286 return (mv->width == 0
287 ? mv_is_num_missing (mv, v->f)
288 : mv_is_str_missing (mv, v->s));
291 /* Returns true if D is system missing or a missing value in MV,
293 MV must be a set of numeric missing values. */
295 mv_is_num_missing (const struct missing_values *mv, double d)
297 assert (mv->width == 0);
298 return d == SYSMIS || mv_is_num_user_missing (mv, d);
301 /* Returns true if S[] is a missing value in MV, false otherwise.
302 MV must be a set of string missing values.
303 S[] must contain exactly as many characters as MV's width. */
305 mv_is_str_missing (const struct missing_values *mv, const char s[])
307 return mv_is_str_user_missing (mv, s);
310 /* Returns true if V is a missing value in MV, false otherwise. */
312 mv_is_value_user_missing (const struct missing_values *mv,
313 const union value *v)
315 return (mv->width == 0
316 ? mv_is_num_user_missing (mv, v->f)
317 : mv_is_str_user_missing (mv, v->s));
320 /* Returns true if D is a missing value in MV, false otherwise.
321 MV must be a set of numeric missing values. */
323 mv_is_num_user_missing (const struct missing_values *mv, double d)
325 const union value *v = mv->values;
326 assert (mv->width == 0);
334 return v[0].f == d || v[1].f == d;
336 return v[0].f == d || v[1].f == d || v[2].f == d;
338 return v[1].f <= d && d <= v[2].f;
340 return v[0].f == d || (v[1].f <= d && d <= v[2].f);
345 /* Returns true if S[] is a missing value in MV, false otherwise.
346 MV must be a set of string missing values.
347 S[] must contain exactly as many characters as MV's width. */
349 mv_is_str_user_missing (const struct missing_values *mv,
352 const union value *v = mv->values;
353 assert (mv->width > 0);
359 return !memcmp (v[0].s, s, mv->width);
361 return (!memcmp (v[0].s, s, mv->width)
362 || !memcmp (v[1].s, s, mv->width));
364 return (!memcmp (v[0].s, s, mv->width)
365 || !memcmp (v[1].s, s, mv->width)
366 || !memcmp (v[2].s, s, mv->width));
374 /* Returns true if MV is a set of numeric missing values and V is
375 the system missing value. */
377 mv_is_value_system_missing (const struct missing_values *mv,
378 const union value *v)
380 return mv->width == 0 ? v->f == SYSMIS : false;