The following module will do the job.
(*
This module defines the range of integers that can be represented
interchangeably with the float or with int type.
Note that this range depends on size of the int type, which depends
on the compilation target.
*)
(*
OCaml ints have 31 bits or 63 bits.
OCaml floats are double-precision floats (IEEE-754 binary64).
*)
let int_range_min_float = max (-.2.**53.) (float min_int)
let int_range_max_float = min (2.**53.) (float max_int)
let exact_int_of_float x =
if x >= int_range_min_float && x <= int_range_max_float then
truncate x
else
invalid_arg "exact_int_of_float: out of range"
let int_range_min_int = exact_int_of_float int_range_min_float
let int_range_max_int = exact_int_of_float int_range_max_float
let exact_float_of_int x =
if x >= int_range_min_int && x <= int_range_max_int then
float x
else
invalid_arg "exact_float_of_int: out of range"
let test () =
let imin, imax = int_range_min_int, int_range_max_int in
let fmin, fmax = int_range_min_float, int_range_max_float in
assert (exact_int_of_float 1. = 1);
assert (exact_int_of_float (-1.) = -1);
assert (fmin < 0.);
assert (fmax > 0.);
assert (imin < 0);
assert (imax > 0);
assert (float (truncate fmin) = fmin);
assert (float (truncate fmax) = fmax);
assert (truncate (float imin) = imin);
assert (truncate (float imax) = imax);
assert (float (imin + 1) = float imin +. 1.);
assert (float (imin + 2) = float imin +. 2.);
assert (float (imax - 1) = float imax -. 1.);
assert (float (imax - 2) = float imax -. 2.)
result is unspecified if the argument is nan or falls outside the range of representable integers
, it actually means anything can happen, so nothing is surprising. It is precisely left unspecified because they do not want to commit to any particular behavior (which might prevent optimizations and changes in future versions). – anol