X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Fexpressions%2Fhelpers.c;h=4a0a01b97b680907b0c1efe33f9bb1010e68891a;hb=bb4f63c29bd0682115e5708332289423685b30a8;hp=ac17c1cece19ce842bde63ae9495daac3d6e0109;hpb=6549c9aced0949b16abb372257772fc0893e02bb;p=pspp diff --git a/src/language/expressions/helpers.c b/src/language/expressions/helpers.c index ac17c1cece..4a0a01b97b 100644 --- a/src/language/expressions/helpers.c +++ b/src/language/expressions/helpers.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2008, 2010 Free Software Foundation, Inc. + 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 @@ -15,12 +15,17 @@ along with this program. If not, see . */ #include -#include "helpers.h" + +#include "language/expressions/helpers.h" + #include #include -#include -#include -#include "private.h" + +#include "language/expressions/private.h" +#include "libpspp/assertion.h" +#include "libpspp/pool.h" + +#include "gl/minmax.h" const struct substring empty_string = {NULL, 0}; @@ -40,7 +45,8 @@ expr_ymd_to_ofs (double year, double month, double day) return SYSMIS; } - ofs = calendar_gregorian_to_offset (y, m, d, &error); + ofs = calendar_gregorian_to_offset (y, m, d, settings_get_fmt_settings (), + &error); if (error != NULL) { msg (SE, "%s", error); @@ -172,12 +178,13 @@ recognize_unit (struct substring name, enum date_unit *unit) return true; } - /* TRANSLATORS: Don't translate the the actual unit names `weeks', `days' etc - They must remain in their original English. */ 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)); + "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; } @@ -325,7 +332,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; } } @@ -357,7 +364,8 @@ 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, &error); + output = calendar_gregorian_to_offset (y, m, d, settings_get_fmt_settings (), + &error); if (output != SYSMIS) output = (output * DAY_S) + fmod (date, DAY_S); else @@ -657,3 +665,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); +}