123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219(**************************************************************************)(* This file is part of the Codex semantics library. *)(* *)(* Copyright (C) 2013-2025 *)(* CEA (Commissariat à l'énergie atomique et aux énergies *)(* alternatives) *)(* *)(* you can redistribute it and/or modify it under the terms of the GNU *)(* Lesser General Public License as published by the Free Software *)(* Foundation, version 2.1. *)(* *)(* It is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)(* GNU Lesser General Public License for more details. *)(* *)(* See the GNU Lesser General Public License version 2.1 *)(* for more details (enclosed in the file LICENSE). *)(* *)(**************************************************************************)[@@@ocaml.warning"-32"](* Those OCaml functions do not have the proper semantics w.r.t -0/+0. We
make them inoperative for this entire file. *)letmin=()letmax=()letcompare=()[@@@ocaml.warning"+32"]typekind=Float_sig.prec=Single|Double|Long_Double|Real(* let kind = function
* | Cil_types.FFloat -> Single
* | Cil_types.FDouble -> Double
* | Cil_types.FLongDouble -> Long_Double *)letpretty_kindfmtkind=Format.pp_print_stringfmt(matchkindwith|Single->"Single"|Double->"Double"|Long_Double->"Long Double"|Real->"Real")moduleF=struct(** no NaN should be produced by function of this module
An exception, that should not be caught is returned instead. *)typet=float(* let packed_descr = Structural_descr.p_float *)(** NOTE: all floating-point comparisons using OCaml's standard operators
do NOT distinguish between -0.0 and 0.0.
Whenever floats are compared using them, it implies that negative zeroes
are also considered, e.g. "if x < 0.0" is equivalent to "if x < -0.0",
which is also equivalent to "F.compare x (-0.0) < 0".
This 'compare' operator distinguishes -0. and 0. *)(* replace "noalloc" with [@@noalloc] for OCaml version >= 4.03.0 *)[@@@warning"-3"]externalcompare:float->float->int="fc_ival_float_compare_total""noalloc"[@@@warning"+3"]letequalf1f2=comparef1f2=0(* The Caml version of compare below is fine but the C version above is
faster and does not allocate—it would be possible for the Caml version
to avoid allocation, but OCaml 4.00.1 allocates 80 bytes, for instance *)(* let compare f1 f2 =
let i1 = Int64.bits_of_float f1 in
let i2 = Int64.bits_of_float f2 in
let m1 = (Int64.logand i1 Int64.min_int) in
let m2 = (Int64.logand i2 Int64.min_int) in
if m1 = m2
then compare f1 f2
else compare m1 m2 *)letpretty_normal=Floating_point.pretty_normalletpretty=Floating_point.prettyletplus_zero=0.0letis_finitef=matchclassify_floatfwith|FP_nan|FP_infinite->false|FP_normal|FP_subnormal|FP_zero->true(* Must *not* be exported. All functions of this module should check the
arguments with which they call the functions labelled "may raise Nan
exception" *)exceptionInvalid_NaN(* May raise NaN exception *)letensure_not_nanr=matchclassify_floatrwith|FP_nan->raiseInvalid_NaN|FP_normal|FP_subnormal|FP_infinite|FP_zero->rletensure_not_nan_unaryfx=ensure_not_nan(fx)letid=funx->xletof_float=ensure_not_nan_unaryidletto_float=idletnext_previous_normalint64fupint64fdownfloat=letr=Int64.bits_of_floatfloatinletf=ifr>=0Lthenint64fupelseint64fdowninInt64.float_of_bits(fr)letnext_previousint64fupint64fdownfloat=matchclassify_floatfloatwith|FP_nan->raiseInvalid_NaN|FP_infinite->float|FP_normal|FP_subnormal->beginletf=next_previous_normalint64fupint64fdownfloatinmatchclassify_floatfwith|FP_nan->assertfalse(* can only be produced from an infinity *)|FP_infinite|FP_normal|FP_subnormal|FP_zero->fend|FP_zero->(next_previous_normalint64fupint64fdown(float+.min_float))-.min_floatletnext_floatfkindf'=letf=next_previousInt64.succInt64.predf'inmatchfkindwith|Real|Long_Double->f'|Double->f|Single->Floating_point.set_round_upward();letf=Floating_point.round_to_single_precision_floatfinFloating_point.set_round_nearest_even();fletprev_floatfkindf'=letf=next_previousInt64.predInt64.succf'inmatchfkindwith|Real|Long_Double->f'|Double->f|Single->Floating_point.set_round_downward();letf=Floating_point.round_to_single_precision_floatfinFloating_point.set_round_nearest_even();fendincludeFloat_interval.Make(Fc_float)lettop=topRealletinject_singletonf=inject~nan:falseffletminus_zero=inject_singleton(-0.)letplus_zero=inject_singleton0.letzeros=inject~nan:false(-0.)0.(* If [fkind] is [Float32], we check that [b] and [e] are valid
32-bit representations: lower bits are 0, and the value fits inside
a 32-bit float. *)letcheck_representabilityprecbe=ifprec=Single&&(Floating_point.round_to_single_precision_floatb<>b||Floating_point.round_to_single_precision_floate<>e)thenletthis_onefmtx=ifFloating_point.round_to_single_precision_floatx<>xthenFormat.pp_print_stringfmt"->"inCodex_log.fatal"Ival: invalid float32, %ab=%g (%a) %ae=%g (%a)"this_onebb(Floating_point.pretty_normal~use_hex:true)bthis_oneee(Floating_point.pretty_normal~use_hex:true)eletinject?(nan=false)precbe=check_representabilityprecbe;inject~nanbeletround_to_single_precision_float=forward_cast~dst:Singleletmeet=narrowletpi=(* [pi] is the nearest double to \pi, and is smaller than \pi. *)letpi=3.14159265358979323846ininjectReal~nan:falsepi(F.next_floatDoublepi)lete=(* [e] is the nearest double to \e, and is smaller than \e. *)lete=2.7182818284590452354ininjectReal~nan:falsee(F.next_floatDoublee)letcontains_plus_zero=contains_pos_zeroexceptionNot_Singleton_Floatletfloor_=floorletceil_=ceillettrunc_=truncletfround_=froundletproject_floatt=matchmin_and_maxtwith|Some(b,e),falsewhenF.equalbe->b|_->raiseNot_Singleton_Floatletbackward_cast_float_to_double=backward_cast~src:Singleletbackward_cast_double_to_realt=tletsubdiv_float_interval=subdivide(*
Local Variables:
compile-command: "make -C ../../.. byte"
End:
*)