package base
Source file float0.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232open! 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_compare let ceil = Stdlib.ceil let floor = Stdlib.floor let mod_float = Stdlib.mod_float let modf = Stdlib.modf let float_of_string = Stdlib.float_of_string let float_of_string_opt = Stdlib.float_of_string_opt let nan = Stdlib.nan let infinity = Stdlib.infinity let neg_infinity = Stdlib.neg_infinity let max_finite_value = Stdlib.max_float let epsilon_float = Stdlib.epsilon_float let classify_float = Stdlib.classify_float let abs_float = Stdlib.abs_float let is_integer = Stdlib.Float.is_integer let ( ** ) = Stdlib.( ** ) let ( %. ) a b = (* Raise in case of a negative modulus, as does Int.( % ). *) if b < 0. then Printf.invalid_argf "%f %% %f in float0.ml: modulus should be positive" a b (); let m = Stdlib.mod_float a b in (* Produce a non-negative result in analogy with Int.( % ). *) if m < 0. then m +. b else m ;; (* 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 ( struct include Stdlib include Stdlib.Float end : sig external frexp : float -> float * int = "caml_frexp_float" external ldexp : (float[@unboxed]) -> (int[@untagged]) -> (float[@unboxed]) = "caml_ldexp_float" "caml_ldexp_float_unboxed" [@@noalloc] external log10 : float -> float = "caml_log10_float" "log10" [@@unboxed] [@@noalloc] external log2 : float -> float = "caml_log2_float" "caml_log2" [@@unboxed] [@@noalloc] external expm1 : float -> float = "caml_expm1_float" "caml_expm1" [@@unboxed] [@@noalloc] external log1p : float -> float = "caml_log1p_float" "caml_log1p" [@@unboxed] [@@noalloc] external copysign : float -> float -> float = "caml_copysign_float" "caml_copysign" [@@unboxed] [@@noalloc] external cos : float -> float = "caml_cos_float" "cos" [@@unboxed] [@@noalloc] external sin : float -> float = "caml_sin_float" "sin" [@@unboxed] [@@noalloc] external tan : float -> float = "caml_tan_float" "tan" [@@unboxed] [@@noalloc] external acos : float -> float = "caml_acos_float" "acos" [@@unboxed] [@@noalloc] external asin : float -> float = "caml_asin_float" "asin" [@@unboxed] [@@noalloc] external atan : float -> float = "caml_atan_float" "atan" [@@unboxed] [@@noalloc] external acosh : float -> float = "caml_acosh_float" "caml_acosh" [@@unboxed] [@@noalloc] external asinh : float -> float = "caml_asinh_float" "caml_asinh" [@@unboxed] [@@noalloc] external atanh : float -> float = "caml_atanh_float" "caml_atanh" [@@unboxed] [@@noalloc] external atan2 : float -> float -> float = "caml_atan2_float" "atan2" [@@unboxed] [@@noalloc] external hypot : float -> float -> float = "caml_hypot_float" "caml_hypot" [@@unboxed] [@@noalloc] external cosh : float -> float = "caml_cosh_float" "cosh" [@@unboxed] [@@noalloc] external sinh : float -> float = "caml_sinh_float" "sinh" [@@unboxed] [@@noalloc] external tanh : float -> float = "caml_tanh_float" "tanh" [@@unboxed] [@@noalloc] external sqrt : float -> float = "caml_sqrt_float" "sqrt" [@@unboxed] [@@noalloc] external exp : float -> float = "caml_exp_float" "exp" [@@unboxed] [@@noalloc] external log : float -> float = "caml_log_float" "log" [@@unboxed] [@@noalloc] end) (* We need this indirection because these are exposed as "val" instead of "external" *) let frexp = frexp let ldexp = ldexp let is_nan x = (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). *) let to_int64_preserve_order t = if is_nan t then None else if t = 0. then (* also includes -0. *) Some 0L else if t > 0. then Some (Stdlib.Int64.bits_of_float t) else Some (Stdlib.Int64.neg (Stdlib.Int64.bits_of_float (-.t))) ;; let to_int64_preserve_order_exn x = Option.value_exn (to_int64_preserve_order x) let of_int64_preserve_order x = if Int64_replace_polymorphic_compare.( >= ) x 0L then Stdlib.Int64.float_of_bits x else ~-.(Stdlib.Int64.float_of_bits (Stdlib.Int64.neg x)) ;; let one_ulp dir t = match to_int64_preserve_order t with | None -> Stdlib.nan | Some x -> of_int64_preserve_order (Stdlib.Int64.add x (match dir with | `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) ] *) let upper_bound_for_int num_bits = let exp = Stdlib.float_of_int (num_bits - 1) in one_ulp `Down (2. ** exp) ;; let is_x_minus_one_exact x = (* [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. *) let open Int64_replace_polymorphic_compare in not (Stdlib.Int64.bits_of_float x = Stdlib.Int64.bits_of_float (x -. 1.)) ;; let lower_bound_for_int num_bits = let exp = Stdlib.float_of_int (num_bits - 1) in let min_int_as_float = ~-.(2. ** exp) in let open Int_replace_polymorphic_compare in if num_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_exact min_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_exact min_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 *) module Intrinsics_with_weird_nan_behavior = struct let[@inline always] min a b = Ocaml_intrinsics_kernel.Float.min a b let[@inline always] max a b = Ocaml_intrinsics_kernel.Float.max a b end let clamp_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. *) let t_maybe_nan = Intrinsics_with_weird_nan_behavior.max min_which_is_not_nan to_clamp_maybe_nan in Intrinsics_with_weird_nan_behavior.min max_which_is_not_nan t_maybe_nan ;; let box = (* Prevent potential constant folding of [+. 0.] in the near ocamlopt future. *) let x = Sys0.opaque_identity 0. in fun f -> 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. *) include Float_replace_polymorphic_compare