From: John Darrington Date: Sun, 14 Jun 2020 15:07:27 +0000 (+0200) Subject: GUI: Find dialog: Compare only to the decimal places of the print format. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=aae1a8f067ddd9c091b2ed591f7d496fe98a35e0;p=pspp GUI: Find dialog: Compare only to the decimal places of the print format. When using the find dialog of the data editor, previously a numeric value was compared exactly on it's underlying representation (a IEEE754 double precision float). This is problematic, because most such floats cannot be precisely represented in a decimal format, and even if they can be, the precision required might well exceed that displayed in the data editor. This change rounds both the reference and the comparand to the number of decimal places indicated by the variable's print format. --- diff --git a/NEWS b/NEWS index 2322a00f09..7cb3c135b4 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,10 @@ Please send PSPP bug reports to bug-gnu-pspp@gnu.org. Changes from 1.2.0 to 1.3.0: + * The Find dialog box, when searching for numeric values, will match only + to the precision of the variable's print format. This avoids behaviour + which is suprising to some users. + * PSPP now supports the SPSS viewer (.spv) format that SPSS 16 and later use to save the contents of its output editor: diff --git a/src/ui/gui/find-dialog.c b/src/ui/gui/find-dialog.c index 52f26d4a69..2ff619a60a 100644 --- a/src/ui/gui/find-dialog.c +++ b/src/ui/gui/find-dialog.c @@ -25,6 +25,7 @@ which match particular strings */ #include #include #include +#include #include "data/data-in.h" #include "data/datasheet.h" @@ -428,11 +429,13 @@ struct comparator }; -/* A comparator which operates on the unadulterated union values */ -struct value_comparator +/* A comparator which operates on the numerical values, + rounded to the number of decimal places indicated by + the variable's format. */ +struct numeric_comparator { struct comparator parent; - union value pattern; + double rounded_ref; }; /* A comparator which matches string values or parts thereof */ @@ -454,8 +457,12 @@ static bool value_compare (const struct comparator *cmptr, const union value *v) { - const struct value_comparator *vc = (const struct value_comparator *) cmptr; - return 0 == value_compare_3way (v, &vc->pattern, var_get_width (cmptr->var)); + const struct numeric_comparator *nc = (const struct numeric_comparator *) cmptr; + const struct fmt_spec *fs = var_get_print_format (cmptr->var); + + double c = nearbyint (v->f * exp10 (fs->d)); + + return c == nc->rounded_ref; } @@ -572,27 +579,21 @@ regexp_destroy (struct comparator *cmptr) regfree (&rec->re); } -static void -cmptr_value_destroy (struct comparator *cmptr) -{ - struct value_comparator *vc - = UP_CAST (cmptr, struct value_comparator, parent); - value_destroy (&vc->pattern, var_get_width (cmptr->var)); -} - - static struct comparator * -value_comparator_create (const struct variable *var, const char *target) +numeric_comparator_create (const struct variable *var, const char *target) { - struct value_comparator *vc = xzalloc (sizeof (*vc)); - struct comparator *cmptr = &vc->parent; + struct numeric_comparator *nc = xzalloc (sizeof (*nc)); + struct comparator *cmptr = &nc->parent; cmptr->flags = 0; cmptr->var = var; - cmptr->compare = value_compare ; - cmptr->destroy = cmptr_value_destroy; + cmptr->compare = value_compare; + const struct fmt_spec *fs = var_get_write_format (var); - text_to_value (target, var, &vc->pattern); + union value val; + text_to_value (target, var, &val); + nc->rounded_ref = nearbyint (val.f * exp10 (fs->d)); + value_destroy (&val, var_get_width (var)); return cmptr; } @@ -686,7 +687,7 @@ comparator_factory (const struct variable *var, const char *str, if (flags & (STR_CMP_SUBSTR | STR_CMP_LABELS)) return string_comparator_create (var, str, flags); - return value_comparator_create (var, str); + return numeric_comparator_create (var, str); }