Module Float32.
Definition neg_nan (f : float32) : { x : float32 | is_nan _ _ x = true } :=
match f with
| B754_nan s p H => exist _ (B754_nan 24 128 (negb s) p H) (eq_refl true)
| _ => default_nan_32
end.
Definition abs_nan (f : float32) : { x : float32 | is_nan _ _ x = true } :=
match f with
| B754_nan s p H => exist _ (B754_nan 24 128 false p H) (eq_refl true)
| _ => default_nan_32
end.
Definition cons_pl (x: float32) (l: list (bool * positive)) :=
match x with B754_nan s p _ => (s, p) :: l | _ => l end.
Definition unop_nan (x: float32) : {x : float32 | is_nan _ _ x = true} :=
quiet_nan_32 (Archi.choose_nan_32 (cons_pl x [])).
Definition binop_nan (x y: float32) : {x : float32 | is_nan _ _ x = true} :=
quiet_nan_32 (Archi.choose_nan_32 (cons_pl x (cons_pl y []))).
Definition fma_nan_1 (x y z: float32) : {x : float32 | is_nan _ _ x = true} :=
let '(a, b, c) := Archi.fma_order x y z in
quiet_nan_32 (Archi.choose_nan_32 (cons_pl a (cons_pl b (cons_pl c [])))).
Definition fma_nan (x y z: float32) : {x : float32 | is_nan _ _ x = true} :=
match x, y with
| B754_infinity _, B754_zero _ | B754_zero _, B754_infinity _ =>
if Archi.fma_invalid_mul_is_nan
then quiet_nan_32 (Archi.choose_nan_32 (Archi.default_nan_32 :: cons_pl z []))
else fma_nan_1 x y z
| _, _ =>
fma_nan_1 x y z
end.
(** ** Operations over single-precision floats *)
Definition zero: float32 := B754_zero _ _ false. (**r the float [+0.0] *)
Definition eq_dec: forall (f1 f2: float32), {f1 = f2} + {f1 <> f2} := Beq_dec _ _.
(** Arithmetic operations *)
Definition neg: float32 -> float32 := Bopp _ _ neg_nan. (**r opposite (change sign) *)
Definition abs: float32 -> float32 := Babs _ _ abs_nan. (**r absolute value (set sign to [+]) *)
Definition sqrt: float32 -> float32 :=
Bsqrt 24 128 __ __ unop_nan mode_NE.  (**r square root *)
Definition add: float32 -> float32 -> float32 :=
Bplus 24 128 __ __ binop_nan mode_NE. (**r addition *)
Definition sub: float32 -> float32 -> float32 :=
Bminus 24 128 __ __ binop_nan mode_NE. (**r subtraction *)
Definition mul: float32 -> float32 -> float32 :=
Bmult 24 128 __ __ binop_nan mode_NE. (**r multiplication *)
Definition div: float32 -> float32 -> float32 :=
Bdiv 24 128 __ __ binop_nan mode_NE. (**r division *)
Definition fma: float32 -> float32 -> float32 -> float32 :=
Bfma 24 128 __ __ fma_nan mode_NE. (**r fused multiply-add [x * y + z] *)
Definition compare (f1 f2: float32) : option Datatypes.comparison := (**r general comparison *)
Bcompare 24 128 f1 f2.
Definition cmp (c:comparison) (f1 f2: float32) : bool := (**r comparison *)
cmp_of_comparison c (compare f1 f2).
Definition ordered (f1 f2: float32) : bool :=
ordered_of_comparison (compare f1 f2).
(** Conversions *)
Definition of_double : float -> float32 := Float.to_single.
Definition to_double : float32 -> float := Float.of_single.
Definition to_int (f:float32): option int := (**r conversion to signed 32-bit int *)
option_map Int.repr (ZofB_range _ _ f Int.min_signed Int.max_signed).
Definition to_intu (f:float32): option int := (**r conversion to unsigned 32-bit int *)
option_map Int.repr (ZofB_range _ _ f 0 Int.max_unsigned).
Definition to_long (f:float32): option int64 := (**r conversion to signed 64-bit int *)
option_map Int64.repr (ZofB_range _ _ f Int64.min_signed Int64.max_signed).
Definition to_longu (f:float32): option int64 := (**r conversion to unsigned 64-bit int *)
option_map Int64.repr (ZofB_range _ _ f 0 Int64.max_unsigned).
Definition of_int (n:int): float32 := (**r conversion from signed 32-bit int to single-precision float *)
BofZ 24 128 __ __ (Int.signed n).
Definition of_intu (n:int): float32 := (**r conversion from unsigned 32-bit int to single-precision float *)
BofZ 24 128 __ __ (Int.unsigned n).
Definition of_long (n:int64): float32 := (**r conversion from signed 64-bit int to single-precision float *)
BofZ 24 128 __ __ (Int64.signed n).
Definition of_longu (n:int64): float32 := (**r conversion from unsigned 64-bit int to single-precision float *)
BofZ 24 128 __ __ (Int64.unsigned n).
Definition from_parsed (base:positive) (intPart:positive) (expPart:Z) : float32 :=
Bparse 24 128 __ __ base intPart expPart.
(** Conversions between floats and their concrete in-memory representation as a sequence of 32 bits. *)
Definition to_bits (f: float32) : int := Int.repr (bits_of_b32 f).
Definition of_bits (b: int): float32 := b32_of_bits (Int.unsigned b).
(** ** Properties *)
(** Commutativity properties of addition and multiplication. *)
(** Multiplication by 2 is diagonal addition. *)
(** Divisions that can be turned into multiplication by an inverse. *)
Definition exact_inverse : float32 -> option float32 := Bexact_inverse 24 128 __ __.
(** Properties of comparisons. *)
(** Properties of conversions to/from in-memory representation. The conversions are bijective (one-to-one). *)
(** Conversions from 32-bit integers to single-precision floats can be decomposed into a conversion to a double-precision float, followed by a [Float32.of_double] conversion.  No double rounding occurs. *)
(** Conversion of single-precision floats to integers can be decomposed into a [Float32.to_double] extension, followed by a double-precision-to-int conversion. *)
(** Conversions from 64-bit integers to single-precision floats can be expressed as conversion to a double-precision float followed by a [Float32.of_double] conversion. To avoid double rounding when the integer is large (above [2^53]), a round to odd must be performed on the integer before conversion to double-precision float. *)

Lemma of_long_round_odd:
forall n conv_nan,
2^36 <= Z.abs n < 2^64 ->
BofZ 24 128 __ __ n = Bconv _ _ 24 128 __ __ conv_nan mode_NE (BofZ 53 1024 __ __ (Z.land (Z.lor n ((Z.land n 2047) + 2047)) (-2048))).