[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