123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144(************************************************************************)(* * The Coq Proof Assistant / The Coq Development Team *)(* v * Copyright INRIA, CNRS and contributors *)(* <O___,, * (see version control and CREDITS file for authors & dates) *)(* \VV/ **************************************************************)(* // * This file is distributed under the terms of the *)(* * GNU Lesser General Public License Version 2.1 *)(* * (see LICENSE file for the text of the license) *)(************************************************************************)(* OCaml's float type follows the IEEE 754 Binary64 (double precision)
format *)typet=float(* The [f : float] type annotation enable the compiler to compile f <> f
as comparison on floats rather than the polymorphic OCaml comparison
which is much slower. *)letis_nan(f:float)=f<>fletis_infinityf=f=infinityletis_neg_infinityf=f=neg_infinity(* OCaml gives a sign to nan values which should not be displayed as
all NaNs are considered equal here.
OCaml prints infinities as "inf" (resp. "-inf")
but we want "infinity" (resp. "neg_infinity"). *)letto_string_rawfmtf=ifis_nanfthen"nan"elseifis_infinityfthen"infinity"elseifis_neg_infinityfthen"neg_infinity"elsePrintf.sprintffmtfletto_hex_string=to_string_raw"%h"(* Printing a binary64 float in 17 decimal places and parsing it again
will yield the same float. *)letto_string=to_string_raw"%.17g"letof_string=float_of_string(* Compiles a float to OCaml code *)letcompilef=Printf.sprintf"Float64.of_float (%s)"(to_hex_stringf)letof_floatf=fletto_floatf=ifis_nanfthennanelsefletsignf=copysign1.f<0.letopp=(~-.)letabs=abs_floattypefloat_comparison=FEq|FLt|FGt|FNotComparable(* See above comment on [is_nan] for the [float] type annotations. *)leteq(x:float)(y:float)=x=y[@@ocaml.inlinealways]letlt(x:float)(y:float)=x<y[@@ocaml.inlinealways]letle(x:float)(y:float)=x<=y[@@ocaml.inlinealways](* inspired by lib/util.ml; see also #10471 *)letpervasives_compare(x:float)(y:float)=comparexyletcompare(x:float)(y:float)=ifx<ythenFLtelse(ifx>ythenFGtelse(ifx=ythenFEqelseFNotComparable(* NaN case *)))[@@ocaml.inlinealways]typefloat_class=|PNormal|NNormal|PSubn|NSubn|PZero|NZero|PInf|NInf|NaNletclassifyx=matchclassify_floatxwith|FP_normal->if0.<xthenPNormalelseNNormal|FP_subnormal->if0.<xthenPSubnelseNSubn|FP_zero->if0.<1./.xthenPZeroelseNZero|FP_infinite->if0.<xthenPInfelseNInf|FP_nan->NaN[@@ocaml.inlinealways]letof_uint63x=Uint63.to_floatx[@@ocaml.inlinealways]letprec=53letnormfr_mantissaf=letf=absfiniff>=0.5&&f<1.thenUint63.of_float(ldexpfprec)elseUint63.zero[@@ocaml.inlinealways]leteshift=2101(* 2*emax + prec *)(* When calling frexp on a nan or an infinity, the returned value inside
the exponent is undefined.
Therefore we must always set it to a fixed value (here 0). *)letfrshiftexpf=matchclassify_floatfwith|FP_zero|FP_infinite|FP_nan->(f,Uint63.zero)|FP_normal|FP_subnormal->let(m,e)=frexpfinm,Uint63.of_int(e+eshift)[@@ocaml.inlinealways]letldshiftexpfe=ldexpf(Uint63.to_int_mine(2*eshift)-eshift)[@@ocaml.inlinealways]externalnext_up:float->float="coq_next_up_byte""coq_next_up"[@@unboxed][@@noalloc]externalnext_down:float->float="coq_next_down_byte""coq_next_down"[@@unboxed][@@noalloc]letequalf1f2=iff1=f2thenf1<>0.||signf1=signf2(* OCaml consider 0. = -0. *)elseis_nanf1&&is_nanf2[@@ocaml.inlinealways]lethash=(* Hashtbl.hash already considers all NaNs as equal,
cf. https://github.com/ocaml/ocaml/commit/aea227fdebe0b5361fd3e1d0aaa42cf929052269
and http://caml.inria.fr/pub/docs/manual-ocaml/libref/Hashtbl.html *)Hashtbl.hashlettotal_comparef1f2=(* pervasives_compare considers all NaNs as equal, which is fine here,
but also considers -0. and +0. as equal *)iff1=0.&&f2=0.thenpervasives_compare(1./.f1)(1./.f2)elsepervasives_comparef1f2letis_float64t=Obj.tagt=Obj.double_tag[@@ocaml.inlinealways]