Commit 8084ed94 authored by Morten Welinder's avatar Morten Welinder Committed by Morten Welinder

Fix float case of VLOOKUP/HLOOKUP/MATCH too.

2008-04-08  Morten Welinder  <terra@gnome.org>

	* src/mathfunc.c (gnm_float_hash, gnm_float_equal): Moved from
	rangefunc.c.  Made public.



svn path=/trunk/; revision=16495
parent fbd8c982
2008-04-08 Morten Welinder <terra@gnome.org>
* src/mathfunc.c (gnm_float_hash, gnm_float_equal): Moved from
rangefunc.c. Made public.
* src/dependent.c (workbook_recalc): If we recalculated anything,
emit recalc-finished on the application.
......
......@@ -65,7 +65,8 @@ Morten:
* Fix check for bogus xls files. [#524926]
* Fix CONCATENATE's empty case.
* Improve performance of analysis tools for large ranges.
* Fix performance of repeated [VH]LOOKUP with constant data range. [#525875]
* Fix performance repeated VLOOKUP/HLOOKUP/MATCH with constant
data range. [#525875]
Nick Lamb:
* Honour detachable-toolbar preference. [#321867]
......
......@@ -38,6 +38,7 @@
#include <expr-impl.h>
#include <application.h>
#include <expr-name.h>
#include <mathfunc.h>
#include <parse-util.h>
#include <gnm-i18n.h>
......@@ -50,6 +51,7 @@
GNM_PLUGIN_MODULE_HEADER;
static GHashTable *lookup_string_cache;
static GHashTable *lookup_float_cache;
static void
clear_caches (void)
......@@ -58,12 +60,27 @@ clear_caches (void)
g_hash_table_destroy (lookup_string_cache);
lookup_string_cache = NULL;
}
if (lookup_float_cache) {
g_hash_table_destroy (lookup_float_cache);
lookup_float_cache = NULL;
}
}
static GHashTable *
get_string_cache (const GnmSheetRange *sr)
get_cache (GnmFuncEvalInfo *ei, GnmValue const *data, gboolean stringp)
{
GnmSheetRange sr;
GHashTable *h;
Sheet *end_sheet;
GnmRangeRef const *rr;
if (data->type != VALUE_CELLRANGE)
return NULL;
rr = value_get_rangeref (data);
gnm_rangeref_normalize (rr, ei->pos, &sr.sheet, &end_sheet, &sr.range);
if (sr.sheet != end_sheet)
return NULL;
if (!lookup_string_cache) {
lookup_string_cache = g_hash_table_new_full
......@@ -73,12 +90,18 @@ get_string_cache (const GnmSheetRange *sr)
(GDestroyNotify)g_hash_table_destroy);
}
h = g_hash_table_lookup (lookup_string_cache, sr);
h = g_hash_table_lookup (lookup_string_cache, &sr);
if (!h) {
h = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, NULL);
if (stringp)
h = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free, NULL);
else
h = g_hash_table_new_full ((GHashFunc)gnm_float_hash,
(GEqualFunc)gnm_float_equal,
g_free, NULL);
g_hash_table_insert (lookup_string_cache,
gnm_sheet_range_dup (sr), h);
gnm_sheet_range_dup (&sr), h);
}
return h;
......@@ -198,25 +221,15 @@ find_index_linear_equal_string (GnmFuncEvalInfo *ei,
gpointer pres;
char *sc;
gboolean found;
GnmRangeRef const *rr;
Sheet *start_sheet, *end_sheet;
GnmSheetRange sr;
if (data->type != VALUE_CELLRANGE)
return -2;
rr = value_get_rangeref (data);
gnm_rangeref_normalize (rr, ei->pos, &start_sheet, &end_sheet, &sr.range);
if (start_sheet != end_sheet)
h = get_cache (ei, data, TRUE);
if (!h)
return -2;
/* We need to do this early before calls to value_peek_string gets
called too often. */
sc = g_utf8_casefold (s, -1);
sr.sheet = start_sheet;
h = get_string_cache (&sr);
if (g_hash_table_size (h) == 0) {
int lp, length = calc_length (data, ei->pos, vertical);
......@@ -224,7 +237,7 @@ find_index_linear_equal_string (GnmFuncEvalInfo *ei,
GnmValue const *v = get_elem (data, lp, ei->pos, vertical);
char *vc;
if (!VALUE_IS_STRING (v))
if (!v || !VALUE_IS_STRING (v))
continue;
vc = g_utf8_casefold (value_peek_string (v), -1);
......@@ -241,6 +254,44 @@ find_index_linear_equal_string (GnmFuncEvalInfo *ei,
return found ? GPOINTER_TO_INT (pres) : -1;
}
static int
find_index_linear_equal_float (GnmFuncEvalInfo *ei,
gnm_float f, GnmValue const *data,
gboolean vertical)
{
GHashTable *h;
gpointer pres;
gboolean found;
h = get_cache (ei, data, FALSE);
if (!h)
return -2;
if (g_hash_table_size (h) == 0) {
int lp, length = calc_length (data, ei->pos, vertical);
for (lp = 0; lp < length; lp++) {
GnmValue const *v = get_elem (data, lp, ei->pos, vertical);
gnm_float f2;
if (!v || !VALUE_IS_NUMBER (v))
continue;
f2 = value_get_as_float (v);
if (!g_hash_table_lookup_extended (h, &f2, NULL, NULL))
g_hash_table_insert
(h,
g_memdup (&f2, sizeof (f2)),
GINT_TO_POINTER (lp));
}
}
found = g_hash_table_lookup_extended (h, &f, NULL, &pres);
return found ? GPOINTER_TO_INT (pres) : -1;
}
static int
find_index_linear (GnmFuncEvalInfo *ei,
GnmValue const *find, GnmValue const *data,
......@@ -257,6 +308,13 @@ find_index_linear (GnmFuncEvalInfo *ei,
return i;
}
if (VALUE_IS_NUMBER (find) && type == 0) {
gnm_float f = value_get_as_float (find);
int i = find_index_linear_equal_float (ei, f, data, vertical);
if (i != -2)
return i;
}
length = calc_length (data, ei->pos, vertical);
for (lp = 0; lp < length; lp++) {
......
......@@ -7760,3 +7760,22 @@ lgamma_r (double x, int *signp)
#endif
/* ------------------------------------------------------------------------- */
gint
gnm_float_equal (gnm_float const *a, const gnm_float *b)
{
return (*a == *b);
}
guint
gnm_float_hash (gnm_float const *d)
{
int expt;
gnm_float mant = gnm_frexp (gnm_abs (*d), &expt);
guint h = ((guint)(0x80000000u * mant)) ^ expt;
if (*d >= 0)
h ^= 0x55555555;
return h;
}
/* ------------------------------------------------------------------------- */
......@@ -183,6 +183,9 @@ gnm_float combin (gnm_float n, gnm_float k);
gnm_float permut (gnm_float n, gnm_float k);
gnm_float fact (int n);
gint gnm_float_equal (gnm_float const *a, const gnm_float *b);
guint gnm_float_hash (gnm_float const *d);
void mathfunc_init (void);
/* ------------------------------------------------------------------------- */
......
......@@ -424,25 +424,6 @@ gnm_range_rsq_est (gnm_float const *xs, const gnm_float *ys, int n, gnm_float *r
return 0;
}
static guint
float_hash (gnm_float const *d)
{
int expt;
gnm_float mant = gnm_frexp (gnm_abs (*d), &expt);
guint h = ((guint)(0x80000000u * mant)) ^ expt;
if (*d >= 0)
h ^= 0x55555555;
return h;
}
static gint
float_equal (gnm_float const *a, const gnm_float *b)
{
if (*a == *b)
return 1;
return 0;
}
/* Most-common element. (The one whose first occurrence comes first in
case of several equally common. */
int
......@@ -456,8 +437,8 @@ gnm_range_mode (gnm_float const *xs, int n, gnm_float *res)
if (n <= 1) return 1;
h = g_hash_table_new_full ((GHashFunc)float_hash,
(GCompareFunc)float_equal,
h = g_hash_table_new_full ((GHashFunc)gnm_float_hash,
(GCompareFunc)gnm_float_equal,
NULL,
(GDestroyNotify)g_free);
for (i = 0; i < n; i++) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment