123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146externalformat_float:string->float->string="caml_format_float"(* Stolen from [pervasives.ml]. Adds a "." at the end if needed. It is in
[pervasives.mli], but it also says not to use it directly, so we copy and paste the
code. It makes the assumption on the string passed in argument that it was returned by
[format_float] *)letvalid_float_lexems=letl=String.lengthsinletrecloopi=ifi>=lthens^"."else(matchs.[i]with|'0'..'9'|'-'->loop(i+1)|_->s)inloop0;;open!ImportmoduleT=structincludeBase.Floattypet=float[@@derivingbin_io,typerep]endincludeTincludeHashable.Make_binable(T)includeComparable.Map_and_set_binable_using_comparator(T)includeComparable.Validate_with_zero(T)moduleReplace_polymorphic_compare:Comparisons.Swithtypet:=t=Tletvalidate_ordinaryt=Validate.of_error_opt(letmoduleC=Classinmatchclassifytwith|C.Normal|C.Subnormal|C.Zero->None|C.Infinite->Some"value is infinite"|C.Nan->Some"value is NaN");;moduleV=structmoduleZZ=Comparable.Validate(T)letvalidate_bound~min~maxt=Validate.first_failure(validate_ordinaryt)(ZZ.validate_boundt~min~max);;letvalidate_lbound~mint=Validate.first_failure(validate_ordinaryt)(ZZ.validate_lboundt~min);;letvalidate_ubound~maxt=Validate.first_failure(validate_ordinaryt)(ZZ.validate_uboundt~max);;endincludeVmoduleRobust_compare=structmoduletypeS=sig(* intended to be a tolerance on human-entered floats *)valrobust_comparison_tolerance:floatincludeRobustly_comparable.Swithtypet:=floatendmoduleMake(T:sigvalrobust_comparison_tolerance:floatend):S=struct(* We have test in the tree that rely on these functions not allocating, even without
X_LIBRARY_INLING. The only way to ensure that these don't create temporary boxed
floats without X_LIBRARY_INLING is for this code to see the float operations as
externals, as defined in [Pervasives]. That's why we use [Poly] and float
arithmetic from [Caml]. *)openPolyletrobust_comparison_tolerance=T.robust_comparison_tolerancelet(>=.)xy=x>=Caml.(-.)yrobust_comparison_tolerancelet(<=.)xy=y>=.xlet(=.)xy=x>=.y&&y>=.xlet(>.)xy=x>Caml.(+.)yrobust_comparison_tolerancelet(<.)xy=y>.xlet(<>.)xy=not(x=.y)letrobustly_comparexy=letd=Caml.(-.)xyinifd<Caml.(~-.)robust_comparison_tolerancethen-1elseifd>robust_comparison_tolerancethen1else0;;endendmoduleRobustly_comparable=Robust_compare.Make(structletrobust_comparison_tolerance=1E-7end)includeRobustly_comparablemoduleO=structincludeBase.Float.OincludeRobustly_comparableendmoduleTerse=structtypenonrect=t[@@derivingbin_io]include(Base.Float.Terse:moduletypeofstructincludeBase.Float.Terseendwithtypet:=t)endletrobust_signt:Sign.t=ift>.0.thenPoselseift<.0.thenNegelseZero(* There are two issues:
- Float.sign used to use robust comparison, and users of [Core] might have come to
depend on this.
- Robustness aside, what we get from Comparable.With_zero would map nan to Neg.
*)letsign=robust_sign(* Standard 12 significant digits, exponential notation used as necessary, guaranteed to
be a valid OCaml float lexem, not to look like an int. *)letto_string_12x=valid_float_lexem(format_float"%.12g"x)letquickcheck_generator=Base_quickcheck.Generator.floatletquickcheck_observer=Base_quickcheck.Observer.floatletquickcheck_shrinker=Base_quickcheck.Shrinker.floatletgen_uniform_excl=Base_quickcheck.Generator.float_uniform_exclusiveletgen_incl=Base_quickcheck.Generator.float_inclusiveletgen_without_nan=Base_quickcheck.Generator.float_without_nanletgen_finite=Base_quickcheck.Generator.float_finiteletgen_positive=Base_quickcheck.Generator.float_strictly_positiveletgen_negative=Base_quickcheck.Generator.float_strictly_negativeletgen_zero=Base_quickcheck.Generator.float_of_classZeroletgen_nan=Base_quickcheck.Generator.float_of_classNanletgen_subnormal=Base_quickcheck.Generator.float_of_classSubnormalletgen_normal=Base_quickcheck.Generator.float_of_classNormalletgen_infinite=Base_quickcheck.Generator.float_of_classInfinite