expressions: Add support for 2- and 3-operand RND function.
authorBen Pfaff <blp@cs.stanford.edu>
Sat, 7 Mar 2015 08:36:42 +0000 (00:36 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Sat, 7 Mar 2015 08:36:42 +0000 (00:36 -0800)
Requested by Tom Smekens.

NEWS
doc/expressions.texi
doc/utilities.texi
src/data/settings.c
src/data/settings.h
src/language/expressions/helpers.c
src/language/expressions/helpers.h
src/language/expressions/operations.def
src/language/utilities/set.q
tests/language/expressions/evaluate.at

diff --git a/NEWS b/NEWS
index c1746d6bc89c429588f118c0fec77ab68a5e6040..ed0530656235095bdf155a27f4268f89753b8e74 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -24,6 +24,11 @@ Changes since 0.8.4:
  * The GRAPH command is now available.  Initially it supports
    scatterplots and histograms.
 
+ * The RND operator in expressions now supports additional operands
+   for rounding 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.
+
 Changes from 0.8.3 to 0.8.4:
 
  * Formatting of SYSFILE INFO output was made easier to read.
index 1570d0dfb437ce72072a677b52898484534395cd..7180bf8793ea24a3c0907c13d70eb3ce1e7ef87e 100644 (file)
@@ -331,9 +331,13 @@ Returns the remainder when @var{number} is divided by 10.  If
 @end deftypefn
 
 @cindex rounding
-@deftypefn {Function} {} RND (@var{number})
-Takes the absolute value of @var{number} and rounds it to an integer.
-Then, if @var{number} was negative originally, negates the result.
+@deftypefn {Function} {} RND (@var{number} [, @var{mult}[, @var{fuzzbits}]])
+Rounds @var{number} and rounds it to a multiple of @var{mult} (by
+default 1).  Halves are rounded away from zero, as are values that
+fall short of halves by less than @var{fuzzbits} of errors in the
+least-significant bits of @var{number}.  If @var{fuzzbits} is not
+specified then the default is taken from SET FUZZBITS (@pxref{SET
+FUZZBITS}), which is 6 unless overridden.
 @end deftypefn
 
 @cindex truncation
index da5b7b0daae7d3f5ae0e99f053b53e2d8c475af2..eb30f892d570444a5036fb963090762b617e720a 100644 (file)
@@ -440,6 +440,7 @@ SET
         /MXLOOPS=@var{max_loops}
         /SEED=@{RANDOM,@var{seed_value}@}
         /UNDEFINED=@{WARN,NOWARN@}
+        /FUZZBITS=@var{fuzzbits}
 
 (data output)
         /CC@{A,B,C,D,E@}=@{'@var{npre},@var{pre},@var{suf},@var{nsuf}','@var{npre}.@var{pre}.@var{suf}.@var{nsuf}'@}
@@ -642,6 +643,13 @@ RANDOM, which will obtain an initial seed from the current time of day.
 @item UNDEFINED
 Currently not used.
 
+@item FUZZBITS
+@anchor{SET FUZZBITS}
+The maximum number of bits of errors in the least-significant places
+to accept for rounding up a value that is almost halfway between two
+possibilities for rounding with the RND operator (@pxref{Miscellaneous
+Mathematics}).  The default @var{fuzzbits} is 6.
+
 @item WORKSPACE
 The maximum amount of memory (in kilobytes) that @pspp{} will use to store data being processed.
 If memory in excess of the workspace size is required, then @pspp{} will start
@@ -878,6 +886,7 @@ SHOW
         [DIRECTORY]
         [ENVIRONMENT]
         [FORMAT]
+        [FUZZBITS]
         [LENGTH]
         [MXERRS]
         [MXLOOPS]
index 4c0fde083740ea483852acbaa56e1b53b07dbbb8..5c4e6899b90bd66befbeead94ae40bed2ac64afe 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011, 2015 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
@@ -66,6 +66,7 @@ struct settings
   size_t workspace;
   struct fmt_spec default_format;
   bool testing_mode;
+  int fuzzbits;
 
   int cmd_algorithm;
   int global_algorithm;
@@ -108,6 +109,7 @@ static struct settings the_settings = {
   64L * 1024 * 1024,            /* workspace */
   {FMT_F, 8, 2},                /* default_format */
   false,                        /* testing_mode */
+  6,                            /* fuzzbits */
   ENHANCED,                     /* cmd_algorithm */
   ENHANCED,                     /* global_algorithm */
   ENHANCED,                     /* syntax */
@@ -487,6 +489,18 @@ settings_set_testing_mode ( bool testing_mode)
   the_settings.testing_mode = testing_mode;
 }
 
+int
+settings_get_fuzzbits (void)
+{
+  return the_settings.fuzzbits;
+}
+
+void
+settings_set_fuzzbits (int fuzzbits)
+{
+  the_settings.fuzzbits = fuzzbits;
+}
+
 /* Return the current algorithm setting */
 enum behavior_mode
 settings_get_algorithm (void)
index 409b7fe9ebffb690340dc8ebfbc3f0aca2fb442e..c499293ebb54a49648297af98ce35119295c7b0d 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2015 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
@@ -102,6 +102,9 @@ void settings_set_format ( const struct fmt_spec *);
 bool settings_get_testing_mode (void);
 void settings_set_testing_mode (bool);
 
+int settings_get_fuzzbits (void);
+void settings_set_fuzzbits (int);
+
 enum settings_var_style
   {
     SETTINGS_VAR_STYLE_NAMES,
index 720d910f686dd6993c9df4d3d19fc9762af9548e..5aad13eb160b5f3f160481fcdaefa30a92b05354 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008, 2010, 2011 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2010, 2011, 2015 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
@@ -661,3 +661,17 @@ npdf_beta (double x, double a, double b, double lambda)
       return sum;
     }
 }
