mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-18 10:53:40 +00:00
81 lines
3.0 KiB
Plaintext
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).
|
|
|
|
%-----------------------------------------------------------------------------%
|