Files
mercury/library/float.nu.nl
Fergus Henderson 04b720630b Update the copyright messages so that (a) they contain the correct years
and (b) they say "Copyright (C) ... _The_ University of Melbourne".
1997-07-27 15:09:59 +00:00

81 lines
3.0 KiB
Plaintext

%-----------------------------------------------------------------------------%
% Copyright (C) 1994-1997 The University of Melbourne.
% This file may only be copied under the terms of the GNU Library General
% Public License - see the file COPYING.LIB in the Mercury distribution.
%-----------------------------------------------------------------------------%
%
% File: float.nu.nl.
% Main author: fjh.
%
% This file provides a Prolog implementation of `float__min', `float__max',
% and `float__epsilon'.
%
%-----------------------------------------------------------------------------%
% XXX These definitions are highly platform-dependent.
% Currently we just hard-wire the definitions for IEEE double precision.
% This code is written very carefully to avoid bugs and incompatibilities
% in NU-Prolog and SICStus Prolog:
%
% We mustn't write `X = 1.7976931348623157E308', because NU-Prolog
% has a bug which means that it fails to compile that.
%
% We mustn't write `X is 1.7976931348623157 * 10 ** 308', as NU-Prolog
% wants, because SICStus reports a syntax error.
%
% We mustn't write `X is 1.7976931348623157 * exp(10, 308)', as SICStus
% Prolog wants, because NU-Prolog has a different bug which means that
% it fails to compile that too.
%
% Writing this code was like walking a mine-field... if you change it,
% be sure to test it on both NU-Prolog and SICStus.
float__max(X) :-
% 1.7976931348623157E+308
( nuprolog ->
X is 1.79769313486231 * '**'(10, 308)
;
Exp = exp(10, 308),
X is 1.79769313486231 * Exp
).
% really float__min(2.2250738585072014e-308).
% but if we put in the last two digits, then
% NU-Prolog (1.6.12) will underflow to zero.
% (This happens with compiled code (nc), but not
% with consulted code (np).)
float__min(2.22507385850721e-308).
float__epsilon(2.2204460492503131e-16).
% Note: This hash function is different to the one defined in
% float.m.
% How it works: first ensure Float is positive by taking the
% absolute value (Abs) and then adding epsilon if Abs == 0.0
% (Abs2). Next calculate the lowest power of e that is >=
% Abs2 (i.e. exp(ceil(log(Abs2)))). Divide Abs2 by this
% number to get a number in the range exp(-1) to 1. Multiply
% this by 2^31-1 to get a number, Float2, in the range
% 790015083 to 2147483647. To include the magnitude of Float
% in the computation, add ceil(log(Abs2)) to Float2 and then
% truncate the result to an integer (N2). Truncate Float2 to
% integer (N1), XOR with N2 and take the absolute value to
% ensure the result in non-negative.
float__hash(Float, Hash) :-
( Float >= 0 -> Abs = Float ; Abs is -Float),
( Abs = 0.0 -> float__epsilon(Abs2) ; Abs2 = Abs ),
Log is log(Abs2),
R0 is round(Log),
( R0 < Log -> R is R + 1 ; R is R0),
Exp is exp(R),
Float2 is Abs2 / Exp * 2147483647.0, % 2147483647 = (2^31)-1
N1 is integer(Float2),
( R >= 0 -> R1 = R ; R1 is -R),
N2 is integer(R1),
Hash0 is N1 ^ N2,
int__abs(Hash0, Hash).
%-----------------------------------------------------------------------------%