[m-rev.] for post-commit review: add new float classification predicates

Julien Fischer jfischer at opturion.com
Wed Sep 17 14:41:42 AEST 2014


Add new float classification predicates.

Add the predicates is_finite/1 and is_zero/1 to the float module.
In C grades the implementation of the former maps down to the isfinite macro
(with C99).

configure.ac:
runtime/mercury_confg.h.in:
 	Check if the C99 macro isfinite is available.

runtime/mercury_float.h:
 	Add the macro MR_is_finite for testing if a floating point
 	number is finite.  If the C stdlib provides this operation
 	directly we use that, otherwise we define it in terms of
 	MR_is_infinite and MR_is_nan.

library/float.m:
 	Add the predicates is_finite/2 and is_zero/2.

 	Expand tabs in this file.

 	Fix capitalization in documentation.

library/int.m:
 	Fix inconsistent capitalization in a spot.

library/string.m:
 	Use is_finite/1 in place of negating is_nan_or_infinite/1.

diff --git a/NEWS b/NEWS
index f6bb871..9728c6c 100644
--- a/NEWS
+++ b/NEWS
@@ -65,6 +65,13 @@ Changes to the Mercury standard library:
  * Float special values, NaNs and Infinities, are now converted to strings in
    a way that is backend and grade-independent.  (Bug #348)

+* The following classification predicates have been added to the float module:
+
+   - is_finite/1
+   - is_zero/1
+   - 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)
+
  Changes to the Mercury compiler:

  * We have fixed a long-standing bug causing crashes in deep profiling
diff --git a/configure.ac b/configure.ac
index 3a4bccd..c8624c5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4929,6 +4929,7 @@ MERCURY_CHECK_FOR_IEEE_FUNC(isnanf)
  MERCURY_CHECK_FOR_IEEE_FUNC(isinf)
  MERCURY_CHECK_FOR_IEEE_FUNC(isinff)
  MERCURY_CHECK_FOR_IEEE_FUNC(finite)
+MERCURY_CHECK_FOR_IEEE_FUNC(isfinite)

  #-----------------------------------------------------------------------------#
  #
diff --git a/library/float.m b/library/float.m
index bc263e3..bb3fd2b 100644
--- a/library/float.m
+++ b/library/float.m
@@ -61,19 +61,19 @@
  % Arithmetic functions
  %

-	% addition
+    % Addition.
      %
  :- func (float::in) + (float::in) = (float::uo) is det.

-	% subtraction
+    % Subtraction.
      %
  :- func (float::in) - (float::in) = (float::uo) is det.

-	% multiplication
+    % Multiplication.
      %
  :- func (float::in) * (float::in) = (float::uo) is det.

