[m-rev.] for review: add float.infinity/0
Julien Fischer
jfischer at opturion.com
Wed Sep 17 21:58:36 AEST 2014
Add float.infinity/0 to the standard library.
Add a constant function to the float module that returns positive infinity.
This is implemented for the C, Java, and C# backends.
The Erlang backend currently does not support it.
library/float.m:
Add the new function.
Address review comments from Paul about my previous commit.
tests/hard_coded/Mmakefile:
tests/hard_coded/test_infinity.{m,exp}:
Test various operations involving infinity.
NEWS:
Announce the addition.
Julien.
diff --git a/NEWS b/NEWS
index 9728c6c..561dda7 100644
--- a/NEWS
+++ b/NEWS
@@ -72,6 +72,10 @@ Changes to the Mercury standard library:
- is_infinite/1 (synonym for the existing is_inf/1 predicate)
- is_nan_or_infinite/1 (synonym for the existing is_nan_or_inf/1 predicate)
+ The following function has been added to the float module:
+
+ - infinity/0
+
Changes to the Mercury compiler:
* We have fixed a long-standing bug causing crashes in deep profiling
diff --git a/library/float.m b/library/float.m
index bb3fd2b..8f1766d 100644
--- a/library/float.m
+++ b/library/float.m
@@ -189,7 +189,7 @@
%
:- pred is_nan_or_infinite(float::in) is semidet.
- % Synonym for above.
+ % Synonym for the above.
%
:- pred is_nan_or_inf(float::in) is semidet.
@@ -219,9 +219,13 @@
%
:- func float.min = float.
+ % Positive infinity.
+ %
+:- func float.infinity = float.
+
% Smallest number x such that 1.0 + x \= 1.0.
- % This represents the largest relative spacing of two
- % consecutive floating point numbers.
+ % This represents the largest relative spacing of two consecutive floating
+ % point numbers.
%
% epsilon = radix ** (1 - mantissa_digits)
%
@@ -246,11 +250,13 @@
% Maximum integer such that:
% radix ** (max_exponent - 1)
- % is a normalised floating-point number. In the literature,
- % this is sometimes referred to as `e_max'.
+ % is a normalised floating-point number.
+ % In the literature, this is sometimes referred to as `e_max'.
%
:- func float.max_exponent = int.
+%---------------------------------------------------------------------------%
+
% Convert a float to a pretty_printer.doc for formatting.
%
:- func float.float_to_doc(float) = doc.
@@ -839,6 +845,55 @@ is_zero(0.0).
%
float.min = 2.2250738585072014e-308.
+
+% Java and C# provide constants for +infinity.
+% For C, the situation is more complicated.
+% For single precision floats, we use the following
+% (1) the C99 INFINITY macro if available
+% (2) the HUGE_VALF macro if available
+% (3) HUGE_VAL
+%
+% For double precision floats we just use the HUGE_VAL macro.
+% The C standard does not guarantee that this will be +infinity but it is on all
+% the systems that we support. It will definitely be +infinity if the optional
+% annex F of C99 is supported or if the 2001 revision of POSIX is supported.
+
+:- pragma foreign_proc("C",
+ float.infinity = (F::out),
+ [will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
+ does_not_affect_liveness],
+"
+ #if defined(MR_USE_SINGLE_PREC_FLOAT)
+ #if defined(INFINITY)
+ F = INFINITY;
+ #elif defined(HUGE_VALF)
+ F = HUGE_VALF;
+ #else
+ F = HUGE_VAL;
+ #endif
+ #else
+ F = HUGE_VAL;
+ #endif
+").
+
+:- pragma foreign_proc("Java",
+ float.infinity = (F::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ F = java.lang.Double.POSITIVE_INFINITY;
+").
+
+:- pragma foreign_proc("C#",
+ float.infinity = (F::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ F = System.Double.PositiveInfinity;
+").
+
+float.infinity = _ :-
+ private_builtin.sorry(
+ "infinity/0 not currently available for this backend").
+
:- pragma foreign_proc("C",
float.epsilon = (Eps::out),
[will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
diff --git a/tests/hard_coded/Mmakefile b/tests/hard_coded/Mmakefile
index 687fb47..ce1e137 100644
--- a/tests/hard_coded/Mmakefile
+++ b/tests/hard_coded/Mmakefile
@@ -310,6 +310,7 @@ ORDINARY_PROGS= \
test_cord \
test_cord2 \
test_imported_no_tag \
+ test_infinity \
test_keys_and_values \
test_pretty_printer \
test_pretty_printer_defaults \
diff --git a/tests/hard_coded/test_infinity.exp b/tests/hard_coded/test_infinity.exp
new file mode 100644
index 0000000..c2e6dfb
--- /dev/null
+++ b/tests/hard_coded/test_infinity.exp
@@ -0,0 +1,15 @@
+write_float(infinity) = infinity
+write_float(-infinity) = -infinity
+to infinity and beyond!
+format(-infinity) = -infinity
+is_infinite(infinity) = yes
+is_infinite(-infinity) = yes
+is_finite(infinity) = no
+is_finite(-infinity) = no
+is_nan(infinity) = no
+is_nan(-infinity) = no
+is_zero(infinity) = no
+is_zero(-infinity) = no
+abs(infinity) = infinity
+abs(-infinity) = infinity
+pow(infinity, 0) = 1.000000
diff --git a/tests/hard_coded/test_infinity.m b/tests/hard_coded/test_infinity.m
new file mode 100644
index 0000000..ec40585
--- /dev/null
+++ b/tests/hard_coded/test_infinity.m
@@ -0,0 +1,78 @@
+%------------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%------------------------------------------------------------------------------%
+% Test the constant function float.infinity/0.
+%------------------------------------------------------------------------------%
+
+:- module test_infinity.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+%------------------------------------------------------------------------------%
+%------------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module bool.
+:- import_module float.
+:- import_module list.
+:- import_module math.
+:- import_module string.
+
+%------------------------------------------------------------------------------%
+
+main(!IO) :-
+
+ % Test io.write_float with infinity.
+ %
+ io.write_string("write_float(infinity) = ", !IO),
+ io.write_float(infinity, !IO),
+ io.nl(!IO),
+ io.write_string("write_float(-infinity) = ", !IO),
+ io.write_float(-infinity, !IO),
+ io.nl(!IO),
+
+ % Test format with infinity.
+ %
+ io.format("to %f and beyond!\n", [f(infinity)], !IO),
+ io.format("format(-infinity) = %f\n", [f(-infinity)], !IO),
+
+ % Test float classification predicates with infinity.
+ %
+ io.format("is_infinite(infinity) = %s\n",
+ [s(string(pred_to_bool(is_infinite(infinity))))], !IO),
+ io.format("is_infinite(-infinity) = %s\n",
+ [s(string(pred_to_bool(is_infinite(-infinity))))], !IO),
+
+ io.format("is_finite(infinity) = %s\n",
+ [s(string(pred_to_bool(is_finite(infinity))))], !IO),
+ io.format("is_finite(-infinity) = %s\n",
+ [s(string(pred_to_bool(is_finite(-infinity))))], !IO),
+
+ io.format("is_nan(infinity) = %s\n",
+ [s(string(pred_to_bool(is_nan(infinity))))], !IO),
+ io.format("is_nan(-infinity) = %s\n",
+ [s(string(pred_to_bool(is_nan(-infinity))))], !IO),
+
+ io.format("is_zero(infinity) = %s\n",
+ [s(string(pred_to_bool(is_nan(infinity))))], !IO),
+ io.format("is_zero(-infinity) = %s\n",
+ [s(string(pred_to_bool(is_zero(-infinity))))], !IO),
+
+ % Test abs with infinities.
+ %
+ io.format("abs(infinity) = %f\n", [f(abs(infinity))], !IO),
+ io.format("abs(-infinity) = %f\n", [f(abs(-infinity))], !IO),
+
+ % Test for pow.
+ % XXX most other uses of infinity with pow currently cause a domain error
+ % -- this is at variance with what IEEE 754-2008 says should happen in many
+ % cases.
+ io.format("pow(infinity, 0) = %f\n", [f(pow(infinity, 0))], !IO).
+
+%------------------------------------------------------------------------------%
+:- end_module test_infinity.
+%------------------------------------------------------------------------------%
More information about the reviews
mailing list