From 264cb1a74b754df0455284ae6688ce8d275f9d06 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sun, 13 Mar 2016 12:10:22 -0700 Subject: [PATCH] expressions: Add support for mult and fuzzbits arguments to TRUNC function. --- NEWS | 5 +++++ doc/expressions.texi | 11 ++++++++--- src/language/expressions/helpers.c | 18 ++++++++++++++---- src/language/expressions/helpers.h | 1 + src/language/expressions/operations.def | 4 +++- tests/language/expressions/evaluate.at | 13 ++++++++++++- 6 files changed, 43 insertions(+), 9 deletions(-) diff --git a/NEWS b/NEWS index bb69e05490..d280e7f719 100644 --- a/NEWS +++ b/NEWS @@ -46,6 +46,11 @@ Changes from 0.8.5 to 0.9.0: - MEDIAN, to compute the median of its arguments. + - The TRUNC function in expressions now supports additional arguments + for truncating to values other than integers and to indicate a level + of rounding fuzz. The default rounding fuzz may now be controlled + and displayed with SET FUZZBITS and SHOW FUZZBITS, respectively. + * Bug fixes, including the following notable ones: - The correlation coefficient in the paired samples t-test diff --git a/doc/expressions.texi b/doc/expressions.texi index 5898d53d77..d27d11b407 100644 --- a/doc/expressions.texi +++ b/doc/expressions.texi @@ -342,9 +342,14 @@ FUZZBITS}), which is 6 unless overridden. @end deftypefn @cindex truncation -@deftypefn {Function} {} TRUNC (@var{number}) -Discards the fractional part of @var{number}; that is, rounds -@var{number} towards zero. +@deftypefn {Function} {} TRUNC (@var{number} [, @var{mult}[, @var{fuzzbits}]]) +Rounds @var{number} to a multiple of @var{mult}, toward zero. For the +default @var{mult} of 1, this is equivalent to discarding the +fractional part of @var{number}. Values that fall short of a multiple +of @var{mult} by less than @var{fuzzbits} of errors in the +least-significant bits of @var{number} are rounded away from zero. If +@var{fuzzbits} is not specified then the default is taken from SET +FUZZBITS (@pxref{SET FUZZBITS}), which is 6 unless overridden. @end deftypefn @node Trigonometry diff --git a/src/language/expressions/helpers.c b/src/language/expressions/helpers.c index 57e17713b9..6e73887285 100644 --- a/src/language/expressions/helpers.c +++ b/src/language/expressions/helpers.c @@ -665,19 +665,29 @@ npdf_beta (double x, double a, double b, double lambda) } double -round_nearest (double x, double mult, double fuzzbits) +round__ (double x, double mult, double fuzzbits, double adjustment) { - double adjustment; - if (fuzzbits <= 0) fuzzbits = settings_get_fuzzbits (); - adjustment = .5 + exp2 (fuzzbits - DBL_MANT_DIG); + 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, diff --git a/src/language/expressions/helpers.h b/src/language/expressions/helpers.h index c4e3323406..8646233b66 100644 --- a/src/language/expressions/helpers.h +++ b/src/language/expressions/helpers.h @@ -82,6 +82,7 @@ double cdf_bvnor (double x0, double x1, double r); double idf_fdist (double P, double a, double b); double round_nearest (double x, double mult, double fuzzbits); +double round_zero (double x, double mult, double fuzzbits); struct substring replace_string (struct expression *, struct substring haystack, diff --git a/src/language/expressions/operations.def b/src/language/expressions/operations.def index eb05661678..e8f1f781dc 100644 --- a/src/language/expressions/operations.def +++ b/src/language/expressions/operations.def @@ -90,7 +90,9 @@ function RND (x, mult != 0, fuzzbits >= 0) = round_nearest (x, mult, fuzzbits); function SIN (x) = sin (x); function SQRT (x >= 0) = sqrt (x); function TAN (x) = check_errno (tan (x)); -function TRUNC (x) = x >= 0. ? floor (x) : -floor (-x); +function TRUNC (x) = round_zero (x, 1, 0); +function TRUNC (x, mult != 0) = round_zero (x, mult, 0); +function TRUNC (x, mult != 0, fuzzbits >= 0) = round_zero (x, mult, fuzzbits); absorb_miss function MOD (n, d) { diff --git a/tests/language/expressions/evaluate.at b/tests/language/expressions/evaluate.at index ae7c89a5bb..15641d6073 100644 --- a/tests/language/expressions/evaluate.at +++ b/tests/language/expressions/evaluate.at @@ -352,8 +352,19 @@ RND(number, number, number).]], [[trunc(1.9)], [1.00]], [[trunc(-1.2)], [-1.00]], [[trunc(-1.9)], [-1.00]], + [[trunc(5.06, .1)], [5.00]], + [[trunc(-5.06, .1)], [-5.00]], + [[trunc(1)], [1.00]], + [[trunc(1 - 2**-53)], [1.00]], + [[trunc(1 - 2**-52)], [1.00]], + [[trunc(1 - 2**-51)], [1.00]], + [[trunc(1 - 2**-45)], [0.00]], + [[trunc(1 - 2**-45, 1, 10)], [1.00]], [[trunc('x')], [error], - [error: DEBUG EVALUATE: Type mismatch invoking TRUNC(number) as trunc(string).]]) + [error: DEBUG EVALUATE: Function invocation trunc(string) does not match any known function. Candidates are: +TRUNC(number) +TRUNC(number, number) +TRUNC(number, number, number).]]) CHECK_EXPR_EVAL([acos arsin artan cos sin tan], [[acos(.5) / 3.14159 * 180], [60.00]], -- 2.30.2