+
+double
+round_nearest (double x, double mult, double fuzzbits)
+{
+  double adjustment;
+
+  if (fuzzbits <= 0)
+    fuzzbits = settings_get_fuzzbits ();
+  adjustment = .5 + exp2 (fuzzbits - DBL_MANT_DIG);
+
+  x /= mult;
+  x = x >= 0. ? floor (x + adjustment) : -floor (-x + adjustment);
+  return x * mult;
+}
index ef4fdadd4d310c2842fbaba74e0cfec2ef335b91..0d349f7fd9d91510a9f4674336179e44d5d7258d 100644 (file)
@@ -81,4 +81,6 @@ 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);
+
 #endif /* expressions/helpers.h */
index 37af54a9118abf8755fd0205cdaebdbe20021f46..60ed2eac2022b863af4ef05dbf34f22452687aa5 100644 (file)
@@ -1,7 +1,7 @@
 // -*- c -*-
 //
 // PSPP - a program for statistical analysis.
-// Copyright (C) 2005, 2006, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+// Copyright (C) 2005, 2006, 2009, 2010, 2011, 2012, 2015 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
@@ -84,7 +84,9 @@ function LG10(x) = check_errno (log10 (x));
 function LN (x) = check_errno (log (x));
 function LNGAMMA (x >= 0) = gsl_sf_lngamma (x);
 function MOD10 (x) = fmod (x, 10);
-function RND (x) = x >= 0. ? floor (x + .5) : -floor (-x + .5);
+function RND (x) = round_nearest (x, 1, 0);
+function RND (x, mult != 0) = round_nearest (x, mult, 0);
+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));
index f90e3e14de3d8e675b7988879a79c3a2cca83b67..0be8c47010a7cf541501487456e3ba7eae686de8 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012, 2013, 2014, 2015 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
@@ -80,6 +80,7 @@ int tgetnum (const char *);
      epoch=custom;
      errors=custom;
      format=custom;
+     fuzzbits=integer;
      headers=headers:no/yes/blank;
      highres=hires:on/off;
      histogram=string;
@@ -153,6 +154,14 @@ cmd_set (struct lexer *lexer, struct dataset *ds)
 
   if (cmd.sbc_decimal)
     settings_set_decimal_char (cmd.dec == STC_DOT ? '.' : ',');
+  if (cmd.sbc_fuzzbits)
+    {
+      int fuzzbits = cmd.n_fuzzbits[0];
+      if (fuzzbits >= 0 && fuzzbits <= 20)
+        settings_set_fuzzbits (fuzzbits);
+      else
+        msg (SE, _("%s must be between 0 and 20."), "FUZZBITS");
+    }
 
   if (cmd.sbc_include)
     settings_set_include (cmd.inc == STC_ON);
@@ -710,6 +719,12 @@ show_format (const struct dataset *ds UNUSED)
   return xstrdup (fmt_to_string (settings_get_format (), str));
 }
 
+static char *
+show_fuzzbits (const struct dataset *ds UNUSED)
+{
+  return xasprintf ("%d", settings_get_fuzzbits ());
+}
+
 static char *
 show_journal (const struct dataset *ds UNUSED)
 {
@@ -952,6 +967,7 @@ const struct show_sbc show_table[] =
     {"ENVIRONMENT", show_system},
     {"ERRORS", show_errors},
     {"FORMAT", show_format},
+    {"FUZZBITS", show_fuzzbits},
     {"JOURNAL", show_journal},
     {"LENGTH", show_length},
     {"LOCALE", show_locale},
index cd514fef93d2455272318b94f78bc311447ed6b3..846eee482b858a3f359df1bfa9685fa7f2050080 100644 (file)
@@ -334,8 +334,19 @@ CHECK_EXPR_EVAL([exp lg10 ln sqrt abs mod mod10 rnd trunc],
   [[rnd(5.6)], [6.00]],
   [[rnd(-5.4)], [-5.00]],
   [[rnd(-5.6)], [-6.00]],
+  [[rnd(5.56, .1)], [5.60]],
+  [[rnd(-5.56, .1)], [-5.60]],
+  [[rnd(.5)], [1.00]],
+  [[rnd(.5 - 2**-53)], [1.00]],
+  [[rnd(.5 - 2**-52)], [1.00]],
+  [[rnd(.5 - 2**-51)], [1.00]],
+  [[rnd(.5 - 2**-45)], [0.00]],
+  [[rnd(.5 - 2**-45, 1, 10)], [1.00]],
   [[rnd('x')], [error],
-   [error: DEBUG EVALUATE: Type mismatch invoking RND(number) as rnd(string).]],
+   [error: DEBUG EVALUATE: Function invocation rnd(string) does not match any known function.  Candidates are:
+RND(number)
+RND(number, number)
+RND(number, number, number).]],
 
   [[trunc(1.2)], [1.00]],
   [[trunc(1.9)], [1.00]],