1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2008, 2010, 2011, 2015, 2016 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/>. */
19 #include "language/expressions/helpers.h"
21 #include <gsl/gsl_roots.h>
22 #include <gsl/gsl_sf.h>
24 #include "language/expressions/private.h"
25 #include "libpspp/assertion.h"
26 #include "libpspp/pool.h"
28 #include "gl/minmax.h"
30 const struct substring empty_string = {NULL, 0};
33 expr_ymd_to_ofs (int y, int m, int d,
34 const struct expression *e, const struct expr_node *node,
35 int ya, int ma, int da)
37 int *error = calendar_gregorian_adjust (&y, &m, &d,
38 settings_get_fmt_settings ());
40 return calendar_raw_gregorian_to_offset (y, m, d);
43 msg_at (SE, expr_location (e, node),
44 _("Invalid arguments to %s function."),
45 operations[node->type].name);
47 if (error == &y && ya > 0)
48 msg_at (SN, expr_location (e, y < 1582 ? node->args[ya - 1] : node),
49 _("Date %04d-%d-%d is before the earliest supported date "
50 "1582-10-15."), y, m, d);
51 else if (error == &m && ma > 0)
52 msg_at (SN, expr_location (e, node->args[ma - 1]),
53 _("Month %d is not in the acceptable range of 0 to 13."), m);
54 else if (error == &d && da > 0)
55 msg_at (SN, expr_location (e, node->args[da - 1]),
56 _("Day %d is not in the acceptable range of 0 to 31."), d);
62 expr_ymd_to_date (int y, int m, int d,
63 const struct expression *e, const struct expr_node *n,
64 int ya, int ma, int da)
66 double ofs = expr_ymd_to_ofs (y, m, d, e, n, ya, ma, da);
67 return ofs != SYSMIS ? ofs * DAY_S : SYSMIS;
83 /* Stores in *UNIT the unit whose name is NAME.
86 recognize_unit (struct substring name, const struct expression *e,
87 const struct expr_node *n, enum date_unit *unit)
92 const struct substring name;
94 static const struct unit_name unit_names[] =
96 { DATE_YEARS, SS_LITERAL_INITIALIZER ("years") },
97 { DATE_QUARTERS, SS_LITERAL_INITIALIZER ("quarters") },
98 { DATE_MONTHS, SS_LITERAL_INITIALIZER ("months") },
99 { DATE_WEEKS, SS_LITERAL_INITIALIZER ("weeks") },
100 { DATE_DAYS, SS_LITERAL_INITIALIZER ("days") },
101 { DATE_HOURS, SS_LITERAL_INITIALIZER ("hours") },
102 { DATE_MINUTES, SS_LITERAL_INITIALIZER ("minutes") },
103 { DATE_SECONDS, SS_LITERAL_INITIALIZER ("seconds") },
105 const int n_unit_names = sizeof unit_names / sizeof *unit_names;
107 const struct unit_name *un;
109 for (un = unit_names; un < &unit_names[n_unit_names]; un++)
110 if (ss_equals_case (un->name, name))
116 msg_at (SE, expr_location (e, n),
117 _("Unrecognized date unit `%.*s'. "
118 "Valid date units are `%s', `%s', `%s', "
119 "`%s', `%s', `%s', `%s', and `%s'."),
120 (int) ss_length (name), ss_data (name),
121 "years", "quarters", "months",
122 "weeks", "days", "hours", "minutes", "seconds");
127 /* Returns the number of whole years from DATE1 to DATE2,
128 where a year is defined as the same or later month, day, and
131 year_diff (double date1, double date2)
137 assert (date2 >= date1);
138 calendar_offset_to_gregorian (date1 / DAY_S, &y1, &m1, &d1, &yd1);
139 calendar_offset_to_gregorian (date2 / DAY_S, &y2, &m2, &d2, &yd2);
144 int yd1 = 32 * m1 + d1;
145 int yd2 = 32 * m2 + d2;
147 || (yd2 == yd1 && fmod (date2, DAY_S) < fmod (date1, DAY_S)))
153 /* Returns the number of whole months from DATE1 to DATE2,
154 where a month is defined as the same or later day and time of
157 month_diff (double date1, double date2)
163 assert (date2 >= date1);
164 calendar_offset_to_gregorian (date1 / DAY_S, &y1, &m1, &d1, &yd1);
165 calendar_offset_to_gregorian (date2 / DAY_S, &y2, &m2, &d2, &yd2);
167 diff = ((y2 * 12) + m2) - ((y1 * 12) + m1);
170 || (d2 == d1 && fmod (date2, DAY_S) < fmod (date1, DAY_S))))
175 /* Returns the number of whole quarter from DATE1 to DATE2,
176 where a quarter is defined as three months. */
178 quarter_diff (double date1, double date2)
180 return month_diff (date1, date2) / 3;
183 /* Returns the number of seconds in the given UNIT. */
185 date_unit_duration (enum date_unit unit)
209 /* Returns the span from DATE1 to DATE2 in terms of UNIT_NAME. */
211 expr_date_difference (double date1, double date2, struct substring unit_name,
212 const struct expression *e, const struct expr_node *n)
215 if (!recognize_unit (unit_name, e, n->args[2], &unit))
221 return (date2 >= date1
222 ? year_diff (date1, date2)
223 : -year_diff (date2, date1));
226 return (date2 >= date1
227 ? quarter_diff (date1, date2)
228 : -quarter_diff (date2, date1));
231 return (date2 >= date1
232 ? month_diff (date1, date2)
233 : -month_diff (date2, date1));
240 return trunc ((date2 - date1) / date_unit_duration (unit));
246 /* How to deal with days out of range for a given month. */
249 SUM_ROLLOVER, /* Roll them over to the next month. */
250 SUM_CLOSEST /* Use the last day of the month. */
253 /* Stores in *METHOD the method whose name is NAME.
256 recognize_method (struct substring method_name,
257 const struct expression *e, const struct expr_node *n,
258 enum date_sum_method *method)
260 if (ss_equals_case (method_name, ss_cstr ("closest")))
262 *method = SUM_CLOSEST;
265 else if (ss_equals_case (method_name, ss_cstr ("rollover")))
267 *method = SUM_ROLLOVER;
272 msg_at (SE, expr_location (e, n),
273 _("Invalid DATESUM method. "
274 "Valid choices are `%s' and `%s'."), "closest", "rollover");
279 /* Returns DATE advanced by the given number of MONTHS, with
280 day-of-month overflow resolved using METHOD. */
282 add_months (double date, int months, enum date_sum_method method,
283 const struct expression *e, const struct expr_node *n)
289 calendar_offset_to_gregorian (date / DAY_S, &y, &m, &d, &yd);
302 assert (m >= 1 && m <= 12);
304 if (method == SUM_CLOSEST && d > calendar_days_in_month (y, m))
305 d = calendar_days_in_month (y, m);
307 output = calendar_gregorian_to_offset (y, m, d, settings_get_fmt_settings (),
309 if (output != SYSMIS)
310 output = (output * DAY_S) + fmod (date, DAY_S);
313 msg_at (SE, expr_location (e, n), "%s", error);
319 /* Returns DATE advanced by the given QUANTITY of units given in
320 UNIT_NAME, with day-of-month overflow resolved using
323 expr_date_sum__ (double date, double quantity, struct substring unit_name,
324 enum date_sum_method method,
325 const struct expression *e, const struct expr_node *n)
328 if (!recognize_unit (unit_name, e, n->args[2], &unit))
334 return add_months (date, trunc (quantity) * 12, method, e, n);
337 return add_months (date, trunc (quantity) * 3, method, e, n);
340 return add_months (date, trunc (quantity), method, e, n);
347 return date + quantity * date_unit_duration (unit);
353 /* Returns DATE advanced by the given QUANTITY of units given in
354 UNIT_NAME, with day-of-month overflow resolved using
357 expr_date_sum (double date, double quantity, struct substring unit_name,
358 struct substring method_name,
359 const struct expression *e, const struct expr_node *n)
361 enum date_sum_method method;
362 if (!recognize_method (method_name, e, n->args[3], &method))
365 return expr_date_sum__ (date, quantity, unit_name, method, e, n);
368 /* Returns DATE advanced by the given QUANTITY of units given in
369 UNIT_NAME, with day-of-month overflow resolved using
372 expr_date_sum_closest (double date, double quantity, struct substring unit_name,
373 const struct expression *e, const struct expr_node *n)
375 return expr_date_sum__ (date, quantity, unit_name, SUM_CLOSEST, e, n);
379 compare_string_3way (const struct substring *a, const struct substring *b)
383 for (i = 0; i < a->length && i < b->length; i++)
384 if (a->string[i] != b->string[i])
385 return a->string[i] < b->string[i] ? -1 : 1;
386 for (; i < a->length; i++)
387 if (a->string[i] != ' ')
389 for (; i < b->length; i++)
390 if (b->string[i] != ' ')
396 count_valid (double *d, size_t n)
399 for (size_t i = 0; i < n; i++)
400 n_valid += is_valid (d[i]);
405 alloc_string (struct expression *e, size_t length)
409 s.string = pool_alloc (e->eval_pool, length);
414 copy_string (struct expression *e, const char *old, size_t length)
416 struct substring s = alloc_string (e, length);
417 memcpy (s.string, old, length);
422 round__ (double x, double mult, double fuzzbits, double adjustment)
425 fuzzbits = settings_get_fuzzbits ();
426 adjustment += exp2 (fuzzbits - DBL_MANT_DIG);
429 x = x >= 0. ? floor (x + adjustment) : -floor (-x + adjustment);
434 round_nearest (double x, double mult, double fuzzbits)
436 return round__ (x, mult, fuzzbits, .5);
440 round_zero (double x, double mult, double fuzzbits)
442 return round__ (x, mult, fuzzbits, 0);
446 replace_string (struct expression *e,
447 struct substring haystack,
448 struct substring needle,
449 struct substring replacement,
452 if (!needle.length || haystack.length < needle.length || n <= 0)
455 struct substring result = alloc_string (e, MAX_STRING);
459 while (i <= haystack.length - needle.length)
460 if (!memcmp (&haystack.string[i], needle.string, needle.length))
462 size_t copy_len = MIN (replacement.length, MAX_STRING - result.length);
463 memcpy (&result.string[result.length], replacement.string, copy_len);
464 result.length += copy_len;
472 if (result.length < MAX_STRING)
473 result.string[result.length++] = haystack.string[i];
476 while (i < haystack.length && result.length < MAX_STRING)
477 result.string[result.length++] = haystack.string[i++];
483 compare_doubles (const void *a_, const void *b_)
485 const double *ap = a_;
486 const double *bp = b_;
490 /* Sort SYSMIS to the end. */
498 median (double *a, size_t n)
500 /* Sort the array in-place, sorting SYSMIS to the end. */
501 qsort (a, n, sizeof *a, compare_doubles);
504 n = count_valid (a, n);
508 : (a[n / 2 - 1] + a[n / 2]) / 2.0);
511 const struct variable *
512 expr_index_vector (const struct expression *e, const struct expr_node *n,
513 const struct vector *v, double idx)
515 if (idx >= 1 && idx <= vector_get_n_vars (v))
516 return vector_get_var (v, idx - 1);
518 msg_at (SE, expr_location (e, n),
519 _("Index outside valid range 1 to %zu, inclusive, for vector %s. "
520 "The value will be treated as system-missing."),
521 vector_get_n_vars (v), vector_get_name (v));
523 msg_at (SN, expr_location (e, n->args[0]),
524 _("The index is system-missing."));
526 msg_at (SN, expr_location (e, n->args[0]),
527 _("The index has value %g."), idx);