[m-rev.] for review: implement float library for Java
James Goddard
goddardjames at yahoo.com
Thu Dec 11 15:10:01 AEDT 2003
Estimated hours taken: 4
Branches: main
Implement some library functions for the Java back-end.
library/float.m:
Implement the following predicates for Java:
domain_checks/0
float__ceiling_to_int/2
float__floor_to_int/2
float__round_to_int/2
float__truncate_to_int/2
float__hash/2 <-- also C# now checks for negatives
is_nan/1
is_inf/1
The following constants are now hard-coded in mercury for both Java and
.NET, which is ok since both language specifications conform to the
IEEE standard for double precision 64 bit floats:
float__max/1 <-- Java API actually provided this one
float__min/1
float__epsilon/1
float__radix/1
float__mantissa_digits/1
float__min_exponent/1
float__max_exponent/1
Index: float.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/float.m,v
retrieving revision 1.57
diff -u -d -r1.57 float.m
--- float.m 7 Nov 2003 16:51:35 -0000 1.57
+++ float.m 11 Dec 2003 02:35:09 -0000
@@ -268,10 +268,20 @@
#endif
").
+:- pragma foreign_proc("Java",
+ domain_checks,
+ [thread_safe, promise_pure],
+"
+ succeeded = true;
+").
+
%---------------------------------------------------------------------------%
%
% Conversion functions
%
+% For Java, overflows are not detected, so this must be tested for
+% explicitly. So every time there's a cast to int, the bounds are
+% checked first.
float(Int) = Float :-
int__to_float(Int, Float).
@@ -290,6 +300,19 @@
"
Ceil = System.Convert.ToInt32(System.Math.Ceiling(X));
").
+:- pragma foreign_proc("Java",
+ float__ceiling_to_int(X :: in) = (Ceil :: out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ if( X > (double)java.lang.Integer.MAX_VALUE ||
+ X <= (double)java.lang.Integer.MIN_VALUE - 1 ){
+ throw( new RuntimeException(
+ ""Overflow converting floating point to int"")
+ );
+ } else {
+ Ceil = (int)java.lang.Math.ceil(X);
+ }
+").
% float__floor_to_int(X) returns the
% largest integer not greater than X.
@@ -305,6 +328,19 @@
"
Floor = System.Convert.ToInt32(System.Math.Floor(X));
").
+:- pragma foreign_proc("Java",
+ float__floor_to_int(X :: in) = (Floor :: out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ if( X >= (double)java.lang.Integer.MAX_VALUE + 1 ||
+ X < (double)java.lang.Integer.MIN_VALUE ) {
+ throw( new RuntimeException(
+ ""Overflow converting floating point to int"")
+ );
+ } else {
+ Floor = (int)java.lang.Math.floor(X);
+ }
+").
% float__round_to_int(X) returns the integer closest to X.
% If X has a fractional value of 0.5, it is rounded up.
@@ -320,6 +356,19 @@
"
Round = System.Convert.ToInt32(System.Math.Floor(X + 0.5));
").
+:- pragma foreign_proc("Java",
+ float__round_to_int(X :: in) = (Round :: out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ if( X >= (double)java.lang.Integer.MAX_VALUE + 0.5 ||
+ X < (double)java.lang.Integer.MIN_VALUE - 0.5 ) {
+ throw( new RuntimeException(
+ ""Overflow converting floating point to int"")
+ );
+ } else {
+ Round = (int)java.lang.Math.round(X);
+ }
+").
% float__truncate_to_int(X) returns the integer closest
% to X such that |float__truncate_to_int(X)| =< |X|.
@@ -335,6 +384,19 @@
"
Trunc = System.Convert.ToInt32(X);
").
+:- pragma foreign_proc("Java",
+ float__truncate_to_int(X :: in) = (Trunc :: out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ if( X >= (double)java.lang.Integer.MAX_VALUE + 1 ||
+ X <= (double)java.lang.Integer.MIN_VALUE - 1 ) {
+ throw( new RuntimeException(
+ ""Overflow converting floating point to int"")
+ );
+ } else {
+ Trunc = (int)X;
+ }
+").
%---------------------------------------------------------------------------%
%
@@ -420,6 +482,9 @@
%---------------------------------------------------------------------------%
+ % In hashing a float in .NET or Java, we ensure that the value is
+ % non-negative, as this condition is not guaranteed by either API.
+
:- pragma foreign_proc("C",
float__hash(F::in) = (H::out),
[will_not_call_mercury, promise_pure, thread_safe],
@@ -430,7 +495,23 @@
float__hash(F::in) = (H::out),
[will_not_call_mercury, promise_pure, thread_safe],
"
- H = F.GetHashCode();
+ int Code = F.GetHashCode();
+ if( Code < 0 ) {
+ H = Code ^ 1;
+ } else {
+ H = Code;
+ }
+").
+:- pragma foreign_proc("Java",
+ float__hash(F::in) = (H::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ int Code = (new java.lang.Double(F)).hashCode();
+ if( Code < 0 ) {
+ H = Code ^ 1;
+ } else {
+ H = Code;
+ }
").
%---------------------------------------------------------------------------%
@@ -455,6 +536,12 @@
call bool [mscorlib]System.Double::IsNaN(float64)
stloc 'succeeded'
").
+:- pragma foreign_proc("Java",
+ is_nan(Flt::in),
+ [will_not_call_mercury, thread_safe, max_stack_size(1)],
+"
+ succeeded = java.lang.Double.isNaN(Flt);
+").
:- pragma promise_pure(is_inf/1).
:- pragma foreign_proc(c,
@@ -471,6 +558,12 @@
call bool [mscorlib]System.Double::IsInfinity(float64)
stloc 'succeeded'
").
+:- pragma foreign_proc("Java",
+ is_inf(Flt::in),
+ [will_not_call_mercury, thread_safe, max_stack_size(1)],
+"
+ succeeded = java.lang.Double.isInfinite(Flt);
+").
%---------------------------------------------------------------------------%
%
@@ -479,12 +572,12 @@
% For C, the floating-point system constants are derived from <float.h> and
% implemented using the C interface.
%
-% For .NET, the values are mostly hard-coded.
+% For .NET (and java), the values are mostly hard-coded.
% It's OK to do this, because the ECMA specification for the .NET CLR
% nails down the representation of System.Double as 64-bit IEEE float.
+% The Java Language Specification also follows the IEEE standard.
%
-% XXX For Java, we should do the same as for .NET.
-% In fact, maybe we should code these values in Mercury clauses,
+% Many of these values are coded in Mercury clauses,
% rather than foreign_proc pragmas; assuming IEEE floating point
% is a reasonable default these days, and doing that might improve
% the compiler's optimization.
@@ -525,6 +618,12 @@
"
Max = System.Double.MaxValue;
").
+:- pragma foreign_proc("Java",
+ float__max = (Max::out),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+ Max = java.lang.Double.MAX_VALUE;
+").
% Minimum normalised floating-point number */
:- pragma foreign_proc("C",
@@ -533,18 +632,20 @@
"
Min = ML_FLOAT_MIN;
").
-:- pragma foreign_proc("C#",
- float__min = (Min::out),
- [will_not_call_mercury, promise_pure, thread_safe],
-"
- // We can't use System.Double.MinValue, because in v1 of the .NET CLR,
- // that means something completely different: the negative number
- // with the greatest absolute value.
- // Instead, we just hard-code the appropriate value (copied from the
- // glibc header files); this is OK, because the ECMA specification
- // nails down the representation of double as 64-bit IEEE.
- Min = 2.2250738585072014e-308;
-").
+% C#:
+% We can't use System.Double.MinValue, because in v1 of the .NET CLR
+% that means something completely different: the negative number
+% with the greatest absolute value.
+% Instead, we just hard-code the appropriate value (copied from the
+% glibc header files); this is OK, because the ECMA specification
+% nails down the representation of double as 64-bit IEEE.
+%
+% Java:
+% The Java API's java.lang.Double.MIN_VALUE is not normalized,
+% so can't be used, so we use the same constant as for .NET, as the
+% Java Language Specification also describes Java doubles as 64 bit IEEE.
+%
+float__min = 2.2250738585072014e-308.
% Smallest x such that x \= 1.0 + x
:- pragma foreign_proc("C",
@@ -553,20 +654,21 @@
"
Eps = ML_FLOAT_EPSILON;
").
-:- pragma foreign_proc("C#",
- float__epsilon = (Eps::out),
- [will_not_call_mercury, promise_pure, thread_safe],
-"
- // We can't use System.Double.Epsilon, because in v1 of the .NET CLR,
- // that means something completely different: the smallest (denormal)
- // positive number. I don't know what the people who designed that
- // were smoking; that semantics for 'epsilon' is different from the
- // use of 'epsilon' in C, Lisp, Ada, etc., not to mention Mercury.
- // Instead, we just hard-code the appropriate value (copied from the
- // glibc header files); this is OK, because the ECMA specification
- // nails down the representation of double as 64-bit IEEE.
- Eps = 2.2204460492503131e-16;
-").
+% C#:
+% We can't use System.Double.Epsilon, because in v1 of the .NET CLR,
+% that means something completely different: the smallest (denormal)
+% positive number. I don't know what the people who designed that
+% were smoking; that semantics for 'epsilon' is different from the
+% use of 'epsilon' in C, Lisp, Ada, etc., not to mention Mercury.
+% Instead, we just hard-code the appropriate value (copied from the
+% glibc header files); this is OK, because the ECMA specification
+% nails down the representation of double as 64-bit IEEE.
+%
+% Java:
+% The Java API doesn't provide an epsilon constant, so we use the
+% same constant, which is ok since Java defines doubles as 64 bit IEEE.
+%
+float__epsilon = 2.2204460492503131e-16.
% Radix of the floating-point representation.
:- pragma foreign_proc("C",
@@ -575,15 +677,17 @@
"
Radix = ML_FLOAT_RADIX;
").
-:- pragma foreign_proc("C#",
- float__radix = (Radix::out),
- [will_not_call_mercury, promise_pure, thread_safe],
-"
- // The ECMA specification requires that double be 64-bit IEEE.
- // I think that implies that it must have Radix = 2.
- // This is definitely right for x86, anyway.
- Radix = 2;
-").
+% C#:
+% The ECMA specification requires that double be 64-bit IEEE.
+% I think that implies that it must have Radix = 2.
+% This is definitely right for x86, anyway.
+%
+% Java:
+% The Java API doesn't provide this constant either, so we default to the
+% same constant as .NET, which is ok since Java defines doubles as 64 bit
+% IEEE.
+%
+float__radix = 2.
% The number of base-radix digits in the mantissa.
:- pragma foreign_proc("C",
@@ -592,13 +696,15 @@
"
MantDig = ML_FLOAT_MANT_DIG;
").
-:- pragma foreign_proc("C#",
- float__mantissa_digits = (MantDig::out),
- [will_not_call_mercury, promise_pure, thread_safe],
-"
- // ECMA specifies that System.Double is 64-bit IEEE float
- MantDig = 53;
-").
+% C#:
+% ECMA specifies that System.Double is 64-bit IEEE float
+%
+% Java:
+% The Java API doesn't provide this constant either, so we default to the
+% same constant as .NET, which is ok since Java defines doubles as 64 bit
+% IEEE.
+%
+float__mantissa_digits = 53.
% Minimum negative integer such that:
% radix ** (min_exponent - 1)
@@ -609,13 +715,15 @@
"
MinExp = ML_FLOAT_MIN_EXP;
").
-:- pragma foreign_proc("C#",
- float__min_exponent = (MinExp::out),
- [will_not_call_mercury, promise_pure, thread_safe],
-"
- // ECMA specifies that System.Double is 64-bit IEEE float
- MinExp = -1021;
-").
+% C#:
+% ECMA specifies that System.Double is 64-bit IEEE float
+%
+% Java:
+% The Java API doesn't provide this constant either, so we default to the
+% same constant as .NET, which is ok since Java defines doubles as 64 bit
+% IEEE.
+%
+float__min_exponent = -1021.
% Maximum integer such that:
% radix ** (max_exponent - 1)
@@ -626,13 +734,15 @@
"
MaxExp = ML_FLOAT_MAX_EXP;
").
-:- pragma foreign_proc("C#",
- float__max_exponent = (MaxExp::out),
- [will_not_call_mercury, promise_pure, thread_safe],
-"
- // ECMA specifies that System.Double is 64-bit IEEE float
- MaxExp = 1024;
-").
+% C#:
+% ECMA specifies that System.Double is 64-bit IEEE float
+%
+% Java:
+% The Java API doesn't provide this constant either, so we default to the
+% same constant as .NET, which is ok since Java defines doubles as 64 bit
+% IEEE.
+%
+float__max_exponent = 1024.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
--------------------------------------------------------------------------
mercury-reviews mailing list
post: mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------
More information about the reviews
mailing list