X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Fexpressions%2Fhelpers.c;h=c69e440e4bde0f9c8747296884c0cf83e9ce2b45;hb=3b54533821614d17afc61f1cd3b87d3a06fbf4da;hp=a28f1a666ef2180ea17730c024dbfe19f4d1980e;hpb=49622888cd4954bf11544b2e43f58e523c9954b5;p=pspp
diff --git a/src/language/expressions/helpers.c b/src/language/expressions/helpers.c
index a28f1a666e..c69e440e4b 100644
--- a/src/language/expressions/helpers.c
+++ b/src/language/expressions/helpers.c
@@ -1,27 +1,33 @@
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2008, 2010, 2011, 2015, 2016 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see . */
+
#include
-#include "helpers.h"
+
+#include "language/expressions/helpers.h"
+
#include
#include
-#include
-#include
-#include "private.h"
-const struct substring empty_string = {NULL, 0};
+#include "language/expressions/private.h"
+#include "libpspp/assertion.h"
+#include "libpspp/pool.h"
-static void
-expr_error (void *aux UNUSED, const char *format, ...)
-{
- struct msg m;
- va_list args;
-
- m.category = MSG_SYNTAX;
- m.severity = MSG_ERROR;
- va_start (args, format);
- m.text = xvasprintf (format, args);
- va_end (args);
+#include "gl/minmax.h"
- msg_emit (&m);
-}
+const struct substring empty_string = {NULL, 0};
double
expr_ymd_to_ofs (double year, double month, double day)
@@ -29,6 +35,8 @@ expr_ymd_to_ofs (double year, double month, double day)
int y = year;
int m = month;
int d = day;
+ char *error;
+ double ofs;
if (y != year || m != month || d != day)
{
@@ -37,7 +45,13 @@ expr_ymd_to_ofs (double year, double month, double day)
return SYSMIS;
}
- return calendar_gregorian_to_offset (y, m, d, expr_error, NULL);
+ ofs = calendar_gregorian_to_offset (y, m, d, &error);
+ if (error != NULL)
+ {
+ msg (SE, "%s", error);
+ free (error);
+ }
+ return ofs;
}
double
@@ -163,10 +177,13 @@ recognize_unit (struct substring name, enum date_unit *unit)
return true;
}
- msg (SE, _("Unrecognized date unit \"%.*s\". "
- "Valid date units are \"years\", \"quarters\", \"months\", "
- "\"weeks\", \"days\", \"hours\", \"minutes\", and \"seconds\"."),
- (int) ss_length (name), ss_data (name));
+ msg (SE, _("Unrecognized date unit `%.*s'. "
+ "Valid date units are `%s', `%s', `%s', "
+ "`%s', `%s', `%s', `%s', and `%s'."),
+ (int) ss_length (name), ss_data (name),
+ "years", "quarters", "months",
+ "weeks", "days", "hours", "minutes", "seconds");
+
return false;
}
@@ -314,7 +331,7 @@ recognize_method (struct substring method_name, enum date_sum_method *method)
else
{
msg (SE, _("Invalid DATESUM method. "
- "Valid choices are \"closest\" and \"rollover\"."));
+ "Valid choices are `%s' and `%s'."), "closest", "rollover");
return false;
}
}
@@ -326,6 +343,7 @@ add_months (double date, int months, enum date_sum_method method)
{
int y, m, d, yd;
double output;
+ char *error;
calendar_offset_to_gregorian (date / DAY_S, &y, &m, &d, &yd);
y += months / 12;
@@ -345,9 +363,14 @@ add_months (double date, int months, enum date_sum_method method)
if (method == SUM_CLOSEST && d > calendar_days_in_month (y, m))
d = calendar_days_in_month (y, m);
- output = calendar_gregorian_to_offset (y, m, d, expr_error, NULL);
+ output = calendar_gregorian_to_offset (y, m, d, &error);
if (output != SYSMIS)
output = (output * DAY_S) + fmod (date, DAY_S);
+ else
+ {
+ msg (SE, "%s", error);
+ free (error);
+ }
return output;
}
@@ -388,7 +411,7 @@ expr_date_sum (double date, double quantity, struct substring unit_name,
}
int
-compare_string (const struct substring *a, const struct substring *b)
+compare_string_3way (const struct substring *a, const struct substring *b)
{
size_t i;
@@ -573,14 +596,14 @@ ncdf_beta (double x, double a, double b, double lambda)
double
cdf_bvnor (double x0, double x1, double r)
{
- double z = x0 * x0 - 2. * r * x0 * x1 + x1 * x1;
+ double z = pow2 (x0) - 2. * r * x0 * x1 + pow2 (x1);
return exp (-z / (2. * (1 - r * r))) * (2. * M_PI * sqrt (1 - r * r));
}
double
idf_fdist (double P, double df1, double df2)
{
- double temp = gslextras_cdf_beta_Pinv (P, df1 / 2, df2 / 2);
+ double temp = gsl_cdf_beta_Pinv (P, df1 / 2, df2 / 2);
return temp * df2 / ((1. - temp) * df1);
}
@@ -640,3 +663,96 @@ npdf_beta (double x, double a, double b, double lambda)
return sum;
}
}
+
+static double
+round__ (double x, double mult, double fuzzbits, double adjustment)
+{
+ if (fuzzbits <= 0)
+ fuzzbits = settings_get_fuzzbits ();
+ adjustment += exp2 (fuzzbits - DBL_MANT_DIG);
+
+ x /= mult;
+ x = x >= 0. ? floor (x + adjustment) : -floor (-x + adjustment);
+ return x * mult;
+}
+
+double
+round_nearest (double x, double mult, double fuzzbits)
+{
+ return round__ (x, mult, fuzzbits, .5);
+}
+
+double
+round_zero (double x, double mult, double fuzzbits)
+{
+ return round__ (x, mult, fuzzbits, 0);
+}
+
+struct substring
+replace_string (struct expression *e,
+ struct substring haystack,
+ struct substring needle,
+ struct substring replacement,
+ double n)
+{
+ if (!needle.length
+ || haystack.length < needle.length
+ || n <= 0
+ || n == SYSMIS)
+ return haystack;
+
+ struct substring result = alloc_string (e, MAX_STRING);
+ result.length = 0;
+
+ size_t i = 0;
+ while (i <= haystack.length - needle.length)
+ if (!memcmp (&haystack.string[i], needle.string, needle.length))
+ {
+ size_t copy_len = MIN (replacement.length, MAX_STRING - result.length);
+ memcpy (&result.string[result.length], replacement.string, copy_len);
+ result.length += copy_len;
+ i += needle.length;
+
+ if (--n < 1)
+ break;
+ }
+ else
+ {
+ if (result.length < MAX_STRING)
+ result.string[result.length++] = haystack.string[i];
+ i++;
+ }
+ while (i < haystack.length && result.length < MAX_STRING)
+ result.string[result.length++] = haystack.string[i++];
+
+ return result;
+}
+
+static int
+compare_doubles (const void *a_, const void *b_)
+{
+ const double *ap = a_;
+ const double *bp = b_;
+ double a = *ap;
+ double b = *bp;
+
+ /* Sort SYSMIS to the end. */
+ return (a == b ? 0
+ : a == SYSMIS ? 1
+ : b == SYSMIS ? -1
+ : a > b ? 1 : -1);
+}
+
+double
+median (double *a, size_t n)
+{
+ /* Sort the array in-place, sorting SYSMIS to the end. */
+ qsort (a, n, sizeof *a, compare_doubles);
+
+ /* Drop SYSMIS. */
+ n = count_valid (a, n);
+
+ return (!n ? SYSMIS
+ : n % 2 ? a[n / 2]
+ : (a[n / 2 - 1] + a[n / 2]) / 2.0);
+}