[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