-	% division
+    % Division.
      % Throws a `math.domain_error' exception if the right operand is zero.
      % See the comments at the top of math.m to find out how to disable
      % this check.
@@ -85,11 +85,11 @@
      %
  :- func unchecked_quotient(float::in, float::in) = (float::uo) is det.

-	% unary plus
+    % Unary plus.
      %
  :- func + (float::in) = (float::uo) is det.

-	% unary minus
+    % Unary minus.
      %
  :- func - (float::in) = (float::uo) is det.

@@ -97,12 +97,20 @@
  %
  % Comparison predicates
  %
-
-	% less than, greater than, less than or equal, greater than or equal.
+    % Less than.
      %
  :- pred (float::in) < (float::in) is semidet.
+
+    % Less than or equal.
+    %
  :- pred (float::in) =< (float::in) is semidet.
+
+    % Greater than or equal.
+    %
  :- pred (float::in) >= (float::in) is semidet.
+
+    % Greater than.
+    %
  :- pred (float::in) > (float::in) is semidet.

  %---------------------------------------------------------------------------%
@@ -110,7 +118,7 @@
  % Conversion functions
  %

-	% Convert int to float
+    % Convert int to float.
      %
  :- func float(int) = float.

@@ -127,8 +135,8 @@
      %
  :- func round_to_int(float) = int.

-	% truncate_to_int(X) returns
-	% the integer closest to X such that |truncate_to_int(X)| =< |X|.
+    % truncate_to_int(X) returns the integer closest to X such that
+    % |truncate_to_int(X)| =< |X|.
      %
  :- func truncate_to_int(float) = int.

@@ -137,15 +145,15 @@
  % Miscellaneous functions
  %

-	% absolute value
+    % Absolute value.
      %
  :- func abs(float) = float.

-	% maximum
+    % Maximum.
      %
  :- func max(float, float) = float.

-	% minimum
+    % Minimum.
      %
  :- func min(float, float) = float.

@@ -165,7 +173,7 @@
  % Classification
  %

-    % Is the floating point number of infinite magnitude?
+    % True iff the argument is of infinite magnitude.
      %
  :- pred is_infinite(float::in) is semidet.

@@ -173,36 +181,45 @@
      %
  :- pred is_inf(float::in) is semidet.

-    % Is the floating point number not a number?
+    % True iff the argument is not-a-number (NaN).
      %
  :- pred is_nan(float::in) is semidet.

-	% Is the floating point number not a number or of infinite magnitude?
+    % True iff the argument is of infinite magnitude or not-a-number (NaN).
      %
  :- pred is_nan_or_infinite(float::in) is semidet.

-    % Synonym for is_nan_or_inf/1.
+    % Synonym for above.
      %
  :- pred is_nan_or_inf(float::in) is semidet.

+    % True iff the argument is not of infinite magnitude and is not a
+    % not-a-number (NaN) value.
+    %
+:- pred is_finite(float::in) is semidet.
+
+    % True iff the argument is of zero magnitude.
+    %
+:- pred is_zero(float::in) is semidet.
+
  %----------------------------------------------------------------------------%
  %
  % System constants
  %

-	% Maximum finite floating-point number
+    % Maximum finite floating-point number.
      %
      % max = (1 - radix ** mantissa_digits) * radix ** max_exponent
      %
  :- func float.max = float.

-	% Minimum normalised positive floating-point number
+    % Minimum normalised positive floating-point number.
      %
      % min = radix ** (min_exponent - 1)
      %
  :- func float.min = float.

-	% Smallest number x such that 1.0 + x \= 1.0
+    % Smallest number x such that 1.0 + x \= 1.0.
      % This represents the largest relative spacing of two
      % consecutive floating point numbers.
      %
@@ -215,8 +232,8 @@
      %
  :- func float.radix = int.

-	% The number of base-radix digits in the mantissa.  In the
-	% literature, this is sometimes referred to as `p' or `t'.
+    % The number of base-radix digits in the mantissa.
+    % In the literature, this is sometimes referred to as `p' or `t'.
      %
  :- func float.mantissa_digits = int.

@@ -722,6 +739,20 @@ is_infinite(F) :-
      SUCCESS_INDICATOR = false
  ").

+:- pragma foreign_proc("C",
+    is_finite(Flt::in),
+    [will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
+        does_not_affect_liveness],
+"
+    SUCCESS_INDICATOR = MR_is_finite(Flt);
+").
+
+is_finite(F) :-
+    not is_infinite(F),
+    not is_nan(F).
+
+is_zero(0.0).
+
  %---------------------------------------------------------------------------%
  %
  % System constants
diff --git a/library/int.m b/library/int.m
index b174468..e090ca6 100644
--- a/library/int.m
+++ b/library/int.m
@@ -78,7 +78,7 @@
  :- func int.log2(int) = int.
  :- pred int.log2(int::in, int::out) is det.

-    % addition
+    % Addition.
      %
  :- func int + int = int.
  :- mode in  + in  = uo  is det.
diff --git a/library/string.m b/library/string.m
index 9693bf9..d5cba0f 100644
--- a/library/string.m
+++ b/library/string.m
@@ -3002,7 +3002,7 @@ specifier_to_string(spec_conv(Flags, Width, Prec, Spec)) = String :-
          % Valid float conversion specifiers.
          Spec = e(Float),
          (
-            not is_nan_or_infinite(Float),
+            is_finite(Float),
              using_sprintf
          ->
              FormatStr = make_format(Flags, Width, Prec, "", "e"),
@@ -3014,7 +3014,7 @@ specifier_to_string(spec_conv(Flags, Width, Prec, Spec)) = String :-
      ;
          Spec = cE(Float),
          (
-            not is_nan_or_infinite(Float),
+            is_finite(Float),
              using_sprintf
          ->
              FormatStr = make_format(Flags, Width, Prec, "", "E"),
@@ -3026,7 +3026,7 @@ specifier_to_string(spec_conv(Flags, Width, Prec, Spec)) = String :-
      ;
          Spec = f(Float),
          (
-            not is_nan_or_infinite(Float),
+            is_finite(Float),
              using_sprintf
          ->
              FormatStr = make_format(Flags, Width, Prec, "", "f"),
@@ -3038,7 +3038,7 @@ specifier_to_string(spec_conv(Flags, Width, Prec, Spec)) = String :-
      ;
          Spec = cF(Float),
          (
-            not is_nan_or_infinite(Float),
+            is_finite(Float),
              using_sprintf
          ->
              FormatStr = make_format(Flags, Width, Prec, "", "F"),
@@ -3050,7 +3050,7 @@ specifier_to_string(spec_conv(Flags, Width, Prec, Spec)) = String :-
      ;
          Spec = g(Float),
          (
-            not is_nan_or_infinite(Float),
+            is_finite(Float),
              using_sprintf
          ->
              FormatStr = make_format(Flags, Width, Prec, "", "g"),
@@ -3062,7 +3062,7 @@ specifier_to_string(spec_conv(Flags, Width, Prec, Spec)) = String :-
      ;
          Spec = cG(Float),
          (
-            not is_nan_or_infinite(Float),
+            is_finite(Float),
              using_sprintf
          ->
              FormatStr = make_format(Flags, Width, Prec, "", "G"),
diff --git a/runtime/mercury_conf.h.in b/runtime/mercury_conf.h.in
index 1911cd5..d70d1e5 100644
--- a/runtime/mercury_conf.h.in
+++ b/runtime/mercury_conf.h.in
@@ -298,6 +298,7 @@
  **	MR_HAVE_ISINF		we have the isinf() function.
  **	MR_HAVE_ISINFF		we have the isinff() function.
  **	MR_HAVE_FINITE		we have the finite() function.
+**	MR_HAVE_ISFINITE        we have the isfinite() function.
  **	MR_HAVE_FESETROUND	we have the fesetround() function.
  **	MR_HAVE_FMA		we have the fma() function.
  */
diff --git a/runtime/mercury_float.h b/runtime/mercury_float.h
index 4e4a6fa..91b91e6 100644
--- a/runtime/mercury_float.h
+++ b/runtime/mercury_float.h
@@ -234,6 +234,18 @@ MR_Integer MR_hash_float(MR_Float);
      #define MR_is_infinite(f) MR_is_infinite_func((f))
  #endif

+/*
+** XXX I don't know whether isfinite works on Solaris or not.
+** The finite function apparently does, so we use that instead.
+*/
+#if defined(MR_HAVE_ISFINITE) && !defined(MR_SOLARIS)
+    #define MR_is_finite(f) isfinite((f))
+#elif defined(MR_HAVE_FINITE)
+    #define MR_is_finite(f) finite((f))
+#else
+    #define MR_is_finite(f) (!MR_is_infinite((f)) && !MR_is_nan((f)))
+#endif
+
  MR_bool MR_is_nan_func(MR_Float);
  MR_bool MR_is_infinite_func(MR_Float);




More information about the reviews mailing list