[m-dev.] Re: pragma fact_table
David Matthew OVERTON
dmo at students.cs.mu.oz.au
Wed Feb 26 14:44:05 AEDT 1997
Hi Fergus,
Fergus Henderson wrote:
>
>
> There is also a potential problem if the compilers optimize these two
> versions differently. For example, on many machines floating point
> registers may have more accuracy than floating point values stored
> in memory, so that the exact end result of a floating point computation
> may in fact depend on exactly how the compiler allocates registers.
>
> The problem of the two hashing codes being inconsistent should be fixed
> by avoiding the code duplication and only having one piece of code for
> computing float hashes.
>
> Hashing floats is something that is generally useful, and we already
> have string__hash_string in library/string.m, so it would make sense to
> define this float hashing function in library/float.m. It is probably
> easiest if you use the C code version and define the Mercury version to
> call the C version using `pragma c_code'. The C code should be in a
> `:- pragma c_code("....")' block in library/float.m.
> (The alternative of using the Mercury code version and calling that
> from C using `pragma export' is also possible but the other way is
> likely to be more efficient.)
>
Here are the changes to add the new `float__hash' predicate. I thought
it would be easier to put the C function `hash_float' into the runtime
(as is done with `hash_string') because it is then available whenever
it is needed by the fact table lookup code rather than having to
import the float module. Is that a good idea or not? Should I add a
version to float.nu.nl as well?
Also it is a C function rather than a macro to reduce problems due to
the compiler optimising the code differently in different places.
Tom has suggested an alternative (much more efficient) method that
uses a union of Float and Word to convert the float's bit pattern to
an integer (the same as float_to_word() for UNBOXED_FLOATS). However
I haven't used this method at the moment because (AFAIK) it can't be
implemented in prolog.
David.
Estimated hours taken: 2
Add new predicate `float__hash' to the standard library for computing a
non-negative integer hash value for a float.
Add a C function to the runtime to do the actual hashing. This
function is in the runtime so that it can be called from both
the library and from C code generated for `pragma fact_table'
indexing.
library/float.m
Add a new predicate `float__hash' that calls the runtime
function `hash_float'.
runtime/misc.c
Add a new function `hash_float' for hashing floats.
runtime/mercury_float.m
Add an `extern' declaration for `hash_float'.
Index: library//float.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/library/float.m,v
retrieving revision 1.20
diff -u -r1.20 float.m
--- float.m 1996/07/26 06:00:14 1.20
+++ float.m 1997/02/26 03:07:51
@@ -156,6 +156,12 @@
:- mode float__epsilon(out) is det.
%---------------------------------------------------------------------------%
+% Create a non-negative integer hash value for a float.
+
+:- pred float__hash(float, int).
+:- mode float__hash(in, out) is det.
+
+%---------------------------------------------------------------------------%
:- implementation.
:- import_module int, require.
@@ -286,6 +292,14 @@
% Smallest x such that x \= 1.0 + x
:- pragma(c_code, float__epsilon(Eps::out), "Eps = MERCURY_FLOAT_EPSILON;").
+
+%---------------------------------------------------------------------------%
+
+:- pragma c_code(float__hash(F::in, H::out), will_not_call_mercury, "
+
+ H = hash_float(F);
+
+").
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
Index: library/runtime//mercury_float.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/mercury_float.h,v
retrieving revision 1.3
diff -u -r1.3 mercury_float.h
--- mercury_float.h 1997/02/12 02:15:50 1.3
+++ mercury_float.h 1997/02/25 23:59:09
@@ -72,4 +72,6 @@
#endif /* not BOXED_FLOAT */
+extern Integer hash_float(Float);
+
#endif /* not MERCURY_FLOAT_H */
Index: library/runtime//misc.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/misc.c,v
retrieving revision 1.9
diff -u -r1.9 misc.c
--- misc.c 1997/02/12 07:41:12 1.9
+++ misc.c 1997/02/26 03:32:53
@@ -10,6 +10,7 @@
#include "misc.h"
#include <stdio.h>
+#include <math.h>
/*--------------------------------------------------------------------*/
@@ -490,4 +491,36 @@
hash_string(Word s)
{
HASH_STRING_FUNC_BODY
+}
+
+/*
+** This function is used by the library predicate `float__hash/2' and also
+** for hashing floats for `pragma fact_table' indexing.
+**
+** How it works: first ensure f is positive by taking the absolute value
+** and then adding 1e-15 if f == 0.0. Next calculate the lowest power
+** of e that is >= f (i.e. exp(ceil(log(f)))). Divide f by this number to
+** get a number in the range exp(-1) to 1. Multiply this by 2^31-1 to
+** get a number, g, in the range 790015083 to 2147483647.
+** To include the magnitude of f in the computation, add ceil(log(f)) to g
+** and then truncate the result to an integer. Return the absolute value
+** of this integer to guarantee that the result is non-negative.
+**
+** Note: this is a function rather than a macro to ensure that exactly the
+** same code is executed each time it is called. If a macro were used, it
+** may get optimised differently in different places causing different
+** results to be computed.
+*/
+
+Integer
+hash_float(Float f)
+{
+ Float g, h;
+ Integer i;
+ if (f <= 0.0) f = -f;
+ if (f == 0.0) f = 1e-15;
+ h = ceil(log(f));
+ g = f / exp(h) * 2147483647.0; /* 2147483647 = 2^31 - 1 */
+ i = (Integer)(h + g);
+ return (i >= 0 ? i : -i);
}
More information about the developers
mailing list