123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232open!Import(* Open replace_polymorphic_compare after including functor instantiations so they do not
shadow its definitions. This is here so that efficient versions of the comparison
functions are available within this module. *)open!Float_replace_polymorphic_compareletceil=Stdlib.ceilletfloor=Stdlib.floorletmod_float=Stdlib.mod_floatletmodf=Stdlib.modfletfloat_of_string=Stdlib.float_of_stringletfloat_of_string_opt=Stdlib.float_of_string_optletnan=Stdlib.nanletinfinity=Stdlib.infinityletneg_infinity=Stdlib.neg_infinityletmax_finite_value=Stdlib.max_floatletepsilon_float=Stdlib.epsilon_floatletclassify_float=Stdlib.classify_floatletabs_float=Stdlib.abs_floatletis_integer=Stdlib.Float.is_integerlet(**)=Stdlib.(**)let(%.)ab=(* Raise in case of a negative modulus, as does Int.( % ). *)ifb<0.thenPrintf.invalid_argf"%f %% %f in float0.ml: modulus should be positive"ab();letm=Stdlib.mod_floatabin(* Produce a non-negative result in analogy with Int.( % ). *)ifm<0.thenm+.belsem;;(* The bits of INRIA's [Stdlib] that we just want to expose in [Float]. Most are
already deprecated in [Stdlib], and eventually all of them should be. *)include(structincludeStdlibincludeStdlib.Floatend:sigexternalfrexp:float->float*int="caml_frexp_float"externalldexp:(float[@unboxed])->(int[@untagged])->(float[@unboxed])="caml_ldexp_float""caml_ldexp_float_unboxed"[@@noalloc]externallog10:float->float="caml_log10_float""log10"[@@unboxed][@@noalloc]externallog2:float->float="caml_log2_float""caml_log2"[@@unboxed][@@noalloc]externalexpm1:float->float="caml_expm1_float""caml_expm1"[@@unboxed][@@noalloc]externallog1p:float->float="caml_log1p_float""caml_log1p"[@@unboxed][@@noalloc]externalcopysign:float->float->float="caml_copysign_float""caml_copysign"[@@unboxed][@@noalloc]externalcos:float->float="caml_cos_float""cos"[@@unboxed][@@noalloc]externalsin:float->float="caml_sin_float""sin"[@@unboxed][@@noalloc]externaltan:float->float="caml_tan_float""tan"[@@unboxed][@@noalloc]externalacos:float->float="caml_acos_float""acos"[@@unboxed][@@noalloc]externalasin:float->float="caml_asin_float""asin"[@@unboxed][@@noalloc]externalatan:float->float="caml_atan_float""atan"[@@unboxed][@@noalloc]externalacosh:float->float="caml_acosh_float""caml_acosh"[@@unboxed][@@noalloc]externalasinh:float->float="caml_asinh_float""caml_asinh"[@@unboxed][@@noalloc]externalatanh:float->float="caml_atanh_float""caml_atanh"[@@unboxed][@@noalloc]externalatan2:float->float->float="caml_atan2_float""atan2"[@@unboxed][@@noalloc]externalhypot:float->float->float="caml_hypot_float""caml_hypot"[@@unboxed][@@noalloc]externalcosh:float->float="caml_cosh_float""cosh"[@@unboxed][@@noalloc]externalsinh:float->float="caml_sinh_float""sinh"[@@unboxed][@@noalloc]externaltanh:float->float="caml_tanh_float""tanh"[@@unboxed][@@noalloc]externalsqrt:float->float="caml_sqrt_float""sqrt"[@@unboxed][@@noalloc]externalexp:float->float="caml_exp_float""exp"[@@unboxed][@@noalloc]externallog:float->float="caml_log_float""log"[@@unboxed][@@noalloc]end)(* We need this indirection because these are exposed as "val" instead of "external" *)letfrexp=frexpletldexp=ldexpletis_nanx=(x:float)<>x(* An order-preserving bijection between all floats except for NaNs, and 99.95% of
int64s.
Note we don't distinguish 0. and -0. as separate values here, they both map to 0L, which
maps back to 0.
This should work both on little-endian and high-endian CPUs. Wikipedia says: "on
modern standard computers (i.e., implementing IEEE 754), one may in practice safely
assume that the endianness is the same for floating point numbers as for integers"
(http://en.wikipedia.org/wiki/Endianness#Floating-point_and_endianness).
*)letto_int64_preserve_ordert=ifis_nantthenNoneelseift=0.then(* also includes -0. *)Some0Lelseift>0.thenSome(Stdlib.Int64.bits_of_floatt)elseSome(Stdlib.Int64.neg(Stdlib.Int64.bits_of_float(-.t)));;letto_int64_preserve_order_exnx=Option.value_exn(to_int64_preserve_orderx)letof_int64_preserve_orderx=ifInt64_replace_polymorphic_compare.(>=)x0LthenStdlib.Int64.float_of_bitsxelse~-.(Stdlib.Int64.float_of_bits(Stdlib.Int64.negx));;letone_ulpdirt=matchto_int64_preserve_ordertwith|None->Stdlib.nan|Somex->of_int64_preserve_order(Stdlib.Int64.addx(matchdirwith|`Up->1L|`Down->-1L));;(* [upper_bound_for_int] and [lower_bound_for_int] are for calculating the max/min float
that fits in a given-size integer when rounded towards 0 (using [int_of_float]).
max_int/min_int depend on [num_bits], e.g. +/- 2^30, +/- 2^62 if 31-bit, 63-bit
(respectively) while float is IEEE standard for double (52 significant bits).
In all cases, we want to guarantee that
[lower_bound_for_int <= x <= upper_bound_for_int]
iff [int_of_float x] fits in an int with [num_bits] bits.
[2 ** (num_bits - 1)] is the first float greater that max_int, we use the preceding
float as upper bound.
[- (2 ** (num_bits - 1))] is equal to min_int.
For lower bound we look for the smallest float [f] satisfying [f > min_int - 1] so that
[f] rounds toward zero to [min_int]
So in particular we will have:
[lower_bound_for_int x <= - (2 ** (1-x))]
[upper_bound_for_int x < 2 ** (1-x) ]
*)letupper_bound_for_intnum_bits=letexp=Stdlib.float_of_int(num_bits-1)inone_ulp`Down(2.**exp);;letis_x_minus_one_exactx=(* [x = x -. 1.] does not work with x87 floating point arithmetic backend (which is used
on 32-bit ocaml) because of 80-bit register precision of intermediate computations.
An alternative way of computing this: [x -. one_ulp `Down x <= 1.] is also prone to
the same precision issues: you need to make sure [x] is 64-bit.
*)letopenInt64_replace_polymorphic_compareinnot(Stdlib.Int64.bits_of_floatx=Stdlib.Int64.bits_of_float(x-.1.));;letlower_bound_for_intnum_bits=letexp=Stdlib.float_of_int(num_bits-1)inletmin_int_as_float=~-.(2.**exp)inletopenInt_replace_polymorphic_compareinifnum_bits-1<53(* 53 = #bits in the float's mantissa with sign included *)then((* The smallest float that rounds towards zero to [min_int] is
[min_int - 1 + epsilon] *)assert(is_x_minus_one_exactmin_int_as_float);one_ulp`Up(min_int_as_float-.1.))else((* [min_int_as_float] is already the smallest float [f] satisfying [f > min_int - 1]. *)assert(not(is_x_minus_one_exactmin_int_as_float));min_int_as_float);;(* X86 docs say:
If only one value is a NaN (SNaN or QNaN) for this instruction, the second source
operand, either a NaN or a valid floating-point value
is written to the result.
So we have to be VERY careful how we use these!
These intrinsics were copied from [Ocaml_intrinsics] to avoid build deps we don't want
*)moduleIntrinsics_with_weird_nan_behavior=structlet[@inlinealways]minab=Ocaml_intrinsics_kernel.Float.minablet[@inlinealways]maxab=Ocaml_intrinsics_kernel.Float.maxabendletclamp_unchecked~(to_clamp_maybe_nan:float)~min_which_is_not_nan~max_which_is_not_nan=(* We want to propagate nans; as per the x86 docs, this means we have to use them as the
_second_ argument. *)lett_maybe_nan=Intrinsics_with_weird_nan_behavior.maxmin_which_is_not_nanto_clamp_maybe_naninIntrinsics_with_weird_nan_behavior.minmax_which_is_not_nant_maybe_nan;;letbox=(* Prevent potential constant folding of [+. 0.] in the near ocamlopt future. *)letx=Sys0.opaque_identity0.infunf->f+.x;;(* Include type-specific [Replace_polymorphic_compare] at the end, after
including functor application that could shadow its definitions. This is
here so that efficient versions of the comparison functions are exported by
this module. *)includeFloat_replace_polymorphic_